From 6d5c4a834e405bfd6bae80fc37bc5fe123a2813c Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Thu, 18 Jan 2018 15:49:02 +0000 Subject: [PATCH] Dockerize the entier wrapping process --- docs/getting_started/minikube.md | 19 +---- examples/models/sklearn_iris/.dockerignore | 4 + examples/models/sklearn_iris/Dockerfile | 84 +++++++++++++++++++ examples/models/sklearn_iris/Makefile | 11 +++ examples/models/sklearn_iris/requirements.txt | 9 +- 5 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 examples/models/sklearn_iris/.dockerignore create mode 100644 examples/models/sklearn_iris/Dockerfile create mode 100644 examples/models/sklearn_iris/Makefile diff --git a/docs/getting_started/minikube.md b/docs/getting_started/minikube.md index ff18013aa5..d23506e5a6 100644 --- a/docs/getting_started/minikube.md +++ b/docs/getting_started/minikube.md @@ -64,24 +64,11 @@ In this session, we show how to wrap the sklearn iris classifier in the [seldon- cd seldon-core/examples/models/sklearn_iris/ ``` ```bash - python train_iris.py + make ```` - This will train a simple logistic regression model on the iris dataset and save the model in the same folder. - - -3. Wrap your saved model using the core-python-wrapper docker image: - ```bash - docker run -v $(pwd):/model seldonio/core-python-wrapper:0.4 /model IrisClassifier 0.1 seldonio --force - ``` - -4. Build the docker image locally - ```bash - cd build - ./build_image.sh - ``` - This will create the docker image ```seldonio/irisclassifier:0.1``` inside the minikube cluster which is ready for deployment with Seldon Core. - + This will build a docker image. During the build, the simple model will be trained (see `train_iris.py`). + Image name will be called `seldonio/irisclassifier:0.1`, and it will be ready for deployment with Seldon Core. ### Deploy your model diff --git a/examples/models/sklearn_iris/.dockerignore b/examples/models/sklearn_iris/.dockerignore new file mode 100644 index 0000000000..d44c64ac46 --- /dev/null +++ b/examples/models/sklearn_iris/.dockerignore @@ -0,0 +1,4 @@ +.dockerignore +Dockerfile +Makefile +sklearn_iris_deployment.json diff --git a/examples/models/sklearn_iris/Dockerfile b/examples/models/sklearn_iris/Dockerfile new file mode 100644 index 0000000000..893f9746c6 --- /dev/null +++ b/examples/models/sklearn_iris/Dockerfile @@ -0,0 +1,84 @@ +## Use alpine as build time and runtime image +FROM alpine:3.7 as build-alpine + +## Install build dependencies +RUN apk add --update \ + build-base \ + freetype-dev \ + gcc \ + gfortran \ + libc6-compat \ + libffi-dev \ + libpng-dev \ + openblas-dev \ + openssl-dev \ + py2-pip \ + python2 \ + python2-dev\ + wget \ + && true + +## Symlink missing header, so we can compile numpy +RUN ln -s /usr/include/locale.h /usr/include/xlocale.h + +## Copy package manager config to staging root tree +RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ +## Install runtime dependencies under staging root tree +RUN apk add --no-cache --initdb --root /out \ + alpine-baselayout \ + busybox \ + ca-certificates \ + freetype \ + libc6-compat \ + libffi \ + libpng \ + libstdc++ \ + musl \ + openblas \ + openssl \ + python2 \ + && true +## Remove package manager residuals +RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache + +## Enter model source tree and install all Python depenendcies +COPY . /src +WORKDIR /src +## TODO this does take a while to build, maybe a good idea to +## put all related build dependencies into a separate public image +RUN pip install --requirement requirements.txt +## Train the model +RUN python train_iris.py + +## Copy source code and Python dependencies to the saging root tree +RUN mkdir -p /out/src && cp -r /src/* /out/src/ +RUN mkdir -p /out/usr/lib/python2.7/ && cp -r /usr/lib/python2.7/* /out/usr/lib/python2.7/ + +## Use Seldon Core wrapper image to wrap the model source code +FROM seldonio/core-python-wrapper:0.4 as build-wrapper + +ARG MODEL_NAME +ARG IMAGE_VERSION +ARG IMAGE_REPO + +## Copy staging diretory here +COPY --from=build-alpine /out /out +## Wrap the Python model +WORKDIR /wrappers/python +RUN python wrap_model.py /out/src $MODEL_NAME $IMAGE_VERSION $IMAGE_REPO --force + +## Copy wrapped model source code into staging tree and cleanup what is not neccessary at runtime +RUN mkdir -p /out/microservice && cp -r /out/src/build/* /out/microservice/ && rm -rf /out/src +WORKDIR /out/microservice +RUN rm -f Dockerfile Makefile requirements*.txt build_image.sh push_image.sh +## TODO dockerfile doesn't support build argument interpolation in array notation for ENTRYPOINT & CMD +## to get rid of `/bin/sh` wrapper, it'd help to make $MODEL_NAME an environment variable and let the +## Python script pick it up +RUN printf '#!/bin/sh\nexec python microservice.py %s REST --service-type MODEL --persistence 0' $MODEL_NAME > microservice.sh && chmod +x microservice.sh + +## Copy staging root tree onto an empty image +FROM scratch +COPY --from=build-wrapper /out / +WORKDIR /microservice +EXPOSE 5000 +ENTRYPOINT ["/microservice/microservice.sh"] diff --git a/examples/models/sklearn_iris/Makefile b/examples/models/sklearn_iris/Makefile new file mode 100644 index 0000000000..c3d0f4236e --- /dev/null +++ b/examples/models/sklearn_iris/Makefile @@ -0,0 +1,11 @@ +IMAGE_REPO?=seldonio +IMAGE_NAME?=irisclassifier +IMAGE_VERSION?=0.1 +MODEL_NAME?=IrisClassifier + +container_image: + docker build \ + --build-arg IMAGE_REPO=$(IMAGE_REPO) \ + --build-arg IMAGE_VERSION=$(IMAGE_VERSION) \ + --build-arg MODEL_NAME=$(MODEL_NAME) \ + --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_VERSION) . diff --git a/examples/models/sklearn_iris/requirements.txt b/examples/models/sklearn_iris/requirements.txt index 4585b69d2c..f02ba9948a 100644 --- a/examples/models/sklearn_iris/requirements.txt +++ b/examples/models/sklearn_iris/requirements.txt @@ -1,2 +1,9 @@ -scikit-learn==0.19.0 +numpy==1.11.2 +pandas==0.18.1 +grpc==0.3.post19 +grpcio==1.8.4 +Flask==0.11.1 +futures +redis==2.10.5 scipy==0.18.1 +scikit-learn==0.19.0