There is no significant change to the *content* here, but a lot of typo fixes and commands added so that the autopilot works correctly.
3.7 KiB
Building images with the Docker Engine
-
Until now, we have built our images manually, directly on a node
-
We are going to show how to build images from within the cluster
(by executing code in a container controlled by Kubernetes)
-
We are going to use the Docker Engine for that purpose
-
To access the Docker Engine, we will mount the Docker socket in our container
-
After building the image, we will push it to our self-hosted registry
Resource specification for our builder pod
.small[
apiVersion: v1
kind: Pod
metadata:
name: build-image
spec:
restartPolicy: OnFailure
containers:
- name: docker-build
image: docker
env:
- name: REGISTRY_PORT
value: "`3XXXX`"
command: ["sh", "-c"]
args:
- |
apk add --no-cache git &&
mkdir /workspace &&
git clone https://github.com/jpetazzo/container.training /workspace &&
docker build -t localhost:$REGISTRY_PORT/worker /workspace/dockercoins/worker &&
docker push localhost:$REGISTRY_PORT/worker
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
]
Breaking down the pod specification (1/2)
-
restartPolicy: OnFailureprevents the build from running in an infinite lopo -
We use the
dockerimage (so that thedockerCLI is available) -
We rely on the fact that the
dockerimage is based onalpine(which is why we use
apkto installgit) -
The port for the registry is passed through an environment variable
(this avoids repeating it in the specification, which would be error-prone)
.warning[The environment variable has to be a string, so the "s are mandatory!]
Breaking down the pod specification (2/2)
-
The volume
docker-socketis declared with ahostPath, indicating a bind-mount -
It is then mounted in the container onto the default Docker socket path
-
We show a interesting way to specify the commands to run in the container:
-
the command executed will be
sh -c <args> -
argsis a list of strings -
|is used to pass a multi-line string in the YAML file
-
Running our pod
- Let's try this out!
.exercise[
-
Check the port used by our self-hosted registry:
kubectl get svc registry -
Edit
~/container.training/k8s/docker-build.yamlto put the port number -
Schedule the pod by applying the resource file:
kubectl apply -f ~/container.training/k8s/docker-build.yaml -
Watch the logs:
stern build-image
]
What's missing?
What do we need to change to make this production-ready?
-
Build from a long-running container (e.g. a
Deployment) triggered by web hooks(the payload of the web hook could indicate the repository to build)
-
Build a specific branch or tag; tag image accordingly
-
Handle repositories where the Dockerfile is not at the root
(or containing multiple Dockerfiles)
-
Expose build logs so that troubleshooting is straightforward
--
🤔 That seems like a lot of work!
--
That's why services like Docker Hub (with automated builds) are helpful.
They handle the whole "code repository → Docker image" workflow.
Things to be aware of
-
This is talking directly to a node's Docker Engine to build images
-
It bypasses resource allocation mechanisms used by Kubernetes
(but you can use taints and tolerations to dedicate builder nodes)
-
Be careful not to introduce conflicts when naming images
(e.g. do not allow the user to specify the image names!)
-
Your builds are going to be fast
(because they will leverage Docker's caching system)