Docker 基础

最后更新: 2022-01-28 15:44:22 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

Docker 是一个仍然依赖主机内核、CPU ISA 及其 x86-64 syscall 的容器系统。 在 Docker 容器中运行的应用称为容器化应用。

组件概览 #

Docker Engine:dockerd #

dockerd 是一个 CLI 守护进程,用于管理本地系统中安装的容器。 它以 Docker Engine 或 Docker CE(社区版)为产品名称,并且开源、免费。

dockerd 守护进程在 UNIX 域套接字 /var/run/docker.sock 上侦听传入的客户端连接。 运行 Docker 客户端的用户必须拥有此套接字文件的读取权限,才能建立套接字连接(以发送 HTTP 请求)。 如果通过 Linux 发行版的包管理器安装 Docker Engine,此套接字文件可能只允许 root 或 Docker 专用用户组(例如 docker)读取。 可以选择将自己加入该用户组,也可以直接切换为 root 后再使用 docker 客户端。 使用 docker info 检查 dockerd 是否正在运行,以及客户端是否拥有相应权限。

dockerd 守护进程公开用于管理容器的 HTTP API,任何程序均可调用。 官方客户端程序是 docker CLI。

Docker Desktop #

Docker Desktop 是专有的 GUI 客户端程序,它与 dockerd 通信并执行容器的日常管理。 并非必须使用 Docker Desktop 应用。

Docker Compose #

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

Docker Compose 是另一个与 dockerd 通信的 CLI 客户端,其可执行文件为 docker-compose。 它使用 docker-compose.yml 文件指定容器属性,而不必到处键入 docker run 选项。 该工具适合配置反复使用和/或配置复杂的服务。

镜像 #

Docker 镜像由多层文件系统内容组成,每一层都在前一层之上添加一些文件。 如果某个镜像的第一层依赖另一个镜像的全部层,则称该镜像基于另一个镜像。

镜像具有人类可读的名称 REPOSITORY 和人类可读的 TAG(通常是版本号,但并非强制要求)。 称为 IMAGE ID 的 SHA256 哈希可唯一标识镜像。

要构建自己的镜像,需要创建一个 Dockerfile,并使用简单语法定义创建镜像所需的步骤。 Dockerfile 中的每条指令都会在镜像中创建一层。 修改 Dockerfile 并重新构建镜像时,仅重新构建发生变化的层。

例如,esolang/vim:latest 镜像包含 10 层。

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 不会在构建后的镜像中存储 Dockerfile,因此检查镜像的构建方式会稍显困难。

原因在于,也可以通过运行容器、进行修改并提交结果来创建镜像。 实际上,可以将 Dockerfile 视为自动执行“运行—修改—提交”过程的脚本。

最小镜像 #

构建一个没有基础镜像且没有文件系统内容的最小 Docker 镜像(其中仅包含一个最小的 hello world 可执行文件):

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

使用 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

使用以下 Dockerfile 构建镜像:

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

在我的计算机上,这会生成一个只有 904 字节的 Docker 镜像(由 docker image ls 报告)。从该镜像运行容器:

sh
docker run foo ./main

容器 #

容器是镜像的运行实例。容器的生命周期从 docker container create <image> 命令开始,随后执行 docker start <container>。docker run <image> 是同时完成这两步的快捷方式;如果本地不存在 <image>,它还会从已配置的注册表(默认为 Docker Hub)下载镜像。docker run 始终基于给定镜像创建一个全新容器并启动它。

要使用已有但未运行(已退出或已暂停)的容器,请再次使用 docker start。

在任意时刻,Docker 容器会处于以下 6 种状态之一。

  1. created:完好;容器自创建以来从未启动。
  2. running:ENTRYPOINT 进程正在运行(准确地说,对它执行 wait(2) 会阻塞)
  3. Restarting:
  4. Exited(num):ENTRYPOINT 进程以 num 退出。
  5. Paused:
  6. Dead:

Dockerfile #

Dockerfile 仅定义了 17 条指令:

名称
ADD添加本地或远程文件及目录。
ARG使用构建时变量。
CMD指定默认命令。
COPY复制文件和目录。
ENTRYPOINT指定默认可执行文件。
ENV设置环境变量。
EXPOSE描述应用正在侦听的端口。
FROM从基础镜像创建新的构建阶段。
HEALTHCHECK在启动时检查容器的健康状态。
LABEL向镜像添加元数据。
MAINTAINER指定镜像作者。
ONBUILD指定镜像用于构建时执行的指令。
RUN执行构建命令。
SHELL设置镜像的默认 shell。
STOPSIGNAL指定退出容器所用的系统调用信号。
USER设置用户和组 ID。
VOLUME创建卷挂载。
WORKDIR更改工作目录。

只有 RUN、COPY 和 ADD 指令会创建保留在最终镜像中的层。

多数指令规定 docker image build 命令应如何在最终的静态镜像中添加新层。

  • RUN 命令是一个例外,它会在构建时立即执行外部命令。

区分在 docker image build 运行时立即执行的指令,以及规定从所创建镜像实例化容器后 Docker 应如何操作的指令,至关重要。

CLI 速查表 #

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)

评论

在 GitHub 上阅读或评论(发表评论需要登录)