Notes on Docker
- Docker is a platform or ecosystem around creating and running containers.
- Image: Single file with all the deps and configs required to run a program
Images are read-only templates with instructions to create a docker container
- File System Snapshot (Example: bin, dev, etc, home, proc, root files for Busybox. Other apps have different file system.)
- Startup command
- Container: Instance of a running image that runs a program. A program with its own set of hardware resources.
- Uses:
- Namespaces : Resource Isolation
- Cgroups : Resource limiting
- Seccomp-bpf : Limiting syscalls
- Uses:
- Docker makes it really easy to install and run software without worrying about setup or dependencies.
Redis:
docker run -it redis
*docker-cli
(docker client) reaches docker-hub, downloads an image and run as a container. - Docker client: Tool that commands are issued to
- Docker Server (daemon): Responsible for creating images, running containers, etc.
- The Docker client contacted the Docker daemon.
- The Docker daemon could not find the “hello-world” image in the Image Cache.
- The Docker daemon pulled the “hello-world” image from the Docker Hub. (amd64)
- The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
- The Docker daemon streamed that output to the Docker client, which sent it to your terminal.
- The Docker client contacted the Docker daemon.
- When docker is installed on MacOS/Windows, the Docker Server is run as a Linux Virtual Machine.
Building an image
- Sample dockerfile
FROM node:12-slim
COPY server.js server.js
CMD ["node", "server.js"]
- Each step
FROM
,COPY
,CMD
creates an image that is consumed by the subsequent step. ANodeJS
Image is created, a temporary container is created where a file is copied. This new container is used to generate a snapshot (image-2). This image-2 is then used to create a final image which has the Startup command set asCMD
. - Javascript code
server.js
const http = require("http");
const app = (req, res) => {
console.log("ping!");
res.end("Hello there.", "utf-8");
}
http.createServer(app).listen(3000);
console.log("server started");
- Building the image
[rritesh-a02:rritesh:~] docker build -t rritesh-node-img .
- Downloads node baseimage from Docker-Hub and creates the template image, by Copying the
server.js
. Doesn’t run theCMD
. - Tags the images as
rritesh-node-img
.
[rritesh-a02:rritesh:~] docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
rritesh-node-img latest bc63aa5603f8 7 minutes ago 142MB
hello-world latest bf756fb1ae65 13 months ago 13.3kB
[rritesh-a02:rritesh:~] docker create --name my-app --init -p 3000:3000 rritesh-node-img 703e2532312a6ace890b97e2bdcd88c03f19435b5f952015c373831df72dd0ae
-p
does port mapping between localhost and docker container.--init
uses Tini package that handlesCtrl-C
Playing around with docker
[rritesh-a02:rritesh:~] docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
703e2532312a rritesh-node-img "docker-entrypoint.s…" 24 seconds ago Created my-app
[rritesh-a02:rritesh:~] docker start my-app
my-app
[rritesh-a02:rritesh:~] docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
703e2532312a rritesh-node-img "docker-entrypoint.s…" 2 minutes ago Up 5 seconds 0.0.0.0:3000->3000/tcp my-app
[rritesh-a02:rritesh:~] docker attach my-app # Attaches to the docker container and prints the logs; Ctrl-C to exit, which also stops the app
ping!
ping!
ping!
attach
command attaches to the primary process of the container, PID 1.- If you run
attach
, your terminal is going to get stuck displaying the container logs. Worse, if youattach
and thenctrl-C
to get out, it will actually stop the container on exit. Or worse, it will just ignore the ctrl-C and trap your terminal. If that ever happens to you, you’ll have to open a new terminal and stop the container. That’s why in your applications you should handle theSIGTERM
or use the Tini package like we have in our example. A better way to see output is the Docker logs command:
[rritesh-a02:rritesh:~] docker logs -f my-app
server started
ping!
ping!
ping!
- Run a bash shell on the container, notice that the server.js file is copied on the root mount point
[rritesh-a02:rritesh:~] docker exec -it my-app bash
root@703e2532312a:/# ls # <= root@<docker ID>
bin boot dev etc home lib lib64 media mnt opt proc root run sbin server.js srv sys tmp usr var
- Stop the container: Sends a
SIGTERM
to the primary process in the container
[rritesh-a02:rritesh:~] docker stop my-app
my-app
[rritesh-a02:rritesh:~] docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
703e2532312a rritesh-node-img "docker-entrypoint.s…" 13 minutes ago Exited (143) 3 seconds ago my-app
docker kill
can be used to send SIGKILL. If docker stop is not handled by container in 10 sec, a docker kill is sent to it.- Remove container
[rritesh-a02:rritesh:~] docker rm my-app
my-app
[rritesh-a02:rritesh:~] docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
run
is a shortcut that takes care of create, start, and attach all at once.--rm
flag removes the container when we stop it (stop+rm).
[rritesh-a02:rritesh:~] docker run -d --name my-app -p 3000:3000 --init --rm rritesh-node-img
700e9387cbca4e7d95f456136bd0046566471bc2130d48cdfe34241ea7ded05c
[rritesh-a02:rritesh:~] docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
700e9387cbca rritesh-node-img "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 0.0.0.0:3000->3000/tcp my-app
docker system prune
will remove all stopped containers, dangling images and build cache.-i
=> interactive: The STDOUT of terminal is piped to the STDIN of the running container, and vice versa-t
=> psuedo-tty: Give a psuedo terminal to interact with.
[rritesh-a02:rritesh:~] docker exec -i fd0c9599579f redis-cli (# Notice no psuedo terminal)
set mynumber "5"
OK
^C
[rritesh-a02:rritesh:~] docker exec -it fd0c9599579f redis-cli
127.0.0.1:6379> get mynumber
"5"
docker commit
is used for converting a container into an image.docker-compose up -d
=> Create multiple containers and network them (-d means detach). Refer Nginx notesdocker-compose down
=> Brings down (stops) all the containers in the current compose.
Mapping volumes
- Changing
index.html
file everytime and rebuilding the nginx image will take too much time. - Instead a local volume of the HOST can be mapped to the container such that the
index.html
is taken from there:
[rritesh-a02:rritesh:~] docker run -d --name nginx-app -p 8000:80 -v /tmp/nginx/html:/usr/share/nginx/html:ro --init --rm nginx
Multi step build
- Outputs from one image build can be taken as the input to another image build
FROM node:alpine as builder
WORKDIR '/app'
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
FROM nginx
COPY --from=builder /app/build /usr/share/nginx/html
-
The output of node app build
/app/build
is taken and copied over to nginx image. This final image will have an nginx server servingnode.js
web service. -
To make local docker daemon point to the docker registry inside minikube
> minikube docker-env
export DOCKER_TLS_VERIFY=”1"
export DOCKER_HOST=”tcp://172.17.0.2:2376"
export DOCKER_CERT_PATH=”/home/user/.minikube/certs”
export MINIKUBE_ACTIVE_DOCKERD=”minikube”
# To point your shell to minikube’s docker-daemon, run:
# eval $(minikube -p minikube docker-env)
> eval $(minikube -p minikube docker-env)
Written on July 20, 2021