Skip to content

Commit

Permalink
Merge 1db211a into 9edd461
Browse files Browse the repository at this point in the history
  • Loading branch information
fabridamicelli committed Apr 14, 2023
2 parents 9edd461 + 1db211a commit 8b02d90
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test docker image and container
name: Docker CI

on:
push:
Expand All @@ -7,7 +7,7 @@ on:
branches: [ "master" ]

jobs:
test-docker-image:
test-build-and-container:
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -16,7 +16,11 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Test Image Build
- name: Test build_image.sh script with custom tagging and gpu flag
working-directory: docker
run: ./test_build_image_tagging.sh ${{ matrix.python-version }}

- name: Build Image for container test
id: image_build
working-directory: docker
run: |
Expand All @@ -28,7 +32,7 @@ jobs:
working-directory: docker
run: ./test_container_health.sh ${{ steps.image_build.outputs.IMAGE_TAG }}

- name: Check Python Version in Container
- name: Check Python version in container
working-directory: docker
run: ./test_container_python_version.sh ${{ steps.image_build.outputs.IMAGE_TAG }} ${{ matrix.python-version }}

Expand Down
45 changes: 25 additions & 20 deletions docker/build_image.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/bin/bash

set -o errexit -o nounset -o pipefail

MACHINE=cpu
BRANCH_NAME="master"
DOCKER_TAG="pytorch/torchserve:latest-cpu"
BUILD_TYPE="production"
DOCKER_FILE="Dockerfile"
BASE_IMAGE="ubuntu:20.04"
CUSTOM_TAG=false
USE_CUSTOM_TAG=false
CUDA_VERSION=""
UBUNTU_VERSION="ubuntu:20.04"
USE_LOCAL_SERVE_FOLDER=false
BUILD_WITH_IPEX=false
PYTHON_VERSION=3.9
Expand Down Expand Up @@ -53,8 +53,8 @@ do
shift
;;
-t|--tag)
DOCKER_TAG="$2"
CUSTOM_TAG=true
CUSTOM_TAG="$2"
USE_CUSTOM_TAG=true
shift
shift
;;
Expand All @@ -80,28 +80,28 @@ do
# With default ubuntu version 20.04
-cv|--cudaversion)
CUDA_VERSION="$2"
if [ $CUDA_VERSION == "cu118" ];
if [ "${CUDA_VERSION}" == "cu118" ];
then
BASE_IMAGE="nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu20.04"
elif [ $CUDA_VERSION == "cu117" ];
elif [ "${CUDA_VERSION}" == "cu117" ];
then
BASE_IMAGE="nvidia/cuda:11.7.0-cudnn8-runtime-ubuntu20.04"
elif [ $CUDA_VERSION == "cu116" ];
elif [ "${CUDA_VERSION}" == "cu116" ];
then
BASE_IMAGE="nvidia/cuda:11.6.0-cudnn8-runtime-ubuntu20.04"
elif [ $CUDA_VERSION == "cu113" ];
elif [ "${CUDA_VERSION}" == "cu113" ];
then
BASE_IMAGE="nvidia/cuda:11.3.0-cudnn8-runtime-ubuntu20.04"
elif [ $CUDA_VERSION == "cu111" ];
elif [ "${CUDA_VERSION}" == "cu111" ];
then
BASE_IMAGE="nvidia/cuda:11.1.1-cudnn8-runtime-ubuntu20.04"
elif [ $CUDA_VERSION == "cu102" ];
elif [ "${CUDA_VERSION}" == "cu102" ];
then
BASE_IMAGE="nvidia/cuda:10.2-cudnn8-runtime-ubuntu18.04"
elif [ $CUDA_VERSION == "cu101" ]
elif [ "${CUDA_VERSION}" == "cu101" ]
then
BASE_IMAGE="nvidia/cuda:10.1-cudnn7-runtime-ubuntu18.04"
elif [ $CUDA_VERSION == "cu92" ];
elif [ "${CUDA_VERSION}" == "cu92" ];
then
BASE_IMAGE="nvidia/cuda:9.2-cudnn7-runtime-ubuntu18.04"
else
Expand All @@ -120,22 +120,27 @@ then
exit 1
fi

if [ "${BUILD_TYPE}" == "dev" ] && ! $CUSTOM_TAG ;
if [ "${BUILD_TYPE}" == "dev" ] && ! $USE_CUSTOM_TAG ;
then
DOCKER_TAG="pytorch/torchserve:dev-$MACHINE"
fi

if [ "${BUILD_TYPE}" == "codebuild" ] && ! $CUSTOM_TAG ;
if [ "${BUILD_TYPE}" == "codebuild" ] && ! $USE_CUSTOM_TAG ;
then
DOCKER_TAG="pytorch/torchserve:codebuild-$MACHINE"
fi

if [ $BUILD_TYPE == "production" ]
if [ "$USE_CUSTOM_TAG" = true ]
then
DOCKER_TAG=${CUSTOM_TAG}
fi

if [ "${BUILD_TYPE}" == "production" ]
then
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE=$BASE_IMAGE --build-arg CUDA_VERSION=$CUDA_VERSION --build-arg PYTHON_VERSION=$PYTHON_VERSION -t $DOCKER_TAG .
elif [ $BUILD_TYPE == "benchmark" ]
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" -t "${DOCKER_TAG}" .
elif [ "${BUILD_TYPE}" == "benchmark" ]
then
DOCKER_BUILDKIT=1 docker build --pull --no-cache --file Dockerfile.benchmark --build-arg USE_LOCAL_SERVE_FOLDER=$USE_LOCAL_SERVE_FOLDER --build-arg BASE_IMAGE=$BASE_IMAGE --build-arg BRANCH_NAME=$BRANCH_NAME --build-arg CUDA_VERSION=$CUDA_VERSION --build-arg MACHINE_TYPE=$MACHINE --build-arg PYTHON_VERSION=$PYTHON_VERSION -t $DOCKER_TAG .
DOCKER_BUILDKIT=1 docker build --pull --no-cache --file Dockerfile.benchmark --build-arg USE_LOCAL_SERVE_FOLDER=$USE_LOCAL_SERVE_FOLDER --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg BRANCH_NAME="${BRANCH_NAME}" --build-arg CUDA_VERSION="${CUDA_VERSION}" --build-arg MACHINE_TYPE="${MACHINE}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" -t "${DOCKER_TAG}" .
else
DOCKER_BUILDKIT=1 docker build --pull --no-cache --file Dockerfile.dev -t $DOCKER_TAG --build-arg BUILD_TYPE=$BUILD_TYPE --build-arg BASE_IMAGE=$BASE_IMAGE --build-arg BRANCH_NAME=$BRANCH_NAME --build-arg CUDA_VERSION=$CUDA_VERSION --build-arg MACHINE_TYPE=$MACHINE --build-arg BUILD_WITH_IPEX=$BUILD_WITH_IPEX --build-arg PYTHON_VERSION=$PYTHON_VERSION .
DOCKER_BUILDKIT=1 docker build --pull --no-cache --file Dockerfile.dev -t "${DOCKER_TAG}" --build-arg BUILD_TYPE="${BUILD_TYPE}" --build-arg BASE_IMAGE=$BASE_IMAGE --build-arg BRANCH_NAME="${BRANCH_NAME}" --build-arg CUDA_VERSION="${CUDA_VERSION}" --build-arg MACHINE_TYPE="${MACHINE}" --build-arg BUILD_WITH_IPEX="${BUILD_WITH_IPEX}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" .
fi
105 changes: 105 additions & 0 deletions docker/test_build_image_tagging.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash

set -o errexit -o nounset -o pipefail

# This test checks the parsing and handling of arguments in `build_image.sh`,
# making sure that `build_image.sh` is invariant to the order of the passed
# arguments `-py` (python version), `-t` (image tag) and `-g` (use gpu flag)
# and that tagging works properly.
# That means, we have 3 args, so there are 6 possibilities to order them and
# we expect these script runs to produce the *very same output*:
#
# $ ./build_image.sh -py "${VERSION}" -t "${TAG}" -g
# $ ./build_image.sh -py "${VERSION}" -g -t "${TAG}"
# $ ./build_image.sh -t "${TAG}" -py "${VERSION}" -g
# $ ./build_image.sh -t "${TAG}" -g -py "${VERSION}"
# $ ./build_image.sh -g -py "${VERSION}" -t "${TAG}"
# $ ./build_image.sh -g -t "${TAG}" -py "${VERSION}"
#
# In order to assert the equivalence of all these variations, we take advantage
# of how docker builds images: If two images are exactly the same (ie, they are
# composed of the very same layers) they will have the same digest (ie, a hash
# value representing the content of the image), regardless of the tag assigned
# to the image. So, for example, if we run (with the same Dockerfile):
#
# $ docker build -f Dockerfile -t Org/Repo:TagOne .
# $ docker build -f Dockerfile -t Org/Repo:TagTwo .
# $ docker images --no-trunc
#
# we will see something like this:
#
# REPOSITORY TAG IMAGE ID CREATED SIZE
# Org/Repo TagOne sha256:e3824d794c0ccf10d2f61291f34e0d7e1e02e30b3d459465bc57d04dd3b65884 30 seconds ago 2.14GB
# Org/Repo TagTwo sha256:e3824d794c0ccf10d2f61291f34e0d7e1e02e30b3d459465bc57d04dd3b65884 30 seconds ago 2.14GB
#
# Notice that IMAGEID and CREATED are the same, since the first time it is
# actually created while the second time it just uses the cached layers.
# So the tag is "just a label" attached to the underlying image.
#
# Putting all together for our test:
# We run `build_image.sh` (on the same machine to allow docker cache) with each
# args order variation, tagging each variation with a different name (ensured
# by the random part of the string).
# We expect:
# - All the tags to exist (tagging works): len(images_to_test) == len(tags_to_test)
# - All tagged images to be actually one and the same under the hood: len(set(digests)) == 1


PY_VERSION=$1
TAG_1="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"
TAG_2="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"
TAG_3="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"
TAG_4="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"
TAG_5="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"
TAG_6="org/repo:image-${PY_VERSION}-${RANDOM}-${RANDOM}-${RANDOM}-${RANDOM}"

# Do builds alternating the flags order (-g, -t, -py)
# (which should build only one underlying image)
./build_image.sh -py "${PY_VERSION}" -t "${TAG_1}" -g
./build_image.sh -py "${PY_VERSION}" -g -t "${TAG_2}"

./build_image.sh -g -py "${PY_VERSION}" -t "${TAG_3}"
./build_image.sh -g -t "${TAG_4}" -py "${PY_VERSION}"

./build_image.sh -t "${TAG_5}" -py "${PY_VERSION}" -g
./build_image.sh -t "${TAG_6}" -g -py "${PY_VERSION}"

# Collect all the images with their tags and ids
IMGS_FILE="test_images.json"
docker images --no-trunc --format "{{json .}}" | jq '{"repo": .Repository, "tag": .Tag, "digest": .ID}' | jq -s > "${IMGS_FILE}"

python <<EOF
import json
tags_to_test = [
"${TAG_1}",
"${TAG_2}",
"${TAG_3}",
"${TAG_4}",
"${TAG_5}",
"${TAG_6}",
]
with open("${IMGS_FILE}") as file:
images_to_test = [
img
for img in json.load(file)
if f'{img["repo"]}:{img["tag"]}' in tags_to_test
]
if len(images_to_test) == 0:
raise ValueError("No images to test were detected")
if len(images_to_test) != len(tags_to_test):
raise ValueError(f"number of images_to_test {len(images_to_test)} does not match number of tags_to_test {len(tags_to_test)}")
digests = set(img["digest"] for img in images_to_test)
if len(digests) != 1:
raise ValueError(f"There should be only 1 digest, found these: {digests}")
print(f"Test successfull! All flags orders lead to the same image build with digest {digests} \n")
EOF

rm -f "${IMGS_FILE}"
docker system prune -f

0 comments on commit 8b02d90

Please sign in to comment.