Skip to content

Commit 0b2b076

Browse files
authored
Adding containers-102 workshop (#39)
Signed-off-by: Eric Smalling <eric.smalling@chainguard.dev>
1 parent 537eec0 commit 0b2b076

12 files changed

Lines changed: 210 additions & 0 deletions

File tree

containers-102/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Chainguard Workshop: Containers 102
2+
* Deep dive into container images
3+
* Hands on exercises to learn tactics needed for hardened, distroless-type images
4+
5+
## Hands-on Exercises
6+
All exercises assume you are cd'd into the `containers-102` directory (where this README is located).
7+
### Understanding image layers
8+
Steps:
9+
1. Get a big file, untar it, and remove the tarball
10+
1. `cd layers`
11+
1. `cat Dockerfile.1` and note the 3 RUN lines to download a big file, untar it, and remove the tarball
12+
1. `docker build . -t layers:1 -f Dockerfile.1`
13+
1. `docker images layers` Note at the image size is ~33.5MB
14+
1. `docker image history layers:1` You will see individual layers for each `RUN` line in the Dockerfile
15+
16+
1. Concatenate operations into a single RUN line
17+
1. `cat Dockerfile.2` and note change to a single `RUN` line to download a big file, untar it, and remove the tarball
18+
1. `docker build . -t layers:2 -f Dockerfile.2`
19+
1. `docker images layers` Compare the new image size which is about 1.5MB smaller due to the removal of the tarball in the same `RUN` line
20+
1. `docker image history layers:2` You will see a single layer for the single `RUN` line in the Dockerfile
21+
22+
### Multi-stage builds
23+
Steps:
24+
1. Using multistage to eliminate unwanted layers
25+
1. `cd multistage`
26+
1. `cat Dockerfile.1`<br>This is similar to the 1st step of the previous exercise, but with a multi-stage build.
27+
1. `docker build . -t mstage:1 -f Dockerfile.1`
28+
1. `docker images mstage`
29+
1. `docker images layers`<br>Comparing the image sizes, this one is about 1.2MB smaller that the previous exercise
30+
1. `docker image history mstage:1`<br>There is now a single layer for the COPY line
31+
32+
1. Copying a dependency to a final stage w/out a package manager
33+
1. `cat Dockerfile.2`<br>In this example, we want to get `jq` working in the final image but there's no `apk` tooling there because it's a non-dev Chainguard imag, so we are trying to just COPY it.
34+
1. `docker build . -t mstage:2 -f Dockerfile.2`
35+
1. `docker run --rm -it mstage:2`<br>We get an error because the required `libonig.so.5` library is missing
36+
37+
1. Find out what libraries are needed, target the builder image
38+
1. `docker build -t mstage:2b -f Dockerfile.2 --target=builder .`<br>This will build the `builder` stage only
39+
1. `docker run --rm -it --entrypoint sh -u root mstage:2b`
40+
1. `ldd /usr/bin/jq`<br>ldd is not installed so we need to find and add it
41+
1. `apk search --no-cache cmd:ldd`<br>This will search for packages that provide the `ldd` command
42+
1. `apk add --no-cache posix-libc-utils`<br>This will install the `ldd` command
43+
2. `ldd /usr/bin/jq`<br>Now we can see the dependencies of the `jq` command and see that `libonig.so.5` is needed
44+
3. `exit`<br>Exit the container
45+
46+
1. Copy the .so file(s) to the final image
47+
1. `cat Dockerfile.3`<br> Note the addition of the `libonig.so.5` library to the final image
48+
1. `docker build . -t mstage:3 -f Dockerfile.3`
49+
1. `docker run --rm -it mstage:3`<br>Now the `jq` command should work

containers-102/layers/Dockerfile.1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM cgr.dev/chainguard/wolfi-base
2+
RUN apk --no-cache add wget
3+
WORKDIR /workdir
4+
RUN wget -O nginx.tar.gz https://github.com/nginx/nginx/releases/download/release-1.27.2/nginx-1.27.2.tar.gz
5+
RUN tar -xzvf nginx.tar.gz
6+
RUN rm nginx.tar.gz

containers-102/layers/Dockerfile.2

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM cgr.dev/chainguard/wolfi-base
2+
RUN apk --no-cache add wget
3+
WORKDIR /workdir
4+
RUN wget -O nginx.tar.gz https://github.com/nginx/nginx/releases/download/release-1.27.2/nginx-1.27.2.tar.gz && \
5+
tar -xzvf nginx.tar.gz && \
6+
rm nginx.tar.gz

containers-102/layers/cleanup.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# env bash
2+
docker rmi layers:1 layers:2

containers-102/layers/layers.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#! env bash
2+
. ../../base.sh
3+
TAGS=$(docker images layers --format json | jq -r .Tag)
4+
for tag in $TAGS; do
5+
docker rmi layers:$tag
6+
done
7+
clear
8+
banner "Step 1: Get a big file, untar it, and remove the tarball"
9+
$BATCAT Dockerfile.1
10+
p "docker build . -t layers:1 -f Dockerfile.1"
11+
docker build . -t layers:1 -f Dockerfile.1 --quiet
12+
pe "docker images layers"
13+
pe "docker image history layers:1"
14+
wait
15+
16+
banner "Step 2: Concatenate operations into a single RUN line"
17+
$BATCAT Dockerfile.2
18+
p "docker build . -t layers:2 -f Dockerfile.2"
19+
docker build . -t layers:2 -f Dockerfile.2 --quiet
20+
pe "docker images layers"
21+
p "diff Dockerfile.1 Dockerfile.2"
22+
diff --color=always Dockerfile.1 Dockerfile.2
23+
pe "docker image history layers:1"
24+
pe "docker image history layers:2"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM cgr.dev/chainguard/wolfi-base AS builder
2+
RUN apk --no-cache add wget
3+
WORKDIR /workdir
4+
RUN wget -O /tmp/nginx.tar.gz https://github.com/nginx/nginx/releases/download/release-1.27.2/nginx-1.27.2.tar.gz
5+
RUN tar -xzvf /tmp/nginx.tar.gz
6+
7+
FROM cgr.dev/chainguard/wolfi-base:latest
8+
COPY --from=builder /workdir /workdir
9+
WORKDIR /workdir
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM cgr.dev/chainguard/python:latest-dev AS builder
2+
USER root
3+
RUN apk --no-cache add jq
4+
USER nonroot
5+
# other stuff ...
6+
7+
# Use a more minimal base image
8+
FROM cgr.dev/chainguard/python:latest
9+
# COPY --from=builder other stuff I built above...
10+
COPY --from=builder /usr/bin/jq /usr/bin/jq
11+
ENTRYPOINT ["/usr/bin/jq"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
FROM cgr.dev/chainguard/python:latest-dev AS builder
2+
USER root
3+
RUN apk --no-cache add jq
4+
USER nonroot
5+
# other stuff ...
6+
7+
# Use a more minimal base image
8+
FROM cgr.dev/chainguard/python:latest
9+
# COPY --from=builder other stuff I built above...
10+
COPY --from=builder /usr/bin/jq /usr/bin/jq
11+
COPY --from=builder /usr/lib/libonig.so.5 /usr/lib/libonig.so.5
12+
COPY --from=builder /usr/lib/libjq.so.1 /usr/lib/libjq.so.1
13+
ENTRYPOINT ["/usr/bin/jq"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM cgr.dev/chainguard/python:latest-dev AS build
2+
# Do stuff
3+
4+
USER root
5+
COPY --from=cgr.dev/chainguard/python:latest / /base-chroot
6+
RUN echo 'print("hello")' > /base-chroot/hello.py
7+
8+
FROM cgr.dev/chainguard/python:latest
9+
COPY --from=build /base-chroot /
10+
11+
CMD ["/hello.py"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM cgr.dev/chainguard/python:latest-dev AS build
2+
# Do stuff
3+
4+
USER root
5+
COPY --from=cgr.dev/chainguard/python:latest / /base-chroot
6+
RUN echo 'print("hello")' > /base-chroot/hello.py
7+
8+
FROM cgr.dev/chainguard/python:latest
9+
COPY --link --from=build /base-chroot /
10+
11+
CMD ["/hello.py"]

0 commit comments

Comments
 (0)