Docker 疑难问题

docker

安装

开发测试环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
curl -fsSL https://get.docker.com | bash -s docker

# 配置docker
cat >/etc/docker/daemon.json<<EOF
{
"default-runtime": "nvidia",
"exec-opts": [
"native.cgroupdriver=systemd"
],
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
},
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": true,
"features": {
"buildkit": true
},
"insecure-registries": [
"harbor.baijiayun.com",
"docker.huaguisystems.com"
],
"registry-mirrors": [
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://reg-mirror.qiniu.com"
]
}
EOF

# 重启docker
systemctl restart docker

links:

更新

查看系统版本,根据官方 文档 更新

1
cat /etc/os-release

QA: Error response from daemon: Unknown runtime specified docker-runc
当从不兼容的版本升级 docker 并且升级后无法启动 docker 容器时会出现这种情况,执行一下命令,然后重启 docker。

1
grep -rl 'docker-runc' /var/lib/docker/containers/ | xargs sed -i 's/docker-runc/runc/g'

dockerd

1
2
ps -ef | grep dockerd
root 6515 1 1 15:28 ? 00:01:08 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock 是 Docker daemon 的启动命令,其中:

  • /usr/bin/dockerd 是 Docker daemon 的路径。

  • -H fd:// 是 Docker daemon 的监听地址,fd:// 是一个特殊的 Unix socket,用于 systemd socket activation。

  • –containerd=/run/containerd/containerd.sock 是指定 Docker daemon 使用的 containerd 的 socket 文件路径。

Docker daemon 使用 containerd 作为其默认的容器运行时,主要是因为 containerd 是一个轻量级的、高性能的开源容器运行时,它可以管理完整的容器生命周期,包括镜像管理、容器执行、任务管理、网络管理等。

除了 containerd,Docker 还支持其他的容器运行时,例如 runc、gVisor、Kata Containers 等。可以通过修改 Docker daemon 的配置文件来更改默认的容器运行时。

cgroup driver

Docker 的 cgroup driver 主要有两种类型:systemd 和 cgroupfs。

  • systemd: 当 Docker 使用 systemd 作为其 cgroup driver 时,它将会使用 systemd 来创建和管理 cgroup。这意味着 Docker 将会与系统的其他部分(也使用 systemd 的部分)共享同一套 cgroup,从而实现更好的资源管理。

  • cgroupfs: 当 Docker 使用 cgroupfs 作为其 cgroup driver 时,它将会直接与 cgroup 文件系统交互来创建和管理 cgroup。这意味着 Docker 将会有自己独立的一套 cgroup,与系统的其他部分(使用 systemd 的部分)分开。

总的来说,systemd 和 cgroupfs 的主要区别在于它们与系统的其他部分的交互方式不同。systemd 更倾向于与系统的其他部分共享资源,而 cgroupfs 则更倾向于独立管理资源。

要将 Docker 的 cgroup driver 从 cgroupfs 迁移到 systemd,需要在 Docker 的配置文件中进行更改。以下是步骤:

  • 打开 Docker 的配置文件,通常位于 /etc/docker/daemon.json。如果文件不存在,需要创建它。

1
nano /etc/docker/daemon.json
  • 在配置文件中添加或修改 "exec-opts",将其设置为 "native.cgroupdriver=systemd"。

1
2
3
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
  • 保存并关闭文件,然后重启 Docker 服务。

1
systemctl restart docker

迁移到 systemd 的好处主要有:

  • 更好的资源管理:systemd 可以与系统的其他部分共享 cgroup,从而实现更好的资源管理。

  • 更好的兼容性:一些 Kubernetes 工具(如 kubeadm)要求 Docker 使用 systemd 作为其 cgroup driver,以确保与 Kubernetes 的兼容性。

  • 更好的稳定性:systemd 作为 cgroup driver 的稳定性通常比 cgroupfs 更好。

links:

command

docker daemon service

1
2
service docker start/stop/restart/status
systemctl start/stop/restart docker

volume

1
2
3
4
5
docker volume ls
# 清除匿名不再引用的 volume
docker volume prune
# 清除所有不再引用的 volume
docker volume ls -f dangling=true | awk '{print $2}' | xargs docker volume rm

docker QA

以下为 Docker 中各种疑难问题及解答

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/images/json: dial unix /var/run/docker.sock: connect: permission denied

docker daemon 配置

docker 运行配置主要通过文件 daemon.json 配置。所在路径在 /etc/docker/daemon.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
// 配置docker运行数据储存路径
"data-root": "/home/docker",
// 配置docker仓库源
"insecure-registries": [
// 私有源
"harbor.xxx.com"
],
// 公开源
"registry-mirrors": [
"https://docker.mirrors.sjtug.sjtu.edu.cn"
]
}

links:

docker context

docker context 用于本地方便地访问远程主机的 docker 服务。在不需要手动通过 ssh 连接远程服务器时比较有帮助。

添加 context

1
docker context create <context-name> --docker "host=ssh://format"

这里 format 可使用一下格式:

  • username@host-ip[:port]

  • name,指在~/.ssh/config 中提供的 ssh 连接配置名称。

示例:

1
2
3
4
5
6
7
$ cat ~/.ssh/config
Host my-remote-docker-machine
Hostname host
User username
Port 12345

$ docker context create my-remote-docker-machine --docker "host=ssh://my-remote-docker-machine"

常用命令

下面列出了常用的 docker context 命令和示例。

1
2
3
4
5
6
7
8
$ docker --context my-remote-docker-machine images -q
65dadc9c7fe7
f814fce55133
7a9b6da4328e
33655f17f093
d120da10b040
6d6859d1a42a
c19ae228f069
1
2
3
4
5
6
7
$ docker context use my-remote-docker-machine
my-remote-docker-machine
Current context is now "my-remote-docker-machine"
$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
my-remote-docker-machine * ssh://username@host
1
2
3
$ docker context use default # back to default
$ docker context rm my-remote-docker-machine
my-remote-docker-machine

使用 docker 上下文可能有助于避免手动将 SSH 连接到远程服务器。但是,当涉及到在本地使用远程 docker 构建映像时,需要考虑将上载 / 下载多少 docker 上下文。

reference

docker run permission

–cap-add

通常用于开发用的镜像需要设置 cli 参数给予相应的容器权限。

  • –cap-add=NET_RAW: 允许容器进程使用原始套接字,直接访问网络层,一般进行网络嗅探等网络底层操作的容器进程需要。

  • –cap-add=SYS_PTRACE: 允许容器进程使用 ptrace 系统调用。 ptrace 允许一个进程监视和控制另一个进程的执行,包括读取和修改其内存和寄存器状态。这个选项通常用于需要进行调试或其他进程控制操作的容器。

  • –cap-add=NET_ADMIN: 允许容器进程使用网络管理功能。该选项需要对网络进行配置或管理的容器,例如配置网络接口、设置路由或进行网络诊断等操作。

–security-opt

  • –security-opt seccomp=unconfined: 允许设置容器的 seccomp 配置。seccomp 是一种 Linux 内核安全模块,它可以限制进程可以执行的系统调用。该选项禁用 seccomp 配置,从而允许容器进程执行所有系统调用,通常用于需要执行一些不受限制的系统调用的容器,但是这也会降低容器的安全性。

–privileged

  • 它允许容器进程拥有主机上的所有特权。这个选项通常用于需要访问主机上的特权设备或执行一些需要特权的操作的容器。使用这个选项会增加容器的安全风险,因为容器进程可以访问主机

–gpus

允许访问主机 gpu 资源

  • [num]: gpu 数量

  • all: 所有 gpu

[!TIP]
如果需要支持 Nvidia Cuda,则需要额外安装支持的 Docker Runtime

1
2
apt update && apt install -y nvidia-docker2 \
&& nvidia-ctk runtime configure

验证 gpu 是否可用

1
2
# https://catalog.ngc.nvidia.com/orgs/nvidia/teams/k8s/containers/cuda-sample
docker run --rm --gpus=all nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2

QA

  • failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error running hook #0: error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: requirement error: unsatisfied condition: cuda>=11.7: unknown.

镜像版本要求 cuda 需要大于 11.7:

  1. 升级驱动满足镜像要求

  2. 采用符合要求的镜像

容器中执行设置错误退出

1
2
3
4
5
6
7
8
9
10
# set -e 配置遇到错误即退出,并设置退出错误码255
docker run --rm \
--volume "$PWD":/src \
-w /src \
python:3.8-bullseye \
bash -c "set -e && \
pip config set global.index-url "https://pypi.tuna.tsinghua.edu.cn/simple/" && \
pip config set global.trusted-host "pypi.tuna.tsinghua.edu.cn" && \
pip install mlflow==2.4.2 || \
exit 255"

dockerignore

.dockerignore 主要用于在 docker 构建镜像时忽略不需要打包进去的过滤方式,类似于 .gitignore 文件。该文件位于构建上下文的根目录。

匹配规则如下:

pattern description
/temp 匹配根路径下一级目录下所有以 temp 开头的文件或目录
//temp* 匹配根路径下两级目录下所有以 temp 开头的文件或目录
temp? 匹配根路径下以 temp 开头,任意一个字符结尾的文件或目录
**/*.go 匹配所有路径下以 .go 结尾的文件或目录,即递归搜索所有路径
*.md
!README.md
匹配根路径下所有以 .md 结尾的文件或目录,但 README.md 除外

[!CAUTION]
如果存在冲突的行或重叠包含关系,那么以后面的匹配规则为准。

reference

dockerfile

容器优化的思路和方法.

links:

RUN

使用 EOF 避免使用冗余的换行符运行,dockerfile:1.4 声明版本,或者直接指定版本 1

1
2
3
4
5
6
7
8
9
10
11
# syntax=docker/dockerfile:1

RUN <<-EOF
set -o errexit -o nounset -o pipefail
cd clash-dashboard
npm config set registry https://registry.npmmirror.com
npm i -g pnpm
pnpm install
npm run build
EOF

links:

ADD & COPY

在编写 Dockerfile 时经常需要拷贝文件或文件夹的操作,这时就需要用到 ADD 和 COPY 指令。

  • 拷贝单个文件到指定目录

1
2
#拷贝当前目录下的test.jar到/usr/bin目录下
ADD ./test.jar /usr/bin/
  • 拷贝特定的多个文件到指定目录

ADD 指令支持通配符,常用的示例如下:

1
2
3
4
5
6
7
8
9
#拷贝当前目录下的bin文件夹的所有sh文件到/usr/bin目录下
#拷贝当前目录下的bin文件夹的所有sh文件到/usr/bin目录下
ADD ./bin/*.sh /usr/bin/
#拷贝当前目录下的bin文件夹的所有带后缀的文件到/usr/bin目录下
ADD ./bin/*.* /usr/bin/
#拷贝当前目录下的bin文件夹的所有不带后缀的文件到/usr/bin目录下
ADD ./bin/* /usr/bin/
#拷贝当前目录下的bin文件夹的所有文件到/usr/bin目录下(/usr/bin目录原有的文件会保留)
ADD ./bin/ /usr/bin/
  • 拷贝文件夹到指定的目录

ADD 宿主机文件夹的全路径 docker 容器下的文件夹路径 + 新文件夹名

1
2
#拷贝当前目录下的config文件夹到/usr/bin目录下
ADD ./config /usr/bin/config

SHELL

用于覆盖默认的 Shell

1
2
3
4
5
6
7
8
9
10
11
12
# syntax=docker/dockerfile:1

FROM docker:latest

RUN <<-EOF
set -x
apk update && apk add --no-cache bash npm nodejs git
npm install -g @devcontainers/cli
EOF

# Override default shell as bash
SHELL ["/bin/bash", "-c"]

links:

dockerfile 优化

选择基础镜像

选择官方镜像.

使用具体的镜像 tag.

使用最小基础镜像.

优化指令顺序

把 WORKDIR/ENV 等命令放在前面,COPY/ADD 等命令放在后面 [^2]。

优化 WORKDIR/ENV 和 COPY/ADD 顺序.

使用更具体的 COPY 路径.

合并构建指令

合并多个 RUN 指令,减少层数.

清理中间缓存

清理系统包信息缓存.

用户数据缓存:

  • ~/.cache 等用户缓存。

  • 安装包临时缓存。

开发镜像和运行时镜像分离

runtime 镜像仅包含基本运行环境,开发镜像包含所有的开发依赖。开发镜像尽可能以 runtime 镜像为基础构建。

多阶段构建

多阶段构建

使用 buildkit

1
2
3
4
5
6
7
# 构建多平台镜像
$ docker buildx build --platform \
linux/arm,linux/arm64,linux/amd64 \
-t <group>/hello . --push

# 查看镜像信息
$ docker buildx imagetools inspect <group>/hello

使用构建缓存 RUN --mount

[!CAUTION]
buildkit 会使用 docker 构建缓存,也就是 Build Cache,需要定期清理。

查看缓存:docker system df

清理方式:echo yes | docker builder prune -a

二进制工具安装

从现有镜像中安装二进制文件

1
2
3
4
5
6
7
8
9
10
11
12
FROM golang:1.17

ARG GOLANG_LINT_VERSION=V1.43.0

ENV GOV PATH=/usr/local/bin/govc

COPY --from=vmware/govc:v0.27.2 /govc /usr/local/bin
COPY --from=dtzar/helm-kubectl:3.8.0 /usr/local/bin /usr/local/bin
COPY --from=koalaman/shellcheck:stable /bin/shellcheck /usr/local/bin/shellcheck
COPY -from=docker: 20.10.12-dind-rootless /usr/local/bin/docker /usr/local/bin/docker
COPY --from=hashicorp/packer:1.8 /bin/packer /usr/local/bin
COPY --from=quay.io/argoproj/argocli:v3.2.6 /bin/argo /usr/local/bin

reference

docker inspect

docker inspect 输出可以通过 --format, 使用 {{.}} 检索某个字段结果

1
2
3
4
5
6
# 输出原始数据, 这里`.`表示所有结果
docker inspect --format '{{.}}' <container name>
# 以json输出,并检索字段 LogPath
docker inspect --format '{{json .LogPath}}' <container name> | jq
# 以表格输出
docker inspect --format 'table {{.ID}}\t{{.Name}}\t{{.Node}}\t{{.CurrentState}}' <container name>

log

Docker 默认将日志存储到一个日志文件中。要检查日志文件路径,请运行命令

1
2
3
docker inspect --format='{{.LogPath}}' containername

/var/lib/docker/containers/f844a7b45ca5a9589ffaa1a5bd8dea0f4e79f0e2ff639c1d010d96afb4b53334/f844a7b45ca5a9589ffaa1a5bd8dea0f4e79f0e2ff639c1d010d96afb4b53334-json.log

要查看实时日志,可以在以下命令中运行

1
tail -f `docker inspect --format='{{.LogPath}}' containername`

注意:

/var/lib/docker/containers/f844a7b45ca5a9589ffaa1a5bd8dea0f4e79f0e2ff639c1d010d96afb4b53334/f844a7b45ca5a9589ffaa1a5bd8dea0f4e79f0e2ff639c1d010d96afb4b53334-json.log 仅当 docker 生成日志(如果没有日志)时,才会创建此日志文件,否则该文件将不存在。如果我们运行命令 docker logs containername,它类似于某个时候,但什么也不返回。在这种情况下,该文件将不可用。

  • 重定向

1
docker logs -f <yourContainer> &> your.log &

说明:

  • -f(即–follow):写入所有现有日志,并继续(跟随)记录接下来出现的所有内容。

  • &> 重定向标准输出和标准错误。

  • 可能想在后台运行该方法,因此 &。

  • 可以通过以下方式将输出和 stderr 分开:(> output.log 2> error.log 而不是使用 &>)。

docker port

porting 映射

默认情况下,宿主机是无法访问容器内部网络的,但是可以使用端口映射来解决这个问题。主要通过 docker run 跟 -P(大写) 或 -p(小写)参数来实现。docker run -P 会把容器中监听的端口随机绑定到宿主机的可用端口上:

1
2
3
4
5
6
7
8
9
docker run -p <format> image
# 默认是 tcp 协议,如果是 udp 协议,则可以显示指定
docker run -d -p 127.0.0.1:8080:80/udp nginx:latest
# 查看容器 port 映射情况
docker port container_ID #容器ID
#将nginx的80端口映射到宿主机的800端口上
docker run -d --name ng -it -p 800:80 nginx
# docker port ng
80/tcp -> 0.0.0.0:800

<format> 指定格式如下

  • ip:hostport:containerport #指定 ip、指定宿主机 port、指定容器 port

  • ip::containerport #指定 ip、未指定宿主机 port(随机)、指定容器 port

  • hostport:containerport #未指定 ip、指定宿主机 port、指定容器 port

容器互联

容器互联通过 --link 配置链接实现单独隔离容器的互联。

以下以 nginx + php-fpm 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 这里分别有一个 php-fpm 和 nginx 镜像。

# 1、先启动php-fpm 容器, 并使用 --name 参数指定容器名
[root@localhost ~] docker run -d --name php-fpm php:5.6.32-fpm
3e4b04174da9a91f77d9560113d3021f90a9638165968ccff44fede6c7961871
# 每一个运行中的Docker容器都有一块虚拟网卡和一个内网ip,可以进到上面的容器来查看:
# 先安装ifconfig命令,然后使用ifconfig查看ip地址信息
[root@localhost ~] docker exec -it php-fpm /bin/bash
root@3e4b04174da9:/var/www/html# apt-get update
root@3e4b04174da9:/var/www/html# apt-get install net-tools
root@3e4b04174da9:/var/www/html# ifconfig
# 可以看到php-fpm容器有一块 eth0 网卡, 其ip地址为 172.17.0.54,还可以查看hosts信息
root@3e4b04174da9:/var/www/html# cat /etc/hosts
# 容器ID解析到了该容器局域网IP

# 2、再启动nginx容器,同样指定一个名字,并使用 --link 连接到之前的php-fpm容器。
[root@localhost ~] docker run -d -p 8080:80 --name nginx --link php-fpm nginx:latest
03fe0d3fbd43b5db157992703f70dd6eff4555c4e49c3620e7a212c81824778f
# 此时 nginx 容器就连接到 php-fpm 容器上了,可以进入nginx容器查看相关环境变量和hosts信息
[root@localhost ~] docker exec -it nginx /bin/bash
root@03fe0d3fbd43:/ env
# 能够看到 nginx 容器中有很多 PHP_FPM 相关的环境变量,而hosts中除了有本身容器ID与自身IP地址的解析关系外,
# 还包含了php-fpm 容器的解析,我们可以使用 ping 或 telnet 命令查看两个容器之间的网络是否畅通。
# 先安装 ping 和 telnet :
root@03fe0d3fbd43:/ apt-get install iputils-ping
root@03fe0d3fbd43:/ apt-get install telnet
root@03fe0d3fbd43:/ ping php-fpm
# 看到连接了容器之后可以直接用容器名来访问,非常方便
# 现在我们可以配置 nginx 的 fastcgi, 转发php请求到 php-fpm 容器
# 先安装VI:
root@03fe0d3fbd43:/ apt-get install vim-tiny
# 然后修改 /etc/nginx/conf.d/default.nginx
# 记得修改好后 reload 一下nginx
root@03fe0d3fbd43:/ /etc/init.d/nginx reload
# 在php-fpm容器的 /php 目录下创建一个 test.php,并添加相应的权限
[root@localhost ~] docker exec -it php-fpm /bin/bash
root@0805ea04f2c8:/var/www/html# mkdir /php
root@0805ea04f2c8:/var/www/html# echo '<?php echo time() . "\n";' > /php/test.php
root@0805ea04f2c8:/var/www/html# chmod 777 /php/test.php
# 然后在宿主机下访问该php文件:
[root@localhost ~] curl '127.0.0.1:8080/test.php'
1509695115
[root@localhost ~] curl '127.0.0.1:8080/test.php'
1509695138

参考

dumb-init

这里介绍了一种容器初始化系统 dumb-init

主要关注于解决两个问题。

  • 作为 PID 为 1 容器进程的信号处理。

  • 孤儿僵尸进程回收。

为什么使用 dumb-init

使用时需注意参考

install

通过系统命令安装。

1
yum/apt/apk install -y dumb-init

通过 pip 安装管理器。

1
pip install dumb-init

通过 github 安装

1
2
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64
RUN chmod +x /usr/local/bin/dumb-init

参考

docker template

本文主要搜集了标准的 docker 镜像的标准模板。

python

python 官方标准模板 包括 python3 的基础镜像。

版本分布

版本分布 bullseye/buster/alpine:

  • slim 最小安装,不包含 gdb 调试脚本加载。

  • 非 slim,包含 gdb 调试脚本(建议使用)。

  • alpine 非 glibc 的最小镜像模板。

参考

mysql

这里简单介绍 docker 启动配置 mysql 服务方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 安装时映射到容器中的3306即可
#!/bin/bash

docker run \
-p 3365:3306 \
--name mysql5.7.21 \
--privileged=true \
# no #不重启(不带restart参数时,默认不重启)
# on-failure #退出状态非0时重启
# always #始终重启
--restart=always \ #在宿主机重启后或者Docker服务重启后自动启动容器,
-v /opt/mysql5.7.21/mysql:/etc/mysql \
-v /opt/mysql5.7.21/logs:/logs \
-v /opt/mysql5.7.21/data:/var/lib/mysql \
-v /etc/localtime:/etc/localtime \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7.21 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_general_ci #设置编码为utf8mb4

docker-compose

docker-compose 是一个多容器编排工具,常用于开发配置.

GPU support

docker-compose gpu support.

1
2
3
4
5
6
7
8
9
10
11
version: '3'
services:
test:
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

healthcheck

CMD 和 CMD-SHELL 是 Docker Compose 文件中用于定义容器健康检查的两种不同的命令类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: "3.8"

services:
minio:
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://minio:9000/minio/health/live"]
interval: 10s
timeout: 10s
retries: 3

tritonserver:
depends_on:
minio:
condition: service_healthy
create_models_buckets:
condition: service_completed_successfully
healthcheck:
test: ["CMD-SHELL", "curl -f http://tritonserver:8000/v2/health/ready"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
shm_size: 256M
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
  • CMD 命令类型用于执行指定的命令,它将命令及其参数作为一个数组传递。在给定的示例中,CMD 命令执行的是 curl -f http://minio:9000/minio/health/live 命令,用于检查 MinIO 服务的健康状态。

  • CMD-SHELL 命令类型用于执行指定的命令字符串。在给定的示例中,CMD-SHELL 命令执行的是 curl -f http://tritonserver:8000/v2/health/ready 命令,同样用于检查 Triton Server 服务的健康状态。

因此,CMD 和 CMD-SHELL 的区别在于命令的传递方式,CMD 使用数组形式传递命令及其参数,而 CMD-SHELL 使用字符串形式传递命令。

restart

restart 策略用于控制容器在退出后的行为。

  • on-failure 是指在容器退出时,当其退出状态码不为 0(即失败)时,自动重启该容器。具体来说,它会重启那些在容器退出时返回非 0 状态码的容器。如果容器在退出时返回状态码 0,则不会自动重启该容器。

  • no:容器退出时不重启容器;

  • always:容器退出时总是重启容器;

  • unless-stopped:容器退出时重启容器,除非容器被手动停止。

volume

1
2
3
4
5
6
7
8
version: '3'
services:
your-service:
volumes:
- type: volume
source: cppblueprint-src
target: /workspace
consistency: cached

config

docker-compose config 命令用于验证并查看最终的 docker-compose 文件。当有多个 docker-compose 文件时,可以使用 -f 参数来指定多个文件。这些文件将按照它们在命令行中出现的顺序进行合并。如果在多个文件中定义了相同的服务,那么后面的定义将覆盖前面的定义。

合并规则如下:

  • 对于字典类型的字段(例如 environment,labels),它们将被深度合并。如果同一个键在多个文件中定义,那么后面的值将覆盖前面的值。

  • 对于列表类型的字段(例如 ports,volumes),它们将被扩展。也就是说,所有文件中的值都将被包含在最终的列表中。

  • 对于其他类型的字段,例如 image,command,如果在多个文件中定义,那么后面的值将覆盖前面的值。

例如,如果有两个 docker-compose 文件,docker-compose.yml 和 docker-compose.override.yml,可以使用以下命令来查看最终的配置:

1
docker-compose -f docker-compose.yml -f docker-compose.override.yml config

docker api

Docker Engine 有一个 RESTful API。可以在这里找到完整的 API 文档 https://docs.Docker.com/Engine/API/v1.40 / 这意味着由于多克引擎有一个 RESTful HTTP/S API,我们可以连接到一个远程多克引擎,甚至可以使用 curl 或 wget 命令远程运行命令,就像我们可以对任何其他基于 HTTP/S 的 API 所做的那样。

python client

python 通过包 docker 提供 api 客户端操作工具,pip install docker

1
2
3
import docker
client = docker.from_env()
print(client.containers.run("alpine", ["echo", "hello", "world"]))

links:

docker swarm

Docker Swarm 是 Docker 的原生集群和编排工具,用于创建和管理 Docker 节点集群和在集群中部署服务。

links:

swarm 管理

Step 1, 初始化 Swarm 集群:首先,需要在一个节点上初始化 Swarm 集群。这个节点将成为集群的管理节点。使用以下命令初始化 Swarm:

1
2
# 其中<MANAGER-IP>是管理节点的IP地址。
docker swarm init --advertise-addr <MANAGER-IP>
1
2
3
4
5
6
7
8
docker swarm init --advertise-addr 10.16.31.3
Swarm initialized: current node (vw5q29giyjap87yfwjbd9t0hh) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-1la2dx1j0o12hk8mq0an415s637b71ujx9hfqm90c5vmi61d3v-3fcfcedql7voq0skyrj1wxson 10.16.31.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Step 2, 添加工作节点:初始化 Swarm 后,会得到一个命令和 token,其他节点可以使用这个命令和 token 加入 Swarm 集群。命令如下:

1
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

Step 3, 从 Swarm 集群中退出

1
2
3
4
# 在工作节点上执行:如果想让一个工作节点从Swarm集群中退出,可以在该节点上运行以下命令
docker swarm leave
# 在管理节点上执行:如果想让一个管理节点从Swarm集群中退出,需要添加--force选项,命令如下
docker swarm leave --force

[!CAUTION]
请注意,如果 Swarm 集群只有一个管理节点,不应该让它退出,因为这将导致失去管理 Swarm 集群的能力。

links:

节点管理

Docker Swarm 中的节点管理主要涉及到添加节点、查看节点状态、更新节点和删除节点等操作。

添加节点:在初始化 Swarm 集群后,会得到一个命令和 token,其他节点可以使用这个命令和 token 加入 Swarm 集群。命令如下:

1
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

节点状态:可以使用以下命令查看 Swarm 集群中所有节点的状态:

1
docker node ls

更新节点:可以使用以下命令更新 Swarm 集群中的节点:

1
2
docker node update <NODE-ID>
docker node update <NODE-ID> --availiabiblity drain/active/pause

删除节点:可以使用以下命令从 Swarm 集群中删除节点:

1
2
3
4
# 首相设置节点不再被调度
docker node update <NODE-ID> --availiabiblity drain
# 然后删除节点
docker node rm <NODE-ID>

label 管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 给节点添加label
docker node update --label-add <key>=<value> <NODE-ID>
# 根据label部署服务
docker service create --constraint 'node.labels.<key>==<value>' <IMAGE>
# 使用docker-compose
cat <<EOF | docker-compose up -f -
version: '3'
services:
web:
image: <IMAGE>
deploy:
placement:
constraints:
- node.labels.<key>==<value>
EOF

links:

服务管理

docker stack 和 docker service 都是 Docker Swarm 模式下的命令,它们用于管理和操作服务,但是它们的使用场景和功能有所不同。

  • docker stack:这个命令主要用于管理和操作整个应用栈。一个应用栈可以包含多个服务,这些服务可以通过同一个 docker-compose.yml 文件定义。可以使用 docker stack deploy 命令来部署整个应用栈,或者使用 docker stack rm 来移除整个应用栈。

  • docker service:这个命令主要用于管理和操作单个服务。可以使用 docker service create 命令来创建一个新的服务,或者使用 docker service update 来更新一个现有的服务。此外,还可以使用 docker service scale 来调整服务的副本数量。

总的来说,docker stack 命令提供了一个更高级别的抽象,它允许一次性管理和操作整个应用栈,而 docker service 命令则提供了更细粒度的控制,它允许管理和操作单个服务。

1
2
3
4
5
6
7
8
# 部署服务
docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml myapp_stack
# 查看服务
docker service ls
# 更新服务
docker service update <SERVICE-ID>
# 删除服务
docker service rm <SERVICE-ID>

GPU

将 docker runtime 默认位置为 nvidia.

links:

docker-compose

[!CAUTION]
docker-compose 中 depends_on,restart,deploy.resources.reservations 等资源不可用,需要单独配置.

UI

Docker Swarm 的管理和部署可以通过各种 UI 工具进行,以下是一些常见的选项:

  1. Portainer:Portainer 是一个轻量级的管理 UI,可以用来管理 Docker、Swarm、Kubernetes 等。它提供了一个直观的界面来管理 Docker Swarm 集群,包括服务、容器、网络和卷。

  2. SwarmPit:SwarmPit 提供了一个简单而强大的界面来管理 Docker Swarm 集群。它支持服务的自动扩展、容器日志、服务发现等功能。

  3. Rancher:Rancher 是一个开源的容器管理平台,它支持 Docker Swarm、Kubernetes 等。Rancher 提供了一个全面的界面来管理和部署服务。

以上工具都可以帮助更方便地管理和部署 Docker Swarm 集群。可以根据需求选择合适的工具。

swarmpit

SwarmPit:Lightweight mobile-friendly Docker Swarm management UI

1
2
3
4
docker run -it --rm   \
--name swarmpit-installer \
--volume /var/run/docker.sock:/var/run/docker.sock \
swarmpit/install:1.9

portainer

1
2
3
4
5
6
7
8
docker volume create portainer_data
docker run -d \
-p 9000:9000 \
--name=portainer \
--restart=unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce

links:

swarm mesh

swarm 默认使用的是 IPVS 提供的四层模型请求负载均衡消费模式。即和默认非 swarm 模式下单独 docker 使用同一一个网络模型.

当有其它需求实时,推荐使用 traefik 等开源方案.

links:

docker proxy

在容器环境中配置代理环境变量,配置示例

  • HTTP_PROXY

  • http_proxy

  • HTTPS_PROXY

  • https_proxy

  • NO_PROXY

  • no_proxy

  • ALL_PROXY

  • all_proxy

links: