Docker Fundamentals

Last update: 2022-01-28 15:44:22 +0800 +0800
Available translations: 日本語 / 中文(简体) / 中文(繁體)

Docker, the container system that still depends on your kernel, your CPU ISA, and its x86-64 syscall. An application that runs in a docker container is said to be containerized.

Component Overview #

Docker Engine: dockerd #

dockerd is a CLI daemon program that manages installed containers on the local system. It is branded as Docker Engine or Docker CE (Community Edition), and is open-source and free.

The dockerd daemon listens on the UNIX domain socket /var/run/docker.sock for incoming clients. This socket file must be readable by the user who runs a docker client to establish the socket (to send HTTP request). If you installed the Docker Engine from your Linux distro’s package manager, this socket file may be only readable by the root or a special user group dedicated to Docker, e.g. docker. You may choose to add yourself to that user group, or simply become root whenever using the docker client. Use docker info to check if the dockerd is running and the client has permissions.

The dockerd daemon exposes HTTP APIs for the management of containers, which can be used by any program. An official client program is the docker CLI program.

Docker Desktop #

Docker Desktop is a proprietary GUI client program that talks to dockerd and perform housekeeping of containers. Using the Docker Desktop application is not mandatory.

Docker Compose #

https://docs.docker.com/compose/

Docker Compose is another CLI client that communicates with the dockerd. Its executable is docker-compose. It specifies properties of containers using a docker-compose.yml file rather than, typing docker run options all over the place. This is useful for setting up reoccurring services that are frequently used and/or have complex configurations.

Images #

A docker image consists of layers of filesystem content where each layer adds some files to a previous layer. An image is said to be based on another image, if its first layer depends on all layers of another iamge.

An image has a human-readable name REPOSITORY, and a human-readable TAG (usually, but not mandatory, its version number). A SHA256 hash known as IMAGE ID uniquely identify an image.

To build your own image, create a Dockerfile with a simple syntax for defining the steps needed to create the image. Each instruction in a Dockerfile creates a layer in the image. When the Dockerfile is modified and the image needs to be rebuilt, only those layers which have changed are rebuilt.

For example, the esolang/vim:latest image contains 10 layers.

sh
# $ Docker Pull Esolang/vim
Using default tag: latest
latest: Pulling from esolang/vim
4abcf2066143: Downloading  2.951MB/3.409MB
e7609a7fad9e: Download complete
a891a2921638: Download complete
6ea6322cdcb0: Download complete
729f825b6ae6: Download complete
e6cb43f5f474: Downloading  2.618MB/31.24MB
c12ed1c2e19b: Download complete
6928286dd6f6: Download complete
05de04103836: Download complete
b5a8264627eb: Download complete

Docker doesn’t store the Dockerfile in the built image, making it a little bit hard to inspect how an image is built.

This is because an image can also be created by running a container, making modifications and committing the result. In fact, one can think Dockerfile to be a script that automates this run-modification-commit process.

Minimal Images #

Build a minimal docker image with no base image and no filesystem content (other than a minimal hello world executable):

asm
; linux_syscall call_no, arg0, arg1, arg2, arg3, arg4, arg5
%macro linux_syscall 1-7 0,0,0,0,0,0

    mov rax, %1
    mov rdi, %2
    mov rsi, %3
    mov rdx, %4
    mov r10, %5
    mov r8, %6
    mov r9, %7
    syscall

%endmacro



SECTION .data
msg:    db `hello world\n`
msglen: equ $-msg

GLOBAL main

SECTION .text
main:
    ; write to stdout a string
    linux_syscall 1,1,msg,msglen

    ; exit the process with code 42
    linux_syscall 0x3c, 42

build the executable with make:

Makefile
main: main.o
	# -N: don't align data segment on a new memory page, thus makes the executable as small as possible
	ld -N -e manbaout -omain main.o

main.o: main.asm
	nasm -f elf64 -o main.o main.asm

clean:
	rm *.o main

Build an image with the following Dockerfile:

Dockerfile
FROM    scratch
ADD     main    /
sh
docker build -t foo .

This gives us a docker image of only 904 bytes (reported by docker image ls) on my machine. Run a container from the image:

sh
docker run foo ./main

Containers #

A container is a running instance of an image. The lifecycle of a container starts from a docker container create <image> command, followed by a docker start <container>. docker run <image> is a shortcut that does both, plus download the image from your configured registry (default: the docker hub) if <image> is not presented locally. docker run always creates a brand new container from a given image and starts it.

To use an existing but inactive (exited or paused) container, use docker start again.

At any particular instant, a Docker container can be found in one of 6 possible states.

  1. created: intact, the container has never been started since its creation.
  2. running: the ENTRYPOINT process is running (to be precise, a wait(2) on it blocks)
  3. Restarting:
  4. Exited(num): the ENTRYPOINT process exited with num.
  5. Paused:
  6. Dead:

Dockerfile #

Only 17 directive are defined for Dockerfile:

name
ADDAdd local or remote files and directories.
ARGUse build-time variables.
CMDSpecify default commands.
COPYCopy files and directories.
ENTRYPOINTSpecify default executable.
ENVSet environment variables.
EXPOSEDescribe which ports your application is listening on.
FROMCreate a new build stage from a base image.
HEALTHCHECKCheck a container’s health on startup.
LABELAdd metadata to an image.
MAINTAINERSpecify the author of an image.
ONBUILDSpecify instructions for when the image is used in a build.
RUNExecute build commands.
SHELLSet the default shell of an image.
STOPSIGNALSpecify the system call signal for exiting a container.
USERSet user and group ID.
VOLUMECreate volume mounts.
WORKDIRChange working directory.

Only the instructions RUN, COPY, ADD create layers perpetuated in the resulting image.

Most instructions instruct how docker image build command should put a new layer the resulting static image, such that.

  • An exception being the RUN command that execute an external command immediately at build-time.

It’s very important to distinguish an instruction that gets executed instantaneously when docker image build is running, and one that instructs how docker should behave after a container is instantiated from the created image.

CLI Cheatsheet #

sh
# Show Active Container
docker container ls
# Show All Container Includes Dead One
docker container ls -a
# Stop Certain Containers
docker stop <cid1> <cid2> ...
# Stop All Active Containers
docker stop $(docker container ls –aq)

Comments

Read or comment on GitHub (sign-in required to comment)