2. Docker 使用
主要讲解 docker-compose.yaml 如何书写, Docker Swarm 集群管理方式 (未写完), Dockerfile 的书写规范和注意点
1. Docker 测试镜像 (Hello World)
1.1 Hello World 镜像
1
2
runoob@runoob:~$ docker run ubuntu:15.10 /bin/echo "Hello world"
Hello world
各个参数解析:
- docker: Docker 的二进制执行文件
- run: 与前面的 docker 组合
- ubuntu:15.10 指定要运行的镜像, 首先从本地主机上查找镜像是否存在; 若不存在, 则从镜像仓库 Docker Hub 下载公共镜像
- /bin/echo “Hello world”: 在启动的容器里执行的命令
以上命令可解释为: Docker 以 ubuntu15.10 镜像创建一个新容器, 在容器里执行 bin/echo “Hello world”, 输出结果
1.2. 运行交互式容器
通过 docker 的参数 -i -t, 让容器实现“对话”的能力:
1
2
runoob@runoob:~$ docker run -i -t ubuntu:15.10 /bin/bash
root@0123ce188bd8:/#
各个参数解析:
- -t: 在新容器内指定一个伪终端 or 终端
- -i: 允许对容器内的标准输入 (STDIN) 进行交互
在容器中运行命令 cat /proc/version 和 ls 分别查看当前系统的版本信息和当前目录下的文件列表
1
2
3
4
5
root@0123ce188bd8:/# cat /proc/version
Linux version 4.4.0-151-generic (buildd@lgw01-amd64-043) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10) ) #178-Ubuntu SMP Tue Jun 11 08:30:22 UTC 2019
root@0123ce188bd8:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@0123ce188bd8:/#
通过运行 exit 命令 or 使用 CTRL+D 退出容器
1
2
3
root@0123ce188bd8:/# exit
exit
root@runoob:~#
1.3. 启动容器 (后台模式)
使用以下命令创建以 进程方式 运行的容器:
1
2
runoob@runoob:~$ docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63
在输出中, 我们没有看到期望的 “hello world”, 而是一串长字符
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63: 容器 ID, 对每个容器来说唯一; 可通过容器 ID 来查看对应的容器发送了什么
可以通过 docker ps 来查看正在运行的容器:
1
2
3
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ...
5917eac21c36 ubuntu:15.10 "/bin/sh -c 'while t…" ...
输出详情介绍:
-
COMMAND: 启动容器时运行的命令 -
CREATED: 容器的创建时间 -
STATUS: 容器状态-
created (已创建)
-
restarting (重启中)
-
running 或 Up (运行中)
-
removing (迁移中) (如何促使迁移)
-
paused (暂停) (如何促使暂停)
-
exited (停止)
-
dead (死亡) (如何促使死亡)
-
-
PORTS: 容器的端口信息, 使用的连接类型 (TCP\UDP) -
NAMES: 自动分配的容器名称
在宿主主机内使用 docker logs 命令, 可查看容器内的标准输出.
1.4. 停止容器
1
docker stop <Container_name>
2. Docker 容器的使用
2.1. Docker 客户端
- 是与 Docker 守护进程 (Docker Daemon) 交互的命令行工具
-
非常简单, 可以直接输入 docker 命令来查看到 Docker 客户端所有命令选项
- 可通过命令
docker <command>--help更深入了解指定的 Docker 命令使用方法
常用 Docker 客户端命令:
| 命令 | 功能 | 示例 |
|---|---|---|
docker run |
启动一个新的容器并运行命令 | docker run -d ubuntu |
docker ps |
列出当前正在运行的容器 | docker ps |
docker ps -a |
列出所有容器 (包括已停止的容器) | docker ps -a |
docker build |
使用 Dockerfile 构建镜像 | docker build -t my-image . |
docker images |
列出本地存储的所有镜像 | docker images |
docker pull |
从 Docker 仓库拉取镜像 | docker pull ubuntu |
docker push |
将镜像推送到 Docker 仓库 | docker push my-image |
docker exec |
在运行的容器中执行命令 | docker exec -it container_name bash |
docker stop |
停止一个或多个容器 | docker stop container_name |
docker start |
启动已停止的容器 | docker start container_name |
docker restart |
重启一个容器 | docker restart container_name |
docker rm |
删除一个或多个容器 | docker rm container_name |
docker rmi |
删除一个或多个镜像 | docker rmi my-image |
docker logs |
查看容器的日志 | docker logs container_name |
docker inspect |
获取容器或镜像的详细信息 | docker inspect container_name |
docker exec -it |
进入容器的交互式终端 | docker exec -it container_name /bin/bash |
docker network ls |
列出所有 Docker 网络 | docker network ls |
docker volume ls |
列出所有 Docker 卷 | docker volume ls |
docker compose up |
启动多容器应用 (从 docker-compose.yaml 文件) |
docker-compose up |
docker compose down |
停止并删除由 docker-compose 启动的容器、网络等 |
docker-compose down |
docker info |
显示 Docker 系统的详细信息 | docker info |
docker version |
显示 Docker 客户端和守护进程的版本信息 | docker version |
docker stats |
显示容器的实时资源使用情况 | docker stats |
docker login |
登录 Docker 仓库 | docker login |
docker logout |
登出 Docker 仓库 | docker logout |
常用选项说明:
-d: 后台运行容器, 例如docker run -d ubuntu-it: 以交互式终端运行容器, 例如docker exec -it container_name bash-t: 为镜像指定标签, 例如docker build -t my-image
2.2. 容器使用
1. 获取镜像
1
docker pull <image_name>
2. 启动容器
1
docker run -it ubuntu /bin/bash
3. 启动已停止运行的容器
4. 后台运行
1
docker run -itd --name ubuntu-test ubuntu /bin/bash
5. 停止容器运行
[空]
6. 重启容器
[空]
7. 进入后台运行的容器
在使用 -d 参数时启动容器时, 容器运行在后台, 通过以下命令进入:
docker attach: 允许你与容器的标准输如 (stdin), 输出 (stdout), 标准错误 (stderr) 进行交互; 退出会导致容器停止运行.docker exec: 推荐使用 docker exec 命令 - 只退出容器终端
docker exec 实例:
1
docker exec -it 243c32535da7 /bin/bash
8. 导入, 导出容器
导出容器 - docker export
实例: docker export 1e560fca3906 > ubuntu.tar
[!note]
- 此时导出的 ubuntu.tar 只是容器镜像, 其中没有镜像元数据, 运行环境;
- 可使用
tar -xvf ubuntu.tar -C ubuntu_container来手动解压 (镜像 tar 不行)
导入容器 - docker import
实例:
- 将快照文件
ubuntu.tar导入镜像test/ubuntu:v1:$ cat docker/ubuntu.tar | docker import - test/ubuntu:v1 - 指定 URL or 某个目录导入:
docker import http://example.com/exampleimage.tgz example/imagerepo
9. 删除容器
[空]
10. 运行一个 Web 应用
尝试使用 docker 构建一个 web 应用程序; 在docker容器中运行一个 Python Flask 应用来运行一个web应用
1
2
runoob@runoob:~# docker pull training/webapp
runoob@runoob:~# docker run -d -P training/webapp python app.py
参数说明:
-d: 让容器在后台运行-P: 将容器内部使用的网络端口随机映射到我们使用的主机上
11. 查看 WEB 应用容器
使用 docker ps 来查看正在运行的容器:
1
2
3
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS
d3d5e39ed9d3 training/webapp "python app.py" ... 0.0.0.0:32769->5000/tcp
Docker 开放了 5000 端口 (默认 Python Flask 端口) 映射到主机端口 32769 上
这时我们可以通过浏览器访问WEB应用
可通过 -p 参数来设置不一样的端口:
1
2
3
4
5
runoob@runoob:~$ docker run -d -p 5000:5000 training/webapp python app.py
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE PORTS NAMES
bf08b7f2cd89 training/webapp ... 0.0.0.0:5000->5000/tcp wizardly_chandrasekhar
d3d5e39ed9d3 training/webapp ... 0.0.0.0:32769->5000/tcp xenodochial_hoov
容器内部的 5000 端口映射到宿主机的 5000 端口上
12. 网络端口的快捷方式
docker 还提供了另一个快捷方式 docker port, 使用 docker port 可以查看指定 (ID 或者名字) 容器的某个确定端口映射到宿主机的端口号
上面创建的 web 应用容器 ID 为 bf08b7f2cd89 名字为 wizardly_chandrasekhar.
1
2
3
4
runoob@runoob:~$ docker port bf08b7f2cd89
5000/tcp -> 0.0.0.0:5000
runoob@runoob:~$ docker port wizardly_chandrasekhar
5000/tcp -> 0.0.0.0:5000
13. 查看 WEB 应用程序日志
docker logs <container_ID or container_name> 可查看容器内部的标准输出
1
2
3
4
runoob@runoob:~$ docker logs -f bf08b7f2cd89
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.239.1 - - [09/May/2016 16:30:37] "GET / HTTP/1.1" 200 -
192.168.239.1 - - [09/May/2016 16:30:37] "GET /favicon.ico HTTP/1.1" 404 -
-f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出
14. 查看 WEB 应用程序容器的进程
命令: docker top
1
2
3
runoob@runoob:~$ docker top wizardly_chandrasekhar
UID PID PPID ... TIME CMD
root 23245 23228 ... 00:00:00 python app.py
15. 检查 WEB 应用程序
命令: docker inspect <container_name>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
runoob@runoob:~$ docker inspect wizardly_chandrasekhar
[
{
"Id": "bf08b7f2cd897b5964943134aa6d373e355c286db9b9885b1f60b6e8f82b2b85",
"Created": "2018-09-17T01:41:26.174228707Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 23245,
"ExitCode": 0,
"Error": "",
"StartedAt": "2018-09-17T01:41:26.494185806Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
......
16. 移除 WEB 应用容器
删除容器时, 容器必须是停止状态, 否则报错如下:
1
2
runoob@runoob:~$ docker rm wizardly_chandrasekhar
Error response from daemon: You cannot remove a running container bf08b7f2cd897b5964943134aa6d373e355c286db9b9885b1f60b6e8f82b2b85. Stop the container before attempting removal or force remove
2.3. Docker 镜像使用
任务:
- 管理 & 使用本地镜像
- 创建镜像
1. 列出镜像列表
命令: docker images or docker image ls
输出如下:
1
2
3
4
5
6
7
runoob@runoob:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
hello-world latest 690ed74de00f 6 months ago 960 B
training/webapp latest 6fae60ef3446 11 months ago 348.8 MB
字段说明:
REPOSITORY: 表示镜像的仓库源TAG: 镜像的标签IMAGE ID: 镜像IDCREATED: 镜像创建时间SIZE: 镜像大小
同一仓库源可有多个 TAG, 代表这个仓库源的不同个版本; 如 ubuntu 仓库源里: 有 15.10, 14.04 等多个不同的版本; 使用 REPOSITORY:TAG 来定义不同的镜像. 若要使用版本为 14.04 的 ubuntu 系统镜像来运行容器时, 命令如下:
1
2
runoob@runoob:~$ docker run -t -i ubuntu:14.04 /bin/bash
root@39e968165990:/#
2. 获取 or 拖取一个新镜像
命令: docker pull <image_name>
3. 查找镜像
NAME: 镜像仓库源的名称DESCRIPTION: 镜像的描述OFFICIAL: 是否 docker 官方发布stars: 类似 Github 中 starAUTOMATED: 自动构建
4. 删除镜像
命令: docker rmi <image_name>
5. 创建镜像
通过以下两种方式对镜像进行更改:
-
更新镜像: 从已经创建的容器中更新镜像, 并且提交这个镜像
命令:
docker commit -m="<描述信息>" -a="<author>" <container_name> <new_image_name>:<version> -
构建镜像: 使用 Dockerfile 指令来创建一个新的镜像
- 前提: 可用的
Dockerfile - 命令:
docker build -t <image_name>:<version> .(在Dockerfile所在目录)
- 前提: 可用的
6. 设置镜像标签
命令: docker tag <标签内容> <image_name>:<version>
3. Docker 容器连接
容器中运行一些网络应用, 要让外部也可以访问这些应用, 可以通过 -P 或 -p 参数来指定端口映射
3.1. 网络端口映射
[!Caution]
只有网络模式为
bridge时需要网络端口映射
[!Note]
- 网络模式
bridge: 容器会有自己的虚拟网络接口 $\to$ 需要使用网络端口映射- 网络模式
none: 容器没有网络连接, 完全隔离与宿主机网络- 网络模式
host: 容器的网络栈与宿主机共享, 容器直接能使用宿主机 IP 地址, 端口 $\to$ 不需要使用网络端口映射
创建一个 python 应用的容器:
1
2
runoob@runoob:~$ docker run -d -P training/webapp python app.py
fce072cc88cee71b1cdceb57c2821d054a4a59f67da6b416fceb5593f059fc6d
可指定容器绑定的网络地址: 如绑定 127.0.0.1
我们使用 -P 绑定端口号, 使用 docker ps 可看到容器端口 5000 绑定主机端口 32768
1
2
3
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
fce072cc88ce training/webapp "python app.py" ... 0.0.0.0:32768->5000/tcp grave_hopper
可使用 -p 标识来指定容器端口绑定到主机端口
两种方式的区别:
-P: 容器内部端口随机映射到主机的端口-p: 容器内部端口绑定到指定的主机端口
1
2
3
4
5
6
runoob@runoob:~$ docker run -d -p 5000:5000 training/webapp python app.py
33e4523d30aaf0258915c368e66e03b49535de0ef20317d3f639d40222ba6bc0
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
33e4523d30aa training/webapp "python app.py" ... 0.0.0.0:5000->5000/tcp berserk_bartik
fce072cc88ce training/webapp "python app.py" ... 0.0.0.0:32768->5000/tcp grave_hopper
可指定容器绑定的网络地址: 如绑定 127.0.0.1
1
2
3
4
5
6
7
runoob@runoob:~$ docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
95c6ceef88ca3e71eaf303c2833fd6701d8d1b2572b5613b5a932dfdfe8a857c
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
95c6ceef88ca training/webapp "python app.py" ... 5000/tcp, 127.0.0.1:5001->5000/tcp adoring_stonebraker
33e4523d30aa training/webapp "python app.py" ... 0.0.0.0:5000->5000/tcp berserk_bartik
fce072cc88ce training/webapp "python app.py" ... 0.0.0.0:32768->5000/tcp grave_hopper
这样就可通过访问 127.0.0.1:5001 来访问容器的 5000 端口
若要绑定 UDP 端口, 可以在端口后面加上 /udp
1
2
3
4
5
6
7
8
runoob@runoob:~$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
6779686f06f6204579c1d655dd8b2b31e8e809b245a97b2d3a8e35abe9dcd22a
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
6779686f06f6 training/webapp "python app.py" ... 5000/tcp, 127.0.0.1:5000->5000/udp drunk_visvesvaraya
95c6ceef88ca training/webapp "python app.py" ... 5000/tcp, 127.0.0.1:5001->5000/tcp adoring_stonebraker
33e4523d30aa training/webapp "python app.py" ... 0.0.0.0:5000->5000/tcp berserk_bartik
fce072cc88ce training/webapp "python app.py" ... 0.0.0.0:32768->5000/tcp grave_hopper
docker port 命令可让我们快捷查看端口的绑定情况
1
2
runoob@runoob:~$ docker port adoring_stonebraker 5000
127.0.0.1:5001
3.2. Docker 容器互联
互联方法:
- 网络端口映射
- 连接系统 允许将多个容器连接在一起, 共享连接信息; docker 连接会创建父子关系: 父容器可看到子容器的信息
3.2.1. 容器命名
创建容器的时候, docker 会自动对它进行命名. 但可以使用 --name 标识来命名容器, 如:
1
2
runoob@runoob:~$ docker run -d -P --name runoob training/webapp python app.py
43780a6eabaaf14e590b6e849235c75f3012995403f97749775e38436db9a441
可使用 docker ps 命令来查看容器名称:
1
2
3
runoob@runoob:~$ docker ps -l
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
43780a6eabaa training/webapp "python app.py" ... 0.0.0.0:32769->5000/tcp runoob
3.2.2. 新建网络
创建一个新的 Docker 网络
1
docker network create -d bridge test-net
参数说明:
-d: 参数指定 Docker 网络类型, 有 bridge、overlay
- overlay 网络类型用于 Swarm mode; (什么是 overly 网络类型?)
3.2.3 连接容器
运行一个容器并连接到 test-net 网络:
1
docker run -itd --name test1 --network test-net ubuntu /bin/bash
打开新的终端, 再运行一个容器并加入到 test-net 网络:
1
docker run -itd --name test2 --network test-net ubuntu /bin/bash
通过 ping 来证明 test1 容器和 test2 容器建立了互联关系: 若 test1, test2 容器内中无 ping 命令, 则在容器内执行以下命令安装 ping
1
2
apt-get update
apt install iputils-ping
[!Note]
多容器之前相互连接, 使用 Docker Compose
3.2.4. 配置 DNS
可在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置容器 DNS:
1
2
3
4
5
6
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}
设置后, 启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8; 配置完, 需要重启 docker 才能生效
查看容器 DNS 是否生效可以使用以下命令:
1
docker run -it --rm ubuntu cat etc/resolv.conf
若只想在指定的容器设置 DNS, 运行以下命令:
1
docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
参数说明:
-
--rm: 容器退出时自动清理容器内部的文件系统 -
-h HOSTNAMEor--hostname=HOSTNAME: 设定容器主机名, 会被写到容器内的 /etc/hostname & /etc/hosts 中 -
--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中, 让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名 -
--dns-search=DOMAIN: 设定容器的搜索域, 当设定搜索域为 .example.com 时, 在搜索一个名为 host 的主机时, DNS 不仅搜索 host, 还会搜索 host.example.com (这儿没理解)
[!Caution]
若容器启动时没指定
--dns和--dns-search, Docker 默认使用宿主机的 /etc/resolv.conf 配置容器 DNS
4. Docker 仓库管理
仓库 (Repository) 是集中存放镜像的地方. 以下介绍 Docker Hub. 当然不止 docker hub, 只是远程的服务商不一样, 操作一样.
4.1. Docker Hub
目前 Docker 官方维护了一个公共仓库 Docker Hub. 大部分需求都可通过在 Docker Hub 中直接下载镜像来实现
4.2. 登录和退出
1. 登录
1
docker login
2. 退出
1
docker logout
3. 拉取镜像
通过 docker search命令来查找官方仓库中的镜像
以 ubuntu 为关键词进行搜索:
1
docker search ubuntu
使用 docker pull 将官方 ubuntu 镜像下载到本地:
1
docker pull ubuntu
4.3. 推送镜像
用户登录后, 可通过 docker push 命令将自己的镜像推送到 Docker Hub
以下命令中的 username 请替换为你的 Docker 账号用户名
1
2
3
4
5
6
7
8
9
10
11
$ docker tag ubuntu:18.04 username/ubuntu:18.04
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED ...
ubuntu 18.04 275d79972a86 6 days ago ...
username/ubuntu 18.04 275d79972a86 6 days ago ...
$ docker push username/ubuntu:18.04
$ docker search username/ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
username/ubuntu
5. Docker Dockerfile
5.1. 使用 Dockerfile 定制镜像
仅讲解如何运行 Dockerfile 文件来定制一个镜像; Dockerfile 文件内指令详解将在下一节中介绍
1. 下面以定制一个 nginx 镜像 (构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)
空目录下, 新建一个名为 Dockerfile 文件, 并在文件内添加以下内容:
1
2
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
2. FROM 和 RUN 指令的作用
FROM: 定制的镜像是基于 FROM 的镜像, 这里的 nginx 就是定制需要的基础镜像
RUN: 用于执行后面跟着的命令行命令. 有以下俩种格式:
shell 格式:
1
RUN <命令行命令>
exec 格式:
1
2
3
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
[!Caution]
注意!!! Dockerfile 的指令每执行一次都会在 docker 上新建一层. 所以过多无意义的层, 会造成镜像膨胀过大. 例如:
1 2 3 4 FROM centos RUN **yum** -y **install** **wget** RUN **wget** -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN **tar** -xvf redis.tar.gz以上执行会创建 3 层镜像. 可简化格式:
1 2 3 4 FROM centos RUN **yum** -y **install** **wget** \ **&&** **wget** -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ **&&** **tar** -xvf redis.tar.gz如上, 以
&&符号连接命令, 这样执行后, 只会创建 1 层镜像
5.2. 开始构建镜像
在 Dockerfile 文件的目录下, 执行构建动作. 以下示例, 通过 Dockerfile 构建 nginx:v3
1
docker build -t nginx:v3 .
5.3. 指令详解
| Dockerfile 指令 | 说明 |
|---|---|
| FROM | 指定基础镜像, 用于后续的指令构建 |
| MAINTAINER | 指定Dockerfile的作者/维护者 (已弃用, 推荐使用LABEL指令) |
| LABEL | 添加镜像的元数据, 使用键值对的形式 |
| RUN | 在构建过程中在镜像中执行命令 |
| CMD | 指定容器创建时的默认命令 (可以被覆盖) |
| ENTRYPOINT | 设置容器创建时的主要命令 (不可被覆盖) |
| EXPOSE | 声明容器运行时监听的特定网络端口. |
| ENV | 在容器内部设置环境变量 |
| ADD | 将文件、目录或远程URL复制到镜像中 |
| COPY | 将文件或目录复制到镜像中 |
| VOLUME | 为容器创建挂载点或声明卷 |
| WORKDIR | 设置后续指令的工作目录 |
| USER | 指定后续指令的用户上下文 |
| ARG | 定义在构建过程中传递给构建器的变量, 可使用 “docker build” 命令设置 |
| ONBUILD | 当该镜像被用作另一个构建过程的基础时, 添加触发器 |
| STOPSIGNAL | 设置发送给容器以退出的系统调用信号 |
| HEALTHCHECK | 定义周期性检查容器健康状态的命令 |
| SHELL | 覆盖Docker中默认的shell, 用于RUN、CMD和ENTRYPOINT指令 |
COPY
功能: 复制, 从指定目录中复制 文件 or 目录 到容器里指定路径
格式:
1
2
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=<user>:<group>]: 可选参数, 可改变复制到容器内文件的拥有者和属组
<源路径>: 源文件 or 源目录; 可是通配符表达式, 其通配符规则要满足 Go 的 filepath.Match 规则. 如: (了解 Go 的 filepath.Match 规则)
1
2
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>: 容器内的指定路径, 可自动创建
ADD
ADD 指令和 COPY 格式类型, 功能类型; 推荐用 `COPY`; 不同之处如下:
- ADD 的优点: 源文件为
tar格式 (压缩格式: gzip, bzip2, xz), 自动复制 & 解压到 <目标路径>目标路径> - ADD 的缺点: 不解压时, 无法复制 tar 压缩文件. 会令镜像构建缓存失效, 可能会导致镜像构建比较缓慢.
CMD
类似于 RUN 指令, 用于运行程序, 不同点:
-
CMD: 在docker run时运行. -
RUN: 在docker build时运行
作用: 为启动的容器指定默认运行程序; 程序运行结束, 容器也就结束. CMD 指令指定的程序可被 docker run 命令行参数中指定运行的程序覆盖
[!Caution]
若 Dockerfile 中存在多个 CMD 指令, 仅最后一条生效
格式:
1
2
3
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式; 第一种格式在运行的过程中会转换成第二种格式; 且默认可执行文件是 sh.
ENTRYPOINT (entrypoint, 入口点)
类似 CMD 指令, 但不会被 docker run 的命令行参数指定的指令所覆盖; 且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序.
能被 `docker run` 覆盖的情况: 使用了 ``--entrypoint` 选项, 将覆盖 ENTRYPOINT 指令指定程序
优点: 执行 docker run 时可指定 ENTRYPOINT 运行所需参数
[!Caution]
若 Dockerfile 中存在多个 ENTRYPOINT 指令, 仅最后一个生效
格式:
1
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可搭配 CMD 命令使用: 一般变参才用 CMD; 这里的 CMD 是在给 ENTRYPOINT 传参
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
1
2
3
4
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
- 不传参运行
1
$ docker run nginx:test
容器内默认运行以下命令, 启动主进程
1
nginx -c /etc/nginx/nginx.conf
- 传参运行
1
$ docker run nginx:test -c /etc/nginx/new.conf
容器内默认运行以下命令, 启动主进程
1
nginx -c /etc/nginx/new.conf
ENV
设置 Dockerfile 环境变量; 类似于 C 语言中 #define:
格式:
1
2
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0, 后续指令中可通过 $NODE_VERSION 引用:
1
2
3
4
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
ARG (Argument, 参数)
构建参数, 与 ENV 作用一致.
ARG 与 ENV 不同点:
| 特性 | ARG |
ENV |
|---|---|---|
| 作用范围 | 仅在 构建阶段 可用 | 在 构建阶段 和 运行时阶段 均可用 |
| 生命周期 | 构建时有效, 容器运行时不可访问 | 构建时有效, 容器运行时有效 |
| 使用场景 | 构建时的参数传递; 如版本号, 构建配置等 | 容器运行时的环境变量; 如路径, 配置等 |
| 是否可覆盖 | 可以在 docker build 时使用 --build-arg 覆盖 |
可以在容器运行时使用 -e 覆盖; 如: docker run -e MY_VAR=new_value my_image |
| 是否传递给容器 | 不传递给容器, 容器无法访问 | 会传递给容器, 容器可以访问 |
格式:
1
ARG <参数名>[=<默认值>]
VOLUME (volumes, 数据卷)
定义匿名数据卷. 在启动容器时忘记挂载数据卷, 会自动挂载到匿名卷.
作用:
- 避免重要的数据因容器重启丢失
- 避免容器不断变大
格式:
1
2
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候, 我们可以通过 -v 参数修改挂载点
EXPOSE (expose; 暴露, 端口)
仅仅声明端口
作用:
- 帮助镜像使用者理解镜像服务守护端口, 以方便配置映射
- 在运行时使用随机端口映射时, 也就是
docker run -P时, 会自动随机映射 EXPOSE 的端口
格式:
1
EXPOSE <端口1> [<端口2>...]
WORKDIR (workdir, 工作目录)
指定工作目录; 指定的工作目录在构建镜像的每一层中都存在. 以后各层的当前目录就被改为指定的目录. 如该目录不存在, WORKDIR 会帮你建立目录
docker build 构建镜像过程中的, 每一个 RUN 命令都是新建的一层. 只有通过 WORKDIR 创建的目录才会一直存在. (不太理解)
格式:
1
WORKDIR <工作目录路径>
USER (user; 用户 or 用户组)
指定执行后续命令的用户和用户组; 这边只是切换后续命令执行的用户 (用户和用户组必须提前已经存在)
格式:
1
USER <用户名>[:<用户组>]
HEALTHCHECK (healthcheck; 容器健康检查)
作用
- 监控容器内运行的应用是否正常, 自动化处理不可用的容器状态
- 若容器未通过健康检查, Docker 会标记该容器为“不健康”, 并根据
--restart策略重启容器 (若设置了重启策略)
使用场景
- 健康检查通常用于需要长期运行的服务, 如 Web 服务器、数据库等
HEALTHCHECK 语法
1
2
HEALTHCHECK [OPTIONS] CMD <command>
HEALTHCHECK NONE: 若基础镜像有健康检查指令, 使用这行可以屏蔽掉其健康检查指令
CMD: 指定健康检查命令, Docker 会在容器中运行该命令来检查健康状态OPTIONS: 健康检查的可选参数; 用来配置健康检查的超时时间, 重试次数;
常见选项
--interval: 指定健康检查的间隔时间 (默认是30s)--timeout: 指定健康检查的超时时间 (默认是30s)--retries: 指定健康检查失败时的最大重试次数 (默认是3)--start-period: 在容器启动后的指定时间内, 健康检查失败不会被视为失败 (默认是0s)
健康检查的返回值
0: 表示健康检查通过, 容器正常1: 表示健康检查失败, 容器不健康2: 表示健康检查不可用, 容器无法执行健康检查命令 (如: 命令未找到)
例: 检查 HTTP 服务是否正常
若容器内运行一个 Web 服务, 可使用 curl 来检查端口 80 上的 HTTP 服务是否正常:
1
2
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl --silent --fail http://localhost:80 || exit 1
- 每隔 5 秒钟检查一次
- 若健康检查超时 3 秒 or HTTP 请求失败, 返回状态码
1
ONBUILD (onbuild, 其他镜像继承时执行)
在 父镜像 被用作基础镜像构建子镜像时设置预定义的行为.
典型使用场景:
- 模板镜像: 当你创建一个基础镜像时, 希望某些操作基于该镜像的构建中自动发生
- 通用构建逻辑: 在某些构建过程中, 通用的操作(如设置工作目录、复制源代码、安装依赖等)可通过
ONBUILD指令自动化
语法
1
ONBUILD <instruction>
<instruction>是推迟执行的指令: 如RUN,COPY,ADD
LABEL (label, 添加元数据)
给镜像添加一些元数据 (metadata), 键值对形式, 格式如下:
1
LABEL <key>=<value> <key>=<value> <key>=<value> ...
如:
1
2
3
4
5
LABEL version="1.0" \
description="This image contains a simple web app for demo purposes." \
author="John Doe" \
license="MIT" \
os="ubuntu:20.04"
为什么使用 LABEL?
- 管理和追踪
- 自动化工具集成: 自动化工具和 CI/CD 系统会从镜像标签中提取信息
- 镜像描述: 可帮助其他开发者 or 系统管理员快速了解镜像的用途, 版本, 作者等信息
- 符合规范: 公共镜像仓库 (如 Docker Hub) 要求在镜像中使用
LABEL来提供元数据, 符合这些要求有助于镜像易于发现和管理
查看镜像标签:
1
2
3
docker inspect --format '' <image_name>
# or
docker inspect <image_name> # 之后寻找 Config -> Labels
6. Docker Compose
6.1. Compose 简介
用于定义, 运行多容器 Docker 应用程序的工具. 可使用 yaml 文件配置应用程序需要的服务. 使用命令, 可以 yaml 文件配置中创建, 启动所有服务
Compose 使用步骤:
- Dockerfile 定义应用程序环境
- docker-compose.yaml 定义构成应用程序的服务, 这样它们可在隔离环境中一起运行
- 执行
docker-compose up命令启动, 运行整个应用程序
docker-compose.yaml 的配置案例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# yaml 配置实例
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
6.2. Compose 安装
Linux: 从 Github 上下载二进制包 (此方法为旧版), 新版的 docker compose, docker engine 默认一起提供.
下载 Docker Compose 的当前稳定版本:
1
sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
赋予执行权限:
1
sudo chmod +x /usr/local/bin/docker-compose
创建软链:
1
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
测试是否安装成功:
1
2
3
docker compose version
# 输出如下:
Docker Compose version v2.40.3
6.3. Compose 使用
6.3.1. 准备
创建一个测试目录:
1
2
mkdir composetest
cd composetest
创建 app.py:
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
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
redis: 应用程序网络上的 redis 容器主机名, 端口为 6379
创建 requirements.txt:
flask
redis
6.3.2. 创建 Dockerfile 文件
创建 Dockerfile:
1
2
3
4
5
6
7
8
9
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]
内容解释:
FROM python:3.7-alpine: 从 Python 3.7 映像构建镜像WORKDIR /code: 工作目录设置 /codeENV FLASK_APP app.py&ENV FLASK_RUN_HOST 0.0.0.0: 设置 flask 命令使用的环境变量RUN apk add --no-cache gcc musl-dev linux-headers: 安装 gcc; 以便如 MarkupSafe, SQLAlchemy 类 Python 包编译加速COPY requirements.txt requirements.txt&RUN pip install -r requirements.txt: 复制 requirements.txt; 安装 Python 依赖项COPY . .: 将 . 项目中的当前目录复制到 . 镜像中的工作目录CMD ["flask", "run"]: 容器提供默认执行命令: flask run
6.3.3. 创建 docker-compose.yaml
1
2
3
4
5
6
7
8
9
# yaml 配置
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
定义两个服务: web, redis
- web: 使用从 Dockerfile 当前目录中构建的镜像; 将容器和主机绑定到端口 5000; 此示例服务使用 Flask Web 服务器的默认端口 5000 .
- redis: 使用 Docker Hub 的公共 Redis 映像
6.3.4. 使用 Compose 命令构建
启动应用程序:
1
docker compose up
在后台执行该服务可加上 -d:
1
docker compose up -d
6.4. docker-compose.yaml 配置指令
version 指定本 yaml 依从的 compose 哪个版本制定的
build (这一段没看懂) 指定为构建镜像上下文路径:
-
webapp 服务: 指定从上下文路径 ./dir/Dockerfile 所构建的镜像
1 2 3 4
version: "3.7" services: webapp: build: ./dir
-
作为具有在上下文指定的路径的对象, 以及可选的 Dockerfile 和 args:
1 2 3 4 5 6 7 8 9 10 11 12 13
version: "3.7" services: webapp: build: context: ./dir dockerfile: Dockerfile-alternate args: buildno: 1 labels: - "com.example.description=Accounting webapp" - "com.example.department=Finance" - "com.example.label-with-empty-value" target: prod
- context: 上下文路径
- dockerfile: 指定构建镜像的 Dockerfile 文件名
- args: 添加构建参数, 这是只能在构建过程中访问的环境变量.
- labels: 设置构建镜像的标签.
- target: 多层构建, 可以指定构建哪一层.
cap_add, cap_drop (这段没看懂) 添加或删除容器拥有的宿主机的内核功能:
1
2
3
4
5
cap_add:
- ALL # 开启全部权限
cap_drop:
- SYS_PTRACE # 关闭 ptrace权限
cgroup_parent (cgroup 组是干什么的) 为容器指定父 cgroup 组, 意味着将继承该组的资源限制
1
cgroup_parent: m-executor-abcd
command 覆盖容器启动的默认命令.
1
command: ["bundle", "exec", "thin", "-p", "3000"]
container_name 指定自定义容器名称, 而不是生成的默认名称.
1
container_name: my-web-container
depends_on 设置依赖关系.
- docker-compose up : 以依赖性顺序启动服务. 以下示例中, 先启动 db & redis, 再启动 web
- docker-compose up SERVICE : 自动包含 SERVICE 的依赖项. 以下示例中, docker-compose up web 还将创建并启动 db 和 redis. (SERVICE 是什么? 为什么会要创建 db & redis, 能不创建就启动吗?)
-
docker-compose stop : 按依赖关系顺序停止服务. 以下示例中, 先停止 web, 再停止 db & redis
1 2 3 4 5 6 7 8 9 10 11
version: "3.7" services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres
[!Caution]
Web 服务不会等待 redis & db 完全启动之后再启动
deploy 指定与服务的部署和运行有关的配置. 只在 swarm 模式下才会有用. (deploy 的具体作用, swarm 模式详细资料)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: "3.7"
services:
redis:
image: redis:alpine
deploy:
mode: replicated
replicas: 6
endpoint_mode: dnsrr
labels:
description: "This redis service label"
resources:
limits:
cpus: '0.50'
memory: 50M
reservations:
cpus: '0.25'
memory: 20M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
可以选参数:
-
endpoint_mode: 访问集群服务的方式1 2 3 4
endpoint_mode: vip # Docker 集群服务一个对外的虚拟 ip. 所有的请求都会通过这个虚拟 ip 到达集群服务内部机器. endpoint_mode: dnsrr # DNS 轮询 (DNSRR). 所有请求会自动轮询获取到集群 ip 列表中的一个 ip 地址
-
labels: 在服务上设置标签. 可用容器的 labels (跟 deploy 同级的配置) 覆盖 deploy 下的 labels -
mode: 指定服务提供的模式 -
replicas: mode 为 replicated 时, 需用此参数配置具体运行节点数量 -
resources: 配置服务器资源使用限制; 例如上例子, 配置 redis 集群运行需要的 cpu 的百分比 和 内存占用. 避免占用资源过高出现异常. -
restart_policy: 配置退出容器时如何重新启动容器-
condition: 可选 none, on-failure, any (默认值: any). (这三个值代表的意义) -
delay: 设置重启延时 (默认值: 0). -
max_attempts: 尝试重新启动容器的次数; (默认值: 一直重试). -
window: 设置容器重启超时时间 (默认值: 0).
-
-
rollback_config: 配置在更新失败时如何回滚服务-
parallelism: 一次要回滚的容器数. 若=0 $\to$ 所有容器同时回滚. -
delay: 每个容器组回滚间等待时间 (默认 0s) -
failure_action: 若回滚失败执行的操作. 其中有 continue 或者 pause (默认pause). (continue, pause 分别代表什么? 还能设置什么操作) -
monitor: 每个容器更新后, 持续观察是否失败的时间 (ns or us or ms or s or m or h) (默认 0s) -
max_failure_ratio: 回滚时可容忍的故障率 (默认为0). -
order: 回滚时的操作顺序. 其中有stop-first(串行回滚) orstart-first(并行回滚) (默认 stop-first ).
-
-
update_config: 配置如何更新服务 (对配置滚动更新有用)-
parallelism: 一次更新的容器数. -
delay: 在更新一组容器间的等待时间. -
failure_action: 若更新失败, 如何操作. 其中有 continue, rollback, pause (默认: pause). (continue, rollback, pause 分别代表什么? 还能设置什么操作) -
monitor: 每个容器更新后, 持续观察是否失败的时间 (ns or us or ms or s or m or h) (默认 0s). -
max_failure_ratio: 在更新过程中可容忍的故障率. -
order: 更新时的操作顺序. 其中有 stop-first (串行回滚) or start-first (并行回滚) (默认stop-first).
-
[!Caution]
仅支持 V3.4 及更高版本
devices 指定设备映射列表.
1
2
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"
dns 自定义 DNS 服务器, 可列单值 or 列多个值.
1
2
3
4
5
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
dns_search 自定义 DNS 搜索域. 可列单值 or 列多个值.
1
2
3
4
5
dns_search: example.com
dns_search:
- dc1.example.com
- dc2.example.com
entrypoint
覆盖容器默认 entrypoint. (entrypoint 是干嘛的)
1
2
3
4
5
6
7
8
9
10
entrypoint: /code/entrypoint.sh
# or
entrypoint:
- php
- -d
- zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
- -d
- memory_limit=-1
- vendor/bin/phpunit
env_file 从文件添加环境变量. 可列单值 or 列多个值.
1
2
3
4
5
6
7
env_file: .env
# or
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
environment 环境变量. 可数组或字典, 布尔值(需引号)
1
2
3
environment:
RACK_ENV: development
SHOW: 'true'
expose 暴露端口 (仅可指定内部端口为参数)
1
2
3
expose:
- "3000"
- "8000"
extra_hosts
添加主机名映射. 类似 docker client --add-host
1
2
3
extra_hosts:
- "somehost:162.242.195.82"
- "otherhost:50.31.209.229"
会在此服务内部容器中 /etc/hosts 创建具有 ip 地址&主机名的映射关系:
162.242.195.82 somehost
50.31.209.229 otherhost
healthcheck 检测 docker 服务是否健康运行
1
2
3
4
5
6
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
interval: 1m30s # 设置检测间隔
timeout: 10s # 设置检测超时时间
retries: 3 # 设置重试次数
start_period: 40s # 启动后, 多少秒开始启动检测程序
image 指定容器运行镜像. 以下格式均可:
1
2
3
4
5
image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd # 镜像id
logging
服务日志记录配置
driver: 指定服务容器日志记录驱动程序; 默认值为json-file. 有以下三个选项 (这三个分别代表什么意思)
1
2
3
driver: "json-file"
driver: "syslog"
driver: "none"
-
json-file驱动程序下, 可使用以下参数, 限制日志得数量和大小1 2 3 4 5
logging: driver: json-file options: max-size: "200k" # 单个文件大小为200k max-file: "10" # 最多10个文件
[!Note] 达到文件限制上限, 会自动删除旧文件
-
syslog驱动程序下, 可使用syslog-addres指定日志接收地址.1 2 3 4
logging: driver: syslog options: syslog-address: "tcp://192.168.0.42:123"
network_mode 设置网络模式.
1
2
3
4
5
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
-
networks: 配置容器连接的网络, 引用顶级 networks 下的条目.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
services: some-service: networks: some-network: aliases: - alias1 other-network: aliases: - alias2 networks: some-network: # Use a custom driver driver: custom-driver-1 other-network: # Use a custom driver which takes special options driver: custom-driver-2
-
aliases: 同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务.
restart
1
2
3
4
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
no: 默认重启策略 $\to$ 不会重启容器always: 总是重新启动.on-failure: 非正常退出时 (退出状态非0) 重启容器unless-stopped: 退出时总是重启容器, 不考虑 Docker 守护进程启动时就已停止的容器
[!Caution]
swarm 集群模式改用
restart_policy
secrets 存储敏感数据, 如密码:
1
2
3
4
5
6
7
8
9
10
11
12
13
version: "3.1"
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
secrets:
- my_secret
secrets:
my_secret:
file: ./my_secret.txt
security_opt 修改容器默认的 schema 标签. (解释太少, 需要拓展)
1
2
3
4
5
security-opt:
- label:user:USER # 设置容器的用户标签
- label:role:ROLE # 设置容器的角色标签
- label:type:TYPE # 设置容器的安全策略标签
- label:level:LEVEL # 设置容器的安全等级标签
stop_grace_period
指定在容器无法处理 SIGTERM (or 任何 stop_signal 信号), 等待多久后发送 SIGKILL 信号关闭容器. 默认 10 s (SIGKILL 信号是干什么用的, SIGTERM 信号是干嘛用的)
1
2
stop_grace_period: 1s # 等待 1 秒
stop_grace_period: 1m30s # 等待 1 分 30 秒
stop_signal 设置停止容器的替代信号. 默认情况用 SIGTERM (stop_signal 有哪些信号类型, 有什么区别; 分别用于哪些场景)
1
stop_signal: SIGUSR1 # 使用 SIGUSR1 替代信号 SIGTERM 来停止容器.
sysctls 设置容器中内核参数, 可使用 数组or字典 (详细说说两个参数代指的意思)
1
2
3
4
5
6
7
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
tmpfs 容器内安装一个临时文件系统. 可列单值 or 列多个值. (临时文件系统的作用, 常用于哪些场景)
1
2
3
4
5
tmpfs: /run
tmpfs:
- /run
- /tmp
ulimits 覆盖容器默认的 ulimit. (ulimit 是干嘛用的, 为什么要覆盖默认的)
1
2
3
4
5
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
volumes 主机数据卷 or 文件挂载到容器
1
2
3
4
5
6
7
version: "3.7"
services:
db:
image: postgres:latest
volumes:
- "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
- "/localhost/data:/var/lib/postgresql/data"
7. Docker Machine
简介
可在虚拟主机上安装 Docker 的工具, 并可使用 docker-machine 命令来管理主机; 可集中管理所有 docker 主机(比如快速给 100 台服务器安装上 docker)
[!Caution]
- docker-machine 先处于归档状态; 已停止维护
- Docker Desktop 已经普及, 已自带完善虚拟机管理; 不需要通过 docker-machine 创建底层环境
- 核心技术替代:
docker context
现代的替代方案:
| 场景 | 推荐方案 |
|---|---|
| 本地开发 (Win/Mac) | Docker Desktop or OrbStack |
| 管理远程服务器 | docker context (最推荐,原生支持 SSH) |
| 自动化运维/云端 | Terraform, Ansible or 云厂商提供的容器服务 (ACK, EKS等) |
| 本地多节点集群测试 | Kind (Kubernetes in Docker) or Minikube |
此处应该补充 `docker context` & `Infrastructure as Code (IaC)` 两方面.[!Caution]
此方面应该将精力放在: docker context & Infrastructure as Code (IaC) 工具上
8. Swarm 集群管理
[!note]
维度 Docker Swarm Kubernetes (K8s) 备注 设计理念 简单至上; 追求与 Docker 生态无缝集成 功能至上. 追求极致可扩展性, 自动化&复杂资源调度 - 上手难度 极低, 懂 Docker Compose 没有学习成本 高, 概念繁多 (Pod, Deployment, Ingress, CRD…) - 基本单位 Container (容器), 直接操作容器实例 Pod, 逻辑封装,一个 Pod 可包含多个紧密耦合容器 K8s 最小调度单位: Pod 安装部署 docker swarm init通常需借助 kubeadm, k3s or 云厂商提供的托管服务 - 自动扩缩容 不支持原生自动缩放 (需手动 or 编写脚本) 原生支持(HPA/VPA),根据CPU/内存压力自动增减实例 K8s 强项 自愈能力 基础级别,容器挂了会重启,调度策略简单 高级级别,具备健康检查, 自动替换, 状态同步机制 - 网络模型 简单Overlay网络, 内置Ingress负载均衡 复杂且灵活, 支持 CNI 插件 (Calico, Flannel, Istio等) K8s 支持服务网格 (Service Mesh) 生态系统 有限, 依赖 Docker 社区 庞大且统治级, 大多云厂商 or 中间件优先支持 K8s 职业发展首选 K8s 资源消耗 极轻量, Manager 节点不占额外资源 较重, Control Plane(控制面)需可观内存&CPU 边缘计算多选 Swarm K8s 学习网站:
官方教程: [Kubernetes 文档 Kubernetes](https://kubernetes.io/zh-cn/docs/home/)
Killercoda 交互式场景: [Kubernetes Killercoda](https://killercoda.com/kubernetes)
Kuboard 中文教程: [Kubernetes教程 Kuboard](https://kuboard.cn/learning/)
Kubernetes Handbook (深度专业): [Kubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南 Jimmy Song](https://jimmysong.io/zh/book/kubernetes-handbook/)
K8s 2026 最新标准补充: [Kubernetes Tutorial For Beginners 2026 Learn Kubernetes Kubernetes Tutorial Simplilearn](https://www.youtube.com/watch?v=KFpxOO7PXFg)
8.1. 简介
Docker 集群管理工具; 将 Docker 主机池转变为单个虚拟 Docker 主机. 提供标准 Docker API; 所有已与 Docker 守护程序通信的工具都可用 Swarm 扩展到多个主机
支持的工具包括但不限于:
- Dokku: 非常轻量级的脚本集合,底层基于 Docker,为简化部署而生
- Docker Compose
- Jenkins: 通用的自动化任务执行器
[!Note]
Dokku: 一款 “迷你版 Heroku” 的轻量级 PaaS 平台; 通过简单的 Git 工作流实现应用的自动化部署. 基于 Docker, 极其适合个人开发者 or 小微团队, 只需通过
git push指令, Dokku 就能自动完成代码构建、容器运行、端口映射及 SSL 证书配置, 是追求极简主义和低成本服务器管理的专业首选Jenkins: DevOps 领域的工业级自动化枢纽, 主要负责持续集成与持续部署 (CI/CD); 像是拥有上千种插件的“万能流水线”, 能够串联起代码测试、安全扫描、镜像构建及多环境分发等复杂任务; 虽配置相对繁琐, 但在处理大规模、严谨的企业级开发流程时, 它是确保交付质量和流程自动化的核心支柱
8.2. 原理
如图, swarm 集群由管理节点 (manager), 工作节点 (work node) 构成
- swarm mananger:负责整个集群管理工作; 包括集群配置, 服务管理等 所有跟集群有关工作
- work node:即图中 available node; 主要负责运行相应的服务执行任务 (task)
8.3. 使用
8.3.1. 创建 swarm 集群管理节点(manager)
执行命令:
1
$ docker swarm init --advertise-addr <MANAGER-IP>
在 WSL 中输入: ` docker swarm init –advertise-addr 172.31.226.130` 之后, 输出如下
1
2
3
4
5
6
7
Swarm initialized: current node (u8mvcbr6iyk2ih2jtgkgnqt58) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4q4z3r9pyt266jb74xibmpi6ssxhb0mk6xpah0eovdnia255wb-d6fy5v722al21mz3k8pe2rx2z 172.31.226.130:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
执行命令:
1
2
3
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
u8mvcbr6iyk2ih2jtgkgnqt58 * DESKTOP-02TPVR7 Ready Active Leader 29.1.3
AVAILABILITY:Active: 调度程序 (Scheduler) 可将任务分配到该节点;Pause(静默观察): 停止接收新任务; 现有任务继续运行; 用于临时维护, 不希望增加负载Drain(排空): 停止接收新任务; 现有任务立即停止并转移到其他节点; 适用于硬件下线, 系统升级 or 彻底移除节点
MANAGER STATUS:Leader(领袖): 负责所有集群管理请求, 下达调度指令; 一个集群只有一个 LeaderReachable(可达): 处于健康状态, 参与 Raft 选举; 若 Leader 挂了, 通过竞选产生新 LeaderUnavailable(不可用): 无法与其他 Manager 通信; 意味着节点宕机, Docker 服务停止, 网络隔离;- 空值 (Blank): 该节点是普通 Worker 节点, 不参与集群
大纲:
第一步:创建管理节点 (Manager)
你已经完成了这一步:
Bash
1
docker swarm init --advertise-addr 172.31.226.130
第二步:创建工作节点 (Worker)
现在的变化: 在 WSL 中,如果你想模拟多个节点,你不需要再去安装 VirtualBox。你可以启动另一个 WSL 发行版(比如 Debian),或者更简单地,使用 Docker-in-Docker (DinD) 技术。
第三步:部署服务 (Service)
老教材用的是 alpine ping,我们来个更实际的 Nginx 服务,并体现 Swarm 的声明式编程思想:
Bash
1
docker service create --name my-web --replicas 2 -p 8080:80 nginx
3. 核心实验:滚动更新 (Rolling Update)
这是老教材第 8 点提到的精华。在 Swarm 中,更新服务不会导致停机(Downtime),这非常符合心理学中的“平滑过渡”预期。
让我们动手试试: 假设我们要把刚才部署的 Nginx 从旧版本升级到新版本:
Bash
1
docker service update --image nginx:latest --update-delay 10s my-web
--update-delay 10s:这就是老教材提到的延迟,确保一个容器升级成功后再升级下一个。
附录
1. 碰到的其他技术
Docker-in-Docker (DinD)技术














