From 34498b5afabc33d0c848d0e0edc81adb1533a594 Mon Sep 17 00:00:00 2001 From: sid palas Date: Mon, 30 Jan 2023 11:46:53 -0500 Subject: [PATCH] Add readme for build module. Improve Dockerfile.Sample with more feature examples --- .../Dockerfile.sample | 13 +++++- 06-building-container-images/Makefile | 7 ++- 06-building-container-images/README.md | 45 +++++++++++++++++++ .../api-golang/Dockerfile.4 | 2 +- .../client-react/Dockerfile.5 | 29 ++++++++++++ .../client-react/Makefile | 2 +- 06-building-container-images/local-secret.txt | 1 + 7 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 06-building-container-images/README.md create mode 100644 06-building-container-images/client-react/Dockerfile.5 create mode 100644 06-building-container-images/local-secret.txt diff --git a/06-building-container-images/Dockerfile.sample b/06-building-container-images/Dockerfile.sample index 086ddb9..2794458 100644 --- a/06-building-container-images/Dockerfile.sample +++ b/06-building-container-images/Dockerfile.sample @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1 +# syntax=docker/dockerfile:1.5 # escape=\ # ^ OPTIONAL "directives" (must be at top if used) @@ -14,12 +14,21 @@ FROM node:${BASE_IMAGE_TAG} RUN echo "Hey Team πŸ‘‹ (shell form)" RUN ["echo", "Hey Team πŸ‘‹ (exec form)"] +# Heredocs allow for specifying multiple commands to +# be run within a single step, across multiple lines +# without lots of && and \ +RUN < `Dockerfile.N`) starting with the most simple naive approach, and improving them with each step. + +Types of improvments: +1) **Pinning a specific base image:** By specifying an image tag, you can avoid nasty surprises where the base image +2) **Choosing a smaller base image:** There are often a variety of base images we can choose from. Choosing a smaller base image will usually reduce the size of your final image. +3) **Choosing a more secure base image:** Like image size, we should consider the number of vulnerabilities in our base images and the attack surface area. Chaingaurd publishes a number of hardened images (https://www.chainguard.dev/chainguard-images). +4) **Specifying a working directory:** Many languages have a convention for how/where applications should be installed. Adhering to that convention will make it easier for developers to work with the container. +5) **Consider layer cache to improve build times:** By undersanding the layered nature of container filesytems and choosing when to copy particular files we can make better use of the Docker caching system. +6) **Use COPY β€”link where appropriate:** The `--link` option was added to the `COPY` command in march 2022. It allows you to improve cache behavior in certain situations by copying files into an independent image layer not dependent on its predecessors. +7) **Use a non-root user within the container:** While containers can utilize a user namespace to differentiate between root inside the container and root on the host, this feature won't always be leveraged and by using a non-root user we improve the default safety of the container. +8) **Specify the environment correctly:** Only install production dependencies for a production image, and specify any necessary environment variables to configure the language runtime accordingly. +9) **Avoid assumptions:** Using commands like `EXPOSE ` make it clear to users how the image is intended to be used and avoids the need for them to make assumptions. +10) **Use multi-stage builds where sensible:** For some situations, multi-stage builds can vastly reduce the size of the final image and improve build times. Learn about and use multi-stage builds where appropriate. + +All of these techniques are leveraged across the example applications in this repo. + +## Additional Features + +There are some additional features of Dockerfiles that are not shown in the example applications but are worth knowing about. These are highlighted in `Dockerfile.sample` and the corresponding build / run commands in the `Makefile` + +1) **Parser directives:** +2) **ARG:** +3) **Parser directives:** +4) **Mounting secrets:** +5) **ENTRYPOINT + CMD:** + +## Beyond the scope of this course: + +1) **buildx (multi-architecture images):** You can use a feature called `buildx` to create images for multiple architectures from a single Dockerfile. This video goes into depth on that topic: https://www.youtube.com/watch?v=hWSHtHasJUI \ No newline at end of file diff --git a/06-building-container-images/api-golang/Dockerfile.4 b/06-building-container-images/api-golang/Dockerfile.4 index cfea973..de80ebb 100644 --- a/06-building-container-images/api-golang/Dockerfile.4 +++ b/06-building-container-images/api-golang/Dockerfile.4 @@ -13,7 +13,7 @@ RUN go mod download COPY . . # Compile application during build rather than at runtime -# Add -w and -s flags to +# Add flags to statically link binary RUN go build \ -ldflags="-linkmode external -extldflags -static" \ -o api-golang diff --git a/06-building-container-images/client-react/Dockerfile.5 b/06-building-container-images/client-react/Dockerfile.5 new file mode 100644 index 0000000..2c94674 --- /dev/null +++ b/06-building-container-images/client-react/Dockerfile.5 @@ -0,0 +1,29 @@ +FROM node:19.4-bullseye AS build + +# Specify working directory other than / +WORKDIR /usr/src/app + +# Copy only files required to install +# dependencies (better layer caching) +COPY package*.json ./ + +# Use cache mount to speed up install of existing dependencies +RUN --mount=type=cache,target=/usr/src/app/.npm \ + npm set cache /usr/src/app/.npm && \ + npm install + +COPY . . + +RUN npm run build + +# Use separate stage for deployable image +FROM nginx:1.23-alpine + +# Use COPY --link to avoid breaking cache if we change the second stage base image +COPY --link nginx.conf /etc/nginx/conf.d/default.conf + +COPY --link --from=build usr/src/app/dist/ /usr/share/nginx/html + +EXPOSE 80 + +# No CMD specified... will uses CMD/ENTRYPOINT from base image (nginx:1.23-alpine) \ No newline at end of file diff --git a/06-building-container-images/client-react/Makefile b/06-building-container-images/client-react/Makefile index b399dee..eec16b6 100644 --- a/06-building-container-images/client-react/Makefile +++ b/06-building-container-images/client-react/Makefile @@ -7,6 +7,6 @@ build-N: .PHONY: build-all build-all: - for number in 0 1 2 3 ; do \ + for number in 0 1 2 3 4 5; do \ N=$$number $(MAKE) build-N; \ done \ No newline at end of file diff --git a/06-building-container-images/local-secret.txt b/06-building-container-images/local-secret.txt new file mode 100644 index 0000000..31e446d --- /dev/null +++ b/06-building-container-images/local-secret.txt @@ -0,0 +1 @@ +foobarbaz \ No newline at end of file