The distributed systems that can be deployed by k8s are made up primarily of application container images.
Applications = language run time + libraries + source code
- Problems occur when you deploy an application to a machine that doesn’t available on the production OS. Such a program, naturally, has trouble executing.
- Deployment often involves running scripts which have a set of instructions resulting in a lot of failure cases being missed.
- The situation becomes messier if multiple apps deployed to a single machine use different versions of the same shared library.
Containers help solve the problems described above.
A container image is a binary package that encapsulates all the files
necessary to run an application inside of an OS container.
It bundles the application along with its dependencies (runtime, libraries, config, env variables) into a single artefact under a root filesystem. A container in a runtime instance of the image — what the image becomes in memory when executed. We can obtain container images in two ways:
- a pre-existing image for a container registry (a repository of container images to which people can push images which can be pulled by others)
- build your own locally
Once an image is present on a computer, it can be run to get an application running inside an OS container.
The Docker Image Format
- De facto standard for images
- made up of a series of layers of filesystem where each layers adds/removes/modifies files from the previous layer. It’s called an overlay filesystem.
Container images also have a configuration files which specify how to setup the env (networking, namespaces), the entry point for running the container, resource limits and privileges, etc.
The Docker image format = container root file system + config file
Containers can be of two types:
- System containers: like VMs, run a fool boot process, have system services like ssh, cron, etc.
- Application containers: commonly run only a single app
Building Application Images with Docker
Dockerfiles
It a file that automates the building of container images. Read more here . The book uses a demo app, the source code is available on GitHub. To run the kuar (Kubernetes Up and Running) image, follow these steps:
- Ensure you’ve Docker installed and running
- Download and clone the kuar repo
- Run make build to generate a binary
- Create a file named Dockerfile (no extension) containing the following:
FROM alpine
COPY bin/1/amd64/kuard /kuard
ENTRYPOINT [\”/kuard\”]
- Next, we build the image using the following command: $ docker build -t kuard-amd64:1 . The -t specifies the name of the tag. Tags are a way to version Docker images. the . tells docker to use the Dockerfile present in the current directory to build the image.
alpine as mentioned in the Dockerfile is a minimal Linux distribution that is used as a base image. More info can be found here.
Image Security
Don’t ever have passwords/secrets in any layer of your container image. Deleting it from one layer will not help if the preceding layers contain sensitive info.
Optimising Image Sizes
- If a file is present in a preceding layer, it’ll be present in the image that uses that layer even though it’ll be inaccessible.
- Every time a layer is changed, every layer that comes after is also changed. Changing any layer the image uses means that layer and all layers dependent on it need to be rebuilt, re-pushed and re-pulled for the image to work. As a rule of thumb, the layers should be ordered from least likely to change to most likely to change to avoid a lot of pushing and pulling.
Storing Images in a Remote Registry
To easily share container images to promote reuse and make them available on more machines, we use what’s called a registry. It’s a remote location where we can push our images and other people can download them from there. They’re of two types:
- Public: anyone can download images
- Private: authorisation is needed to download images
The book uses the Google Container Registry whereas I used the Docker Hub. After creating an account on Docker Hub, run the following commands:
- $ docker login
- $ docker tag kuard-amd64:1 $DockerHubUsername/kuard-amd64:1
- $ docker push $DockerHubUsername/kuard-amd64:1 Replace $DockerHubUsername with your username.
The Docker Container Runtime
The default container run time used by Kubernetes is Docker.
Running Containers with Docker
Run the following command to run the container that you pushed to Docker Hub in the previous step: $ docker run -d –name kuard -p 8080:8080 $DockerHubUsername/kuard-amd64:1 Let’s try to unpack everything that command does one thing at a time:
- -d tells Docker to run the contain in detached mode. In this mode, the container doesn’t attach its output to your terminal and runs in the background.
- —name gives a name to your container. Keep in mind it doesn’t alter the name of your image in anyway.
- -p enables port-forwarding. It maps port 8080 on your local machine to your container’s port 8080. Each container gets its own IP address and doesn’t have access to the host network (your machine in this case) by default. Hence, we’ve to explicitly expose the port.
To stop & remove the container, run: $ docker stop kuard $ docker rm kuard
Docker allows controlling how many resources your container can use (memory, swap space, CPU) etc., using various flags that can be passed to the run command.
Images can be removed using the following command: $ docker rmi
Docker IDs can be shortened as long as they remain unique.