From 2a2e2fdb72b94fec1507a63644ec4546191dd0ef Mon Sep 17 00:00:00 2001 From: Sudeep Pillai Date: Tue, 24 Oct 2023 09:55:38 -0700 Subject: [PATCH] Added multi-stage exmaple yaml file and generated Dockerfile (#13) --- README.md | 2 +- agipack/builder.py | 4 +- agipack/templates/Dockerfile.j2 | 1 + agipack/version.py | 2 +- examples/agibuild.multistage.yaml | 16 +++ examples/generated/Dockerfile-multistage | 103 ++++++++++++++++++ .../generated/Dockerfile-multistage-example | 74 ------------- 7 files changed, 125 insertions(+), 77 deletions(-) create mode 100644 examples/agibuild.multistage.yaml create mode 100644 examples/generated/Dockerfile-multistage delete mode 100644 examples/generated/Dockerfile-multistage-example diff --git a/README.md b/README.md index 9862eb2..793edbe 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ $ agi-pack generate -c agibuild.yaml As you can see, `agi-pack` will generate a **single** Dockerfile for each of the targets defined in the YAML file. You can then build the individual images from the same Dockerfile using docker targets: `docker build -f Dockerfile --target .` where `` is the name of the image target you want to build. -Here's the corresponding [`Dockerfile`](./examples/generated/Dockerfile-multistage-example) that was generated. +Here's the corresponding [`Dockerfile`](./examples/generated/Dockerfile-multistage) that was generated. ## Why the name? 🤷‍♂️ diff --git a/agipack/builder.py b/agipack/builder.py index 2ac56ce..ac0c2ba 100644 --- a/agipack/builder.py +++ b/agipack/builder.py @@ -198,7 +198,9 @@ def build(self, filename: str, target: str, tags: List[str] = None, push: bool = process.wait() if process.returncode != 0: - raise Exception(f"Failed to build image [target={target}]") + err_msg = f"Failed to build image [target={target}, e={process.stderr}]" + logger.error(err_msg) + raise Exception(err_msg) # Push the Docker image if push: diff --git a/agipack/templates/Dockerfile.j2 b/agipack/templates/Dockerfile.j2 index 534dcb2..322876b 100644 --- a/agipack/templates/Dockerfile.j2 +++ b/agipack/templates/Dockerfile.j2 @@ -3,6 +3,7 @@ # Auto-generated by agi-pack (version={{ agipack_version }}). {%- else %} # >>>>>>>>>>>>>>>>>>>>>>>>>>> +# Auto-generated by agi-pack (version={{ agipack_version }}). {%- endif %} FROM {{ base }} AS {{ target }} diff --git a/agipack/version.py b/agipack/version.py index 08f934f..d38c350 100644 --- a/agipack/version.py +++ b/agipack/version.py @@ -1 +1 @@ -__version__ = "0.1.18" +__version__ = "0.1.19" diff --git a/examples/agibuild.multistage.yaml b/examples/agibuild.multistage.yaml new file mode 100644 index 0000000..7ccfdce --- /dev/null +++ b/examples/agibuild.multistage.yaml @@ -0,0 +1,16 @@ +images: + base-cpu: + name: agi + base: debian:buster-slim + system: + - wget + python: "3.8.10" + pip: + - scikit-learn + run: + - echo "Hello, world!" + + dev-cpu: + base: base-cpu + system: + - build-essential diff --git a/examples/generated/Dockerfile-multistage b/examples/generated/Dockerfile-multistage new file mode 100644 index 0000000..911c5cb --- /dev/null +++ b/examples/generated/Dockerfile-multistage @@ -0,0 +1,103 @@ +# >>>>>>>>>>>>>>>>>>>>>>>>>>> +# Auto-generated by agi-pack (version=0.1.18). +FROM debian:buster-slim AS base-cpu + +# Setup environment variables +ENV AGIPACK_PROJECT agi +ENV AGIPACK_PYENV agi-py38 +ENV AGIPACK_PATH /opt/agi-pack + +ENV DEBIAN_FRONTEND="noninteractive" +ENV PYTHON_VERSION 3.8.10 +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 +ENV PYTHONWARNINGS ignore +ENV PIP_CACHE_DIR /var/cache/pip +ENV CONDA_PKGS_DIRS /var/cache/conda/pkgs + +# Setup conda paths +ENV CONDA_PATH=${AGIPACK_PATH}/conda/envs/${AGIPACK_PYENV} +ENV CONDA_PREFIX=${CONDA_PATH} +ENV CONDA_EXE=${CONDA_PATH}/bin/conda +ENV PATH=${CONDA_PATH}/bin:${AGIPACK_PATH}/conda/bin:$PATH +ENV CONDA_DEFAULT_ENV ${AGIPACK_PYENV} + +# Install base system packages +RUN apt-get -y update \ + && apt-get -y --no-install-recommends install \ + curl bzip2 git ca-certificates + +# Install additional system packages +RUN --mount=type=cache,target=/var/cache/apt \ + apt-get -y update \ + && apt-get -y --no-install-recommends install \ + wget \ + && echo "system install complete" + +# Install mambaforge, with cache mounting ${CONDA_PKGS_DIRS} for faster builds +RUN --mount=type=cache,target=${CONDA_PKGS_DIRS} \ + curl -sLo ~/mambaforge.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-$(uname)-$(uname -m).sh" \ + && chmod +x ~/mambaforge.sh \ + && ~/mambaforge.sh -b -p ${AGIPACK_PATH}/conda \ + && ${AGIPACK_PATH}/conda/bin/mamba init bash \ + && ${AGIPACK_PATH}/conda/bin/mamba config --add channels conda-forge \ + && ${AGIPACK_PATH}/conda/bin/mamba create -n ${AGIPACK_PYENV} python=${PYTHON_VERSION} -y \ + && rm ~/mambaforge.sh + +# Upgrade pip +RUN pip install --upgrade pip + +# Install pip packages, with cache mounting ${PIP_CACHE_DIR} for faster builds +# Note: Cache mounts allow us to re-use the cache for pip packages +# instead of having to re-download them every time we build. +RUN --mount=type=cache,target=${PIP_CACHE_DIR} \ + pip install --cache-dir ${PIP_CACHE_DIR} \ + "scikit-learn" \ + && echo "pip install complete" + +# Export conda environment on login +RUN echo "export CONDA_PATH=${AGIPACK_PATH}/conda/envs/${AGIPACK_PYENV}" >> ~/.bashrc \ + && echo "export PATH=${AGIPACK_PATH}/conda/envs/${AGIPACK_PYENV}/bin:$PATH" >> ~/.bashrc \ + && echo "export CONDA_DEFAULT_ENV=${AGIPACK_PYENV}" >> ~/.bashrc \ + && echo "mamba activate ${AGIPACK_PYENV}" > ~/.bashrc + +# Setup working directory +WORKDIR /app/$AGIPACK_PYENV + +# Run commands +RUN echo "running commands" +RUN --mount=type=cache,target=${CONDA_PKGS_DIRS} \ + --mount=type=cache,target=${PIP_CACHE_DIR} \ + echo "Hello, world!" +RUN echo "run commands complete" +# Cleanup apt, mamba/conda and pip packages +RUN apt-get -y autoclean \ + && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists/* \ + && ${AGIPACK_PATH}/conda/bin/mamba clean -ya \ + && rm -rf ${PIP_CACHE_DIR} \ + && rm -rf ${CONDA_PKGS_DIRS} \ + && rm -rf /tmp/reqs \ + && echo "pip cleanup complete" +# >>>>>>>>>>>>>>>>>>>>>>>>>>> +# Auto-generated by agi-pack (version=0.1.18). +FROM base-cpu AS dev-cpu + +# Install additional system packages +RUN --mount=type=cache,target=/var/cache/apt \ + apt-get -y update \ + && apt-get -y --no-install-recommends install \ + build-essential \ + && echo "system install complete" + +# Setup working directory +WORKDIR /app/$AGIPACK_PYENV +# Cleanup apt, mamba/conda and pip packages +RUN apt-get -y autoclean \ + && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists/* \ + && ${AGIPACK_PATH}/conda/bin/mamba clean -ya \ + && rm -rf ${PIP_CACHE_DIR} \ + && rm -rf ${CONDA_PKGS_DIRS} \ + && rm -rf /tmp/reqs \ + && echo "pip cleanup complete" \ No newline at end of file diff --git a/examples/generated/Dockerfile-multistage-example b/examples/generated/Dockerfile-multistage-example deleted file mode 100644 index 1d0058f..0000000 --- a/examples/generated/Dockerfile-multistage-example +++ /dev/null @@ -1,74 +0,0 @@ -# >>>>>>>>>>>>>>>>>>>>>>>>>>> -# Auto-generated by agi-pack. -FROM debian:buster-slim AS base-cpu - -# Setup environment variables -ENV PROJECT agipack -ENV PYENV agipack-py38 -ENV PYTHON_VERSION 3.8.10 -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 -ENV PYTHONWARNINGS ignore - -# Setup conda paths -ENV CONDA_PATH=/opt/conda/envs/${PYENV} -ENV CONDA_PREFIX=${CONDA_PATH} -ENV CONDA_EXE=${CONDA_PATH}/bin/conda -ENV PATH=${CONDA_PATH}/bin:/opt/conda/bin:$PATH -ENV CONDA_DEFAULT_ENV ${PYENV} - -# Install system packages -RUN apt-get -y update \ - && apt-get -y install \ - curl git \ - wget \ - && apt-get -y autoclean \ - && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists/* - -# Install mambaforge -RUN curl -sLo ~/mambaforge.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-$(uname)-$(uname -m).sh" \ - && chmod +x ~/mambaforge.sh \ - && ~/mambaforge.sh -b -p /opt/conda \ - && /opt/conda/bin/mamba init bash \ - && /opt/conda/bin/mamba config --set pip_interop_enabled True \ - && /opt/conda/bin/mamba create -n ${PYENV} python=${PYTHON_VERSION} -y \ - && rm ~/mambaforge.sh - -# Install pip packages, with cache mounting /opt/conda/pkgs for faster builds -# Note: Cache mounts allow us to re-use the cache for conda packages -# instead of having to re-download them every time we build. -RUN --mount=type=cache,target=/opt/conda/pkgs/ \ - mamba install -yv \ - scikit-learn \ - && echo "pip install complete" - -# Export conda environment on login -RUN echo "export CONDA_PATH=/opt/conda/envs/${PYENV}" >> ~/.bashrc -RUN echo "export PATH=/opt/conda/envs/${PYENV}/bin:$PATH" >> ~/.bashrc -RUN echo "export CONDA_DEFAULT_ENV=${PYENV}" >> ~/.bashrc -RUN echo "mamba activate ${PYENV}" > ~/.bashrc -ENTRYPOINT ["/bin/bash", "-c"] - -# Setup working directory -WORKDIR /app/$PYENV - -# Run commands -RUN \ - echo "Hello, world!" \ - && echo "run commands complete" - -# >>>>>>>>>>>>>>>>>>>>>>>>>>> -FROM base-cpu AS dev-cpu - -# Install system packages -RUN apt-get -y update \ - && apt-get -y install \ - curl git \ - build-essential \ - && apt-get -y autoclean \ - && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists/* - -# Setup working directory -WORKDIR /app/$PYENV