Add readme for build module. Improve Dockerfile.Sample with more feature examples
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1.5
|
||||||
# escape=\
|
# escape=\
|
||||||
# ^ OPTIONAL "directives" (must be at top if used)
|
# ^ 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 👋 (shell form)"
|
||||||
RUN ["echo", "Hey Team 👋 (exec 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 <<EOF
|
||||||
|
apt update
|
||||||
|
apt install iputils-ping -y
|
||||||
|
EOF
|
||||||
|
|
||||||
# --mount allows for mounting additional files
|
# --mount allows for mounting additional files
|
||||||
# into the build context
|
# into the build context
|
||||||
# RUN --mount=type=bind ...
|
# RUN --mount=type=bind ...
|
||||||
# RUN --mount=type=cache ...
|
# RUN --mount=type=cache ...
|
||||||
# RUN --mount=type=secret ...
|
|
||||||
# RUN --mount=type=ssh ...
|
# RUN --mount=type=ssh ...
|
||||||
|
RUN --mount=type=secret,id=secret.txt,dst=/container-secret.txt \
|
||||||
|
echo "Run the command that requires access to the secret here"
|
||||||
|
|
||||||
# Available only at build time
|
# Available only at build time
|
||||||
# (Still in image metadata though...)
|
# (Still in image metadata though...)
|
||||||
|
|||||||
@ -16,7 +16,12 @@ compose-down:
|
|||||||
|
|
||||||
.PHONY: build-sample
|
.PHONY: build-sample
|
||||||
build-sample:
|
build-sample:
|
||||||
docker build -t sample -f Dockerfile.sample .
|
DOCKER_BUILDKIT=1 docker build \
|
||||||
|
--build-arg BASE_IMAGE_TAG=19.3 \
|
||||||
|
--secret id=secret.txt,src=local-secret.txt \
|
||||||
|
-t sample \
|
||||||
|
-f Dockerfile.sample \
|
||||||
|
.
|
||||||
|
|
||||||
define ENTRYPOINT_CMD_DESCRIPTION
|
define ENTRYPOINT_CMD_DESCRIPTION
|
||||||
##############################
|
##############################
|
||||||
|
|||||||
45
06-building-container-images/README.md
Normal file
45
06-building-container-images/README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Building Container Images
|
||||||
|
|
||||||
|
## General Process
|
||||||
|
|
||||||
|
Dockerfiles generally have steps that are similar to those you would use to get your application running on a server.
|
||||||
|
|
||||||
|
1) Start with an Operating System
|
||||||
|
2) Install the language runtime
|
||||||
|
3) Install any application dependencies
|
||||||
|
4) Set up the execution environment
|
||||||
|
5) Run the application
|
||||||
|
|
||||||
|
***Note:** We can often jump right to #3 by choosing a base image that has the OS and language runtime preinstalled.*
|
||||||
|
|
||||||
|
## Writing good Dockerfiles:
|
||||||
|
|
||||||
|
For each of the components of the example application I have included a series of Dockerfiles (`Dockerfile.0` -> `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 <PORT>` 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
|
||||||
@ -13,7 +13,7 @@ RUN go mod download
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Compile application during build rather than at runtime
|
# Compile application during build rather than at runtime
|
||||||
# Add -w and -s flags to
|
# Add flags to statically link binary
|
||||||
RUN go build \
|
RUN go build \
|
||||||
-ldflags="-linkmode external -extldflags -static" \
|
-ldflags="-linkmode external -extldflags -static" \
|
||||||
-o api-golang
|
-o api-golang
|
||||||
|
|||||||
29
06-building-container-images/client-react/Dockerfile.5
Normal file
29
06-building-container-images/client-react/Dockerfile.5
Normal file
@ -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)
|
||||||
@ -7,6 +7,6 @@ build-N:
|
|||||||
|
|
||||||
.PHONY: build-all
|
.PHONY: build-all
|
||||||
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; \
|
N=$$number $(MAKE) build-N; \
|
||||||
done
|
done
|
||||||
1
06-building-container-images/local-secret.txt
Normal file
1
06-building-container-images/local-secret.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
foobarbaz
|
||||||
Reference in New Issue
Block a user