Created
April 19, 2023 20:48
-
-
Save robd003/ff587c755cd360093ba7f70e3af83d98 to your computer and use it in GitHub Desktop.
Emissary-Ingress Dockerfile for 3.6.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
######################################## | |
# The Emissary build stage | |
######################################## | |
FROM golang:1.20.3-bullseye as emissary-factory | |
# See comment in `envoy-factory` for explanation | |
# of this symlink's purpose | |
RUN bash -c 'rm /bin/sh && ln /bin/bash /bin/sh' | |
# TODO(the-wondersmith): Make the build process below dependant upon the non-existence | |
# of pre-compiled, architecture-specific binaries mounted into the | |
# build container with -v "{artifacts/emissary-os-arch}:{/tmp/artifacts/}" | |
# Build the Emissary Golang binaries | |
RUN apt-get update \ | |
&& apt-get install -y patch \ | |
&& mkdir -p /tmp/artifacts \ | |
&& git clone --recursive https://github.com/emissary-ingress/emissary.git /tmp/emissary \ | |
&& cd /tmp/emissary \ | |
&& git checkout release/v3.6 \ | |
&& git pull --no-ff \ | |
&& echo "Building golang binaries for Emissary ..." \ | |
&& go mod vendor \ | |
&& go build -v -mod=vendor -o /tmp/artifacts ./cmd/... \ | |
&& echo "Done!" \ | |
&& cd /go \ | |
# Add the 'housekeeping' script \ | |
&& curl https://gist.githubusercontent.com/robd003/6688db597eeb0c74c6931ae7367e330a/raw/fdc8b242580fa28ffd1ea65aaf423c521179e0d5/housekeeping.py > /tmp/housekeeping.py | |
######################################## | |
# The Debian/Python build stage | |
######################################## | |
FROM debian:stable-slim as artifactory | |
# See comment in `envoy-factory` for explanation | |
# of this symlink's purpose | |
RUN bash -c 'rm /bin/sh && ln /bin/bash /bin/sh' | |
# Start by setting a known-good "save point" to return to when we're done | |
RUN export HERE="$(pwd)" \ | |
# Make the directories we'll be using as transient storage \ | |
&& mkdir -p /tmp/{deb-pkgs,holding-cell,artifacts,pyyaml} \ | |
&& mkdir -p /tmp/artifacts/tmp \ | |
# Install the system-level packages we need in order to compile \ | |
# the LibYAML C-library and to pull down the packages we *actually* \ | |
# need in the final distroless image \ | |
&& apt-get update \ | |
&& apt-get install -yq apt-rdepends python3.9 python3.9-full python3.9-dev python3-pip gcc make musl-dev curl cython3 libcap-dev libffi-dev libssl-dev libyaml-dev patchelf \ | |
# Install the latest version of setuptools to ensure compatibility with \ | |
# the Cython directives when compiling PyYAML \ | |
# the Cython directives when compiling PyYAML \ | |
&& python3 -m pip install -U setuptools \ | |
&& cd /tmp/pyyaml \ | |
# Pull down the latest PyYAML source tarball ... \ | |
&& curl -o pyyaml-6.0.tar.gz -L "https://github.com/yaml/pyyaml/archive/refs/tags/6.0.tar.gz" &> /dev/null \ | |
&& tar xzf pyyaml-6.0.tar.gz \ | |
&& cd pyyaml-6.0 \ | |
# ... and compile it into a valid wheel for whatever architecture \ | |
# we're currently running on, ensuring that we also compile the native \ | |
# C-library extension too \ | |
&& CFLAGS="-w" CPPFLAGS="-w" CXXFLAGS="-w" PYTHONWARNINGS='ignore' python3 setup.py --with-libyaml bdist_wheel --universal \ | |
&& mv ./dist/PyYAML-*.whl /tmp/artifacts/tmp/ \ | |
# Distroless images don't have a shell executable, so any RUN \ | |
# commands we'll need to run will have to be accomplished via Python. \ | |
# Seeing as we're building multi-arch images, it won't be easy to tell what \ | |
# the file name of the compiled PyYAML wheel will actually be, so we'll create \ | |
# a little "installer" script to handle that for us once we're "inside" the final \ | |
# distroless image | |
&& echo '#!/usr/bin/python' > /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo 'import sys, subprocess' >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo 'from pathlib import Path' >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo '' >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo "yaml_wheel = Path('$(printf "/tmp/%s\n" "$(ls /tmp/artifacts/tmp/*.whl | xargs basename --)")')" >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo 'subprocess.check_call([sys.executable, "-m", "pip", "install", str(yaml_wheel)])' >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo "yaml_wheel.unlink()" >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& echo '' >> /tmp/artifacts/tmp/install_pyyaml.py \ | |
&& cd /tmp/deb-pkgs \ | |
# Keep it clean folks \ | |
&& rm -rf /tmp/pyyaml \ | |
# Apt will complain if the permissions on the current directory \ | |
# aren't "correct", so we'll set them to ultra-permissive. Fair \ | |
# warning, apt will *most likely* complain anyway. It's totally \ | |
# safe to ignore it \ | |
&& chmod -R 777 /tmp \ | |
# Instruct apt-cache to recursively trace out the dependencies for \ | |
# each of the system-level packages we'll need to "install" in the \ | |
# final distroless image, passing the list of resolved packages to \ | |
# be downloaded by `apt-get`. This is sort of a hacky way to accomplish \ | |
# what we need, but doing it this way avoids breaking one of the \ | |
# fundamental security guarantees of distroless images \ | |
&& for PKG in "$(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances bash coreutils curl libcap htop libc-bin libc-dev-bin libc6 libc6-dev libcap-dev libcrypt1 libgcc-s1 gcc-10-base libcyaml1 libyaml-0-2 | grep '^\w' | sort -u)"; do apt-get download $PKG; done \ | |
# ... and unpack all of the packages we just downloaded into the temporary \ | |
# artifacts directory. The resulting directory will essentially be "overlaid" \ | |
# onto the distroless image, thereby perfectly mimicking the behavior of `apt-get install` \ | |
&& for PKG in $(ls /tmp/deb-pkgs/*.deb); do dpkg-deb -xv "${PKG}" "/tmp/artifacts"; done \ | |
# Ain't nobody got time to not keep it clean \ | |
&& rm -rf /tmp/{deb-pkgs,holding-cell} \ | |
# Navigate into the directory we just populated with package contents \ | |
# so that when we archive it the structure of the resulting tarball \ | |
# properly mirrors that of a running system (i.e. directory root == /) \ | |
&& cd /tmp/artifacts \ | |
# Use Python's `tarfile` module to pack up the extracted packages \ | |
# as the distroless image doesn't have a tar binary of its own \ | |
&& python3 -c "import tarfile; artifacts = tarfile.open('/tmp/artifacts.tar.gz', mode='w:gz'); artifacts.add('./', recursive=True); artifacts.close()" \ | |
# Return to our known-good "save point" ... \ | |
&& cd "${HERE}" \ | |
# And of course, we run a tight ship and keep it clean \ | |
&& unset HERE | |
######################################## | |
# The final distroless image build stage | |
######################################## | |
FROM gcr.io/distroless/python3 as distroless-factory | |
# Pull over the archive of "installed" packages from the | |
# intermediate `package-factory` image | |
COPY --from=artifactory /tmp/artifacts.tar.gz /tmp/ | |
# Copy over emissary's Python and Golang artifacts | |
COPY --from=emissary-factory /tmp/artifacts /opt/ambassador/bin | |
COPY --from=emissary-factory /tmp/emissary/python /opt/ambassador/python | |
COPY --from=emissary-factory /tmp/housekeeping.py /ambassador/housekeeping.py | |
COPY --from=emissary-factory /tmp/emissary/demo/services /ambassador/demo-services | |
COPY --from=emissary-factory /tmp/emissary/demo/config /ambassador/ambassador-demo-config | |
# Copy over `envoy`'s artifacts | |
COPY --from=local_build/envoy:1.25.4 /artifacts/envoy-static-stripped /opt/ambassador/bin/envoy-static-stripped | |
COPY --from=local_build/envoy:1.25.4 /artifacts/envoy-static-stripped /usr/bin/envoy | |
#COPY --from=docker.io/envoyproxy/envoy:v1.24.6 /usr/local/bin/envoy /opt/ambassador/bin/envoy-static-stripped | |
#COPY --from=docker.io/envoyproxy/envoy:v1.24.6 /usr/local/bin/envoy /usr/bin/ | |
# Run the 'housekeeping' script | |
RUN python /ambassador/housekeeping.py | |
# Force the HOME environment variable to a directory that'll always be writeable. | |
# We use /tmp/ambassador for this, and make sure it exists in our entrypoint, | |
# because trying to create it here in the Dockerfile doesn't always work very | |
# well in the face of situations like KAT volume-mounting /tmp/ambassador or | |
# the like. | |
ENV HOME=/tmp/ambassador | |
ENTRYPOINT ["/bin/bash", "/opt/ambassador/python/entrypoint.sh"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment