docker使用

Docker使用

HELLO WORLD

1
docker run ubuntu:15.10 /bin/echo "Hello world"

image-20230904144746439

各个参数解析:

  • docker: Docker 的二进制执行文件。
  • run: 与前面的 docker 组合来运行一个容器。
  • ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
  • /bin/echo “Hello world”: 在启动的容器里执行的命令

以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo “Hello world”,然后输出结果。

二:运行交互式容器

我们通过 docker 的两个参数 -i -t,让 docker 运行的容器实现**”对话”**的能力:

1
docker run -i -t ubuntu:15.10 /bin/bash

各个参数解析:

  • -t: 在新容器内指定一个伪终端或终端。
  • -i: 允许你对容器内的标准输入 (STDIN) 进行交互。

image-20230904145039515

此时我们已进入一个 ubuntu15.10 系统的容器

我们尝试在容器中运行命令 cat /proc/versionls分别查看当前系统的版本信息和当前目录下的文件列表

1
2
cat /proc/version
ls

image-20230904145143682

我们可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。

image-20230904145234399

注意第三行中 [root@iZ0jl97pcghcwerp9ixrcvZ ~]# 表明我们已经退出了当前的容器,返回到当前的主机中。

三:启动容器(后台模式)

使用以下命令创建一个以进程方式运行的容器

1
docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"

要想让容器在后台以守护态形式运行,可通过-d参数来实现

image-20230904145639031

在输出中,我们没有看到期望的 “hello world”,而是一串长字符

ad4021a07df0218353b5ff0274beb03d75b94a43ff623af70d8f8e6c7e2b487e

这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。

首先,我们需要确认容器有在运行,可以通过 docker ps 来查看:

image-20230904145722870

输出详情介绍:

CONTAINER ID: 容器 ID。

IMAGE: 使用的镜像。

COMMAND: 启动容器时运行的命令。

CREATED: 容器的创建时间。

STATUS: 容器状态。

状态有7种:

  • created(已创建)
  • restarting(重启中)
  • running 或 Up(运行中)
  • removing(迁移中)
  • paused(暂停)
  • exited(停止)
  • dead(死亡)

PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

NAMES: 自动分配的容器名称。

在宿主主机内使用 docker logs 命令,查看容器内的标准输出:

1
docker logs 1a79030bd06a

image-20230904150355061

1a79030bd06a为容器名

要想获取容器的输出信息,可通过docker logs CONTAINER_ID来实现。
命令语法:

1
2
3
4
5
6
7
8
9
10
[root@kvm ~]# docker logs --help
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
--details 打印详细信息
-f, --follow 持续输出
--help 打印帮助信息
--since string 输出从某个时间开始的日志
--tail string 输出最近的若干日志
-t, --timestamps 显示时间戳信息

四:停止容器

我们使用 docker stop 命令来停止容器:

image-20230904150535634

通过 docker ps 查看,容器已经停止工作:

Docker容器使用

Docker 客户端

docker 客户端非常简单 ,我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项。

1
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
[root@iZ0jl97pcghcwerp9ixrcvZ ~]# docker

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Common Commands:
run Create and run a new container from an image
exec Execute a command in a running container
ps List containers
build Build an image from a Dockerfile
pull Download an image from a registry
push Upload an image to a registry
images List images
login Log in to a registry
logout Log out from a registry
search Search Docker Hub for images
version Show the Docker version information
info Display system-wide information

Management Commands:
builder Manage builds
buildx* Docker Buildx (Docker Inc., v0.11.2)
compose* Docker Compose (Docker Inc., v2.20.2)
container Manage containers
context Manage contexts
image Manage images
manifest Manage Docker image manifests and manifest lists
network Manage networks
plugin Manage plugins
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes

Swarm Commands:
swarm Manage Swarm

Commands:
attach Attach local standard input, output, and error streams to a running container
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
export Export a container's filesystem as a tar archive
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
wait Block until one or more containers stop, then print their exit codes

Global Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket to connect to
-l, --log-level string Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit

Run 'docker COMMAND --help' for more information on a command.

For more help on how to use Docker, head to https://docs.docker.com/go/guides/

可以通过命令 docker command –help 更深入的了解指定的 Docker 命令使用方法。

例如我们要查看 docker stats 指令的具体使用方法:image-20230904222619638

1
docker stats --help

容器使用

获取镜像

如果我们本地没有 ubuntu 镜像,我们可以使用 docker pull 命令来载入 ubuntu 镜像:

1
docker pull ubuntu

image-20230904222800984

启动容器

以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:

1
docker run -it ubuntu /bin/bash

image-20230904222909207

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu: ubuntu 镜像。
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

要退出终端,直接输入 exit:

image-20230904222936222

启动已停止运行的容器

查看所有的容器命令如下:

1
docker ps -a

image-20230904223053388

使用 docker start 启动一个已停止的容器:

1
docker start ad4021a07df0

image-20230904223151204

后台运行

在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。

1
docker run -itd --name ubuntu-test ubuntu /bin/bash

image-20230904223236840

注:加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec(下面会介绍到)。

停止一个容器

停止容器的命令如下:

1
docker stop <容器 ID>

进入容器

在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

  • docker attach
  • docker exec:推荐大家使用 docker exec 命令,因为此命令会退出容器终端,但不会导致容器的停止。

attach 命令

下面演示了使用 docker attach 命令。

1
docker attach cee9b3da35a7

注意: 如果从这个容器退出,会导致容器的停止。

exec 命令

下面演示了使用 docker exec 命令。

1
docker exec -it cee9b3da35a7 /bin/bash

注意: 如果从这个容器退出,容器不会停止,这就是为什么推荐大家使用 docker exec 的原因。

启动一个测试容器

要使用docker exec ,你将需要一个正在运行的Docker容器。如果你还没有一个容器,用下面的docker run 命令启动一个测试容器。

1
docker run -d --name container-name alpine watch "date >> /var/log/date.log"

该命令从官方的alpine 镜像创建一个新的Docker容器。这是一个流行的Linux容器镜像,使用Alpine Linux,一个轻量级、最小化的Linux发行版。

我们使用-d 标志将容器从我们的终端分离出来,并在后台运行它。 --name container-name将容器命名为container-name 。你可以在这里选择任何你喜欢的名字,或者完全不考虑这个问题,让Docker自动为新容器生成一个独特的名字。

接下来我们有alpine ,它指定了我们要为容器使用的镜像。

最后,我们有watch "date >> /var/log/date.log" 。这是我们想在容器中运行的命令。watch 将重复运行你给它的命令,默认情况下每两秒一次。在这种情况下,watch 将运行的命令是date >> /var/log/date.logdate 打印当前的日期和时间,像这样。

在Docker容器中运行一个交互式外壳

如果你需要在Docker容器中启动一个交互式外壳,也许是为了探索文件系统或调试运行中的进程,可以使用docker exec ,并加上-i-t 标志。

-i 标志保持对容器的输入开放,而-t 标志创建一个伪终端,让shell可以附着在上面。这些标志可以像这样组合。

1
docker exec -it container-name sh

这将在指定的容器中运行sh shell,给你一个基本的 shell 提示。要退出容器,请输入exit 然后按ENTER

1
exit

如果你的容器镜像包括一个更高级的shell,如bash ,你可以用上面的bash 替换sh

在Docker容器中运行一个非交互式命令

如果你需要在一个正在运行的Docker容器内运行一个命令,但不需要任何交互性,可以使用不带任何标志的docker exec 命令。

1
docker exec container-name tail /var/log/date.log

该命令将在container-name 容器上运行tail /var/log/date.log ,并输出结果。默认情况下,tail 命令将打印出一个文件的最后十行。如果你正在运行我们在第一节中设置的演示容器,你会看到像这样的东西。

image-20230904230639756

这基本上与为Docker容器打开一个交互式外壳相同(如上一步中的 docker exec -it container-name sh),然后运行tail /var/log/date.log 命令。然而,这个命令不是打开一个shell,运行该命令,然后关闭shell,而是在一个命令中返回相同的输出,并且不需要打开一个伪终端。

在Docker容器的备用目录中运行命令

要在容器的某个目录下运行命令,可以使用--workdir 标志来指定目录。

1
docker exec --workdir /tmp container-name pwd

这个例子的命令将/tmp 目录设置为工作目录,然后运行pwd 命令,打印出当前的工作目录。

1
Output/tmp

pwd 命令已经确认了工作目录是/tmp

在Docker容器中以不同的用户身份运行命令

要在你的容器内以不同的用户身份运行命令,可以添加--user 标志。

1
docker exec --user guest container-name whoami

这将使用访客用户在容器中运行whoami 命令。whoami 命令会打印出当前用户的用户名。

1
Outputguest

whoami 命令确认了容器的当前用户是guest

image-20230904231311740

将环境变量传递到Docker容器中

有时你需要把环境变量和要运行的命令一起传入容器。-e 标志可以让你指定一个环境变量。

1
docker exec -e TEST=sammy container-name env

这个命令将TEST 环境变量设置为等于sammy ,然后在容器内运行env 命令。然后,env 命令会打印出所有的环境变量。

1
2
3
4
OutputPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=76aded7112d4
TEST=sammy
HOME=/root

TEST 变量被设置为sammy

要设置多个变量,对每个变量重复使用-e 标志。

1
docker exec -e TEST=sammy -e ENVIRONMENT=prod container-name env

如果你想传入一个充满环境变量的文件,你可以用--env-file 标志来做。

首先,用一个文本编辑器制作文件。我们将在这里用nano 打开一个新文件,但你可以使用任何你熟悉的编辑器。

1
nano .env

我们使用.env 作为文件名,因为这是在版本控制之外使用这类文件来管理信息的流行标准。

把你的KEY=value 变量写进文件,每行一个,如下所示。

.env

1
2
TEST=sammy
ENVIRONMENT=prod

保存并关闭该文件。要保存该文件并退出nano ,按CTRL+O ,然后按ENTER 保存,再按CTRL+X 退出。

现在运行docker exec 命令,在--env-file 后面指定正确的文件名。

1
2
3
4
5
6
docker exec --env-file .env container-name env
ruby复制代码OutputPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=76aded7112d4
TEST=sammy
ENVIRONMENT=prod
HOME=/root

文件中的两个变量被设置。

你可以通过使用多个--env-file 标志来指定多个文件。如果文件中的变量相互重叠,命令中最后列出的文件将覆盖之前的文件。

常见错误

在使用docker exec 命令时,你可能会遇到一些常见的错误。

1
2
javascript
复制代码Error: No such container: container-name

No such container 错误意味着指定的容器不存在,并可能表明容器名称拼写错误。使用docker ps 来列出你正在运行的容器,并仔细检查名称。

1
2
vbnet
复制代码Error response from daemon: Container 2a94aae70ea5dc92a12e30b13d0613dd6ca5919174d73e62e29cb0f79db6e4ab is not running

这个not running 消息意味着容器存在,但它被停止了。你可以用以下命令启动容器 docker start container-name

1
2
python
复制代码Error response from daemon: Container container-name is paused, unpause the container before exec

Container is paused 这个错误相当好地解释了这个问题。你需要用下面的命令解除容器的停顿 docker unpause container-name解除暂停,然后再继续进行。

总结

在本教程中,我们学习了如何在运行中的Docker容器中执行命令,以及这样做时可用的一些命令行选项。

关于Docker的更多信息,请看我们的Docker标签页,其中有Docker教程、Docker相关问答页等链接。

关于安装Docker的帮助,请看如何在Ubuntu 20.04上安装和使用Docker

导出和导入容器

导出容器

如果要导出本地某个容器,可以使用 docker export 命令。

1
docker export 1e560fca3906 > ubuntu.tar

这样将导出容器快照到本地文件。

导入容器快照

可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:

1
$ cat docker/ubuntu.tar | docker import - test/ubuntu:v1

此外,也可以通过指定 URL 或者某个目录来导入,例如:

1
$ docker import http://example.com/exampleimage.tgz example/imagerepo

删除容器

删除容器使用 docker rm 命令:

1
docker rm -f 1e560fca3906

下面的命令可以清理掉所有处于终止状态的容器。

1
docker container prune

运行一个 web 应用

前面我们运行的容器并没有一些什么特别的用处。

接下来让我们尝试使用 docker 构建一个 web 应用程序。

我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用。

1
2
docker pull training/webapp  # 载入镜像
docker run -d -P training/webapp python app.py

参数说明:

  • **-d:**让容器在后台运行。
  • **-P:**将容器内部使用的网络端口随机映射到我们使用的主机上。

查看 WEB 应用容器

使用 docker ps 来查看我们正在运行的容器:

image-20230904233935108

这里多了端口信息。

1
2
PORTS
0.0.0.0:32769->5000/tcp

Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 32768上。

这时我们可以通过浏览器访问WEB应用

image-20230904234521679

我们也可以通过 -p 参数来设置不一样的端口:

1
runoob@runoob:~$ docker run -d -p 5000:5000 training/webapp python app.py

docker ps查看正在运行的容器

1
2
3
4
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 端口上。

网络端口的快捷方式

通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

上面我们创建的 web 应用容器 ID 为 e817961c265c 名字为 wizardly_chandrasekhar

我可以使用 docker port e817961c265c 来查看容器端口的映射情况。

image-20230904234738895

查看 WEB 应用程序日志

docker logs [ID或者名字] 可以查看容器内部的标准输出。

image-20230904234918103

-f:docker logs 像使用 tail -f 一样来输出容器内部的标准输出。

从上面,我们可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。

查看WEB应用程序容器的进程

我们还可以使用 docker top 来查看容器内部运行的进程

image-20230904235131297

检查 WEB 应用程序

使用 docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
[
{
"Id": "e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3",
"Created": "2023-09-04T15:38:12.507728353Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1264339,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-09-04T15:38:13.221502513Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557",
"ResolvConfPath": "/var/lib/docker/containers/e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3/hostname",
"HostsPath": "/var/lib/docker/containers/e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3/hosts",
"LogPath": "/var/lib/docker/containers/e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3/e817961c265c4da98db5e55accdf8af664f2e64857a747dfb842d05160d322e3-json.log",
"Name": "/inspiring_poitras",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
36,
180
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": true,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/2d2a290d24888a35c1d1f9d6dc6eeb301ab47d21ce5d7fc396a711605b13c615-init/diff:/var/lib/docker/overlay2/31d83bf38967766f520386db63bbd47d267ce9860a7eb74aaa0f9a2b4a3cc003/diff:/var/lib/docker/overlay2/f4f1a0964104e38137c78c9f93f16225f65bbdef9cdd246661118b026f50fd48/diff:/var/lib/docker/overlay2/de55dd9f5c5734f96f6e83722a9aadf7def7eba3831b4b817af1b556f71d5d9b/diff:/var/lib/docker/overlay2/9d931e43c7210555d56a7854d4c469798629e04083ea871156bc169387a3570f/diff:/var/lib/docker/overlay2/30a513799aa8dfd3450841a1ab321d828705a6ef1345cd843e642b3639b56f89/diff:/var/lib/docker/overlay2/456df9f3524d5c8b4121a8638a589a5ac1ab6f3f1fab4c5b08d1841c8a6fae91/diff:/var/lib/docker/overlay2/bb79d648bebaa8351d781e42a11a37c1016df57c74c385d996d2b4fcd470725b/diff:/var/lib/docker/overlay2/e2026b1ec0af515163f63e89ca355439ff4fbad83c23f9d358a97fe6b08da3fe/diff:/var/lib/docker/overlay2/2290c8f33422235b3b1d3f9d00c79ea462fd848f64f4f407617105cdbdf63fed/diff:/var/lib/docker/overlay2/aad1953f332586e2c7fecae05f9c6c3f1a8b23db6c105021a8d6c88dafbfe6c9/diff:/var/lib/docker/overlay2/fe8cdcbf8451d12019ead0365e50624133f2da09464810d6373e22672a436a81/diff:/var/lib/docker/overlay2/d1359973390c500de1b12833ff953b430bf9790733ae41d994d64891d28e6075/diff:/var/lib/docker/overlay2/fb9d8a342a94203e0ec950f3b160868a81793e9a0603c4f732cef2cb084a73b7/diff",
"MergedDir": "/var/lib/docker/overlay2/2d2a290d24888a35c1d1f9d6dc6eeb301ab47d21ce5d7fc396a711605b13c615/merged",
"UpperDir": "/var/lib/docker/overlay2/2d2a290d24888a35c1d1f9d6dc6eeb301ab47d21ce5d7fc396a711605b13c615/diff",
"WorkDir": "/var/lib/docker/overlay2/2d2a290d24888a35c1d1f9d6dc6eeb301ab47d21ce5d7fc396a711605b13c615/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "e817961c265c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"5000/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"python",
"app.py"
],
"Image": "training/webapp",
"Volumes": null,
"WorkingDir": "/opt/webapp",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "8c1a11d28636e42624eacd09f01ca77ee9faf4b4cf01124544d68e99895ba045",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"5000/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32768"
},
{
"HostIp": "::",
"HostPort": "32768"
}
]
},
"SandboxKey": "/var/run/docker/netns/8c1a11d28636",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "a1e74e592ed01a855096d2cc950d67c2df8c5de9a3d0780444bbeb6433a24463",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "823386ba858e21687c8c77a72bc8bfd2af15edadb40ffced2e0a1f3e90cabe2e",
"EndpointID": "a1e74e592ed01a855096d2cc950d67c2df8c5de9a3d0780444bbeb6433a24463",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]

停止 WEB 应用容器

image-20230904235453206

重启WEB应用容器

已经停止的容器,我们可以使用命令 docker start 来启动。

image-20230904235525723

移除WEB应用容器

我们可以使用 docker rm 命令来删除不需要的容器

image-20230904235648864

删除容器时,容器必须是停止状态,否则会报如下错误

image-20230904235609305

Docker 镜像使用

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。

下面我们来学习:

  • 1、管理和使用本地 Docker 主机镜像
  • 2、创建镜像

列出镜像列表

我们可以使用 docker images 来列出本地主机上的镜像。

image-20230905142733345

各个选项说明:

  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。

1
docker run -t -i ubuntu:15.10 /bin/bash 

所以,我们如果要使用版本为15.10的ubuntu系统镜像来运行容器时,命令如下:

image-20230905142823923

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu:15.10: 这是指用 ubuntu 15.10 版本镜像为基础来启动容器。
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

如果要使用版本为 14.04 的 ubuntu 系统镜像来运行容器时,命令如下:

1
docker run -t -i ubuntu:14.04 /bin/bash 

如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。

获取一个新的镜像

当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。

image-20230905143118405

下载完成后,我们可以直接使用这个镜像来运行容器。

查找镜像

我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/

我们也可以使用 docker search 命令来搜索镜像。比如我们需要一个 httpd 的镜像来作为我们的 web 服务。我们可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。

image-20230905143233259

NAME: 镜像仓库源的名称

DESCRIPTION: 镜像的描述

OFFICIAL: 是否 docker 官方发布

stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。

AUTOMATED: 自动构建。

拖取镜像

我们决定使用上图中的 httpd 官方版本的镜像,使用命令 docker pull 来下载镜像。

删除镜像

镜像删除使用 docker rmi 命令,比如我们删除 hello-world 镜像:

1
docker rmi hello-world

image-20230905143502457

创建镜像

当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。

  • 1、从已经创建的容器中更新镜像,并且提交这个镜像
  • 2、使用 Dockerfile 指令来创建一个新的镜像

更新镜像

更新镜像之前,我们需要使用镜像来创建一个容器。

1
docker run -t -i ubuntu:15.10 /bin/bash

image-20230905143628738

在运行的容器内使用 apt-get update 命令进行更新。

在完成操作之后,输入 exit 命令来退出这个容器。

此时 ID 为 b3c1ba8c9f63 的容器,是按我们的需求更改的容器。我们可以通过命令 docker commit 来提交容器副本。

1
docker commit -m="has update" -a="shuaige" b3c1ba8c9f63 aaa/ubuntu:v2

image-20230905144215483

各个参数说明:

  • -m: 提交的描述信息
  • -a: 指定镜像作者
  • e218edb10161:容器 ID
  • runoob/ubuntu:v2: 指定要创建的目标镜像名

我们可以使用 docker images 命令来查看我们的新镜像aaa/ubuntu:v2

image-20230905144353435

使用我们的新镜像 aaa/ubuntu 来启动一个容器

1
docker run -t -i aaa/ubuntu:v2 /bin/bash                            

image-20230905144503721

构建镜像

我们使用命令 docker build , 从零开始来创建一个新的镜像。为此,我们需要创建一个 Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。

1
2
3
4
5
6
7
8
9
10
11
cat Dockerfile 
FROM centos:6.7
MAINTAINER Fisher "3304978439@qq.com"

RUN /bin/echo 'root:123456' |chpasswd
RUN useradd Atlantic
RUN /bin/echo 'Atlantic:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D

每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。

第一条FROM,指定使用哪个镜像源

RUN 指令告诉docker 在镜像内执行命令,安装了什么。。。

然后,我们使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。

设置镜像标签

我们可以使用 docker tag 命令,为镜像添加一个新的标签。

1
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

Docker 容器连接

前面我们实现了通过网络端口来访问运行在 docker 容器内的服务。

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P-p 参数来指定端口映射。

下面我们来实现通过端口连接到一个 docker 容器。

网络端口映射

我们创建了一个 python 应用的容器。

image-20230905151825954

另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。

我们使用 -P 绑定端口号,使用 docker ps 可以看到容器端口 5000 绑定主机端口 32770。

image-20230905151919768

我们也可以使用 -p 标识来指定容器端口绑定到主机端口。

两种方式的区别是:

  • -P :是容器内部端口随机映射到主机的端口。
  • -p : 是容器内部端口绑定到指定的主机端口。
1
docker run -d -p 6666:5000 training/webapp python app.py

image-20230905152029877

另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。

image-20230905152306777

这样我们就可以通过访问 127.0.0.1:5001 来访问容器的 5000 端口。

上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp

1
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

image-20230905152337440

docker port 命令可以让我们快捷地查看端口的绑定情况。

1
docker port <CONTAINER_id> [PRIVATE_PORT[/PROTO]]

image-20230905152608795

Docker 容器互联

端口映射并不是唯一把 docker 连接到另一个容器的方法。

docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。

docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。

容器命名

当我们创建一个容器的时候,docker 会自动对它进行命名。另外,我们也可以使用 –name 标识来命名容器,例如:

1
docker run -d -P --name nb training/webapp python app.py

image-20230905153326743

新建网络

下面先创建一个新的 Docker 网络。

1
docker network create -d bridge test-net

然后用

1
docker network ls

查看

image-20230905153642068

参数说明:

-d:参数指定 Docker 网络类型,有 bridge、overlay。

其中 overlay 网络类型用于 Swarm mode,在本小节中你可以忽略它。

连接容器

运行一个容器并连接到新建的 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

在 test1 容器输入以下命令:

1
ping test2

配置 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 是否生效可以使用以下命令,它会输出容器的 DNS 信息:

1
$ docker run -it --rm  ubuntu  cat etc/resolv.conf

没找到这个文件,上网搜索了一下,发现使用json配置 Docker daemon,请在linux系统创建/etc/docker/daemon.json。噢原来要新建一个文件。

手动指定容器的配置

如果只想在指定的容器设置 DNS,则可以使用以下命令:

1
$ docker run -it --rm -h host_ubuntu  --dns=114.114.114.114 --dns-search=test.com ubuntu

参数说明:

–rm:容器退出时自动清理容器内部的文件系统。

-h HOSTNAME 或者 –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。

如果在容器启动时没有指定 –dns–dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。

Docker 仓库管理

仓库(Repository)是集中存放镜像的地方。以下介绍一下 Docker Hub。当然不止 docker hub,只是远程的服务商不一样,操作都是一样的。

Docker Hub

目前 Docker 官方维护了一个公共仓库 Docker Hub

大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。

注册

https://hub.docker.com 免费注册一个 Docker 账号。

登录和退出

登录需要输入用户名和密码,登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像。

1
docker login

退出 docker hub 可以使用以下命令:

1
docker logout

拉取镜像

你可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。

以 ubuntu 为关键词进行搜索:

推送镜像

用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。

以下命令中的 username 请替换为你的 Docker 账号用户名。

Docker Dockerfile

什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. This page describes the commands you can use in a Dockerfile.

使用 Dockerfile 定制镜像

1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

2、FROM 和 RUN 指令的作用

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式:

1
2
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:

1
2
3
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

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 层镜像。可简化为以下格式:

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 层镜像。

开始构建镜像

在 Dockerfile 文件的存放目录下,执行构建动作。

以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。

:最后的 . 代表本次执行的上下文路径,下一节会介绍。

$ docker build -t nginx:v3 .

image-20230906153630276

失败了很多次,文件名称必须是Dockerfile,然后在文件目录打开命令运行。

上下文路径

上一节中,有提到指令最后一个 . 是上下文路径,那么什么是上下文路径呢?

$ docker build -t nginx:v3 .

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

指令详解

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

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

1
2
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

**[–chown=:]**:可选参数,用户改变复制到容器内文件的拥有者和属组。

**<源路径>**:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 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 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

1
2
3
CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 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、不传参运行

1
$ docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

1
nginx -c /etc/nginx/nginx.conf

2、传参运行

1
$ docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

1
nginx -c /etc/nginx/new.conf

ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

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

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。

格式:

1
ARG <参数名>[=<默认值>]

VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的。
  • 避免容器不断变大。

格式:

1
2
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE

仅仅只是声明端口。

作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

1
EXPOSE <端口1> [<端口2>...]

WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

1
WORKDIR <工作目录路径>

USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

1
USER <用户名>[:<用户组>]

HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

1
2
3
4
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

1
ONBUILD <其它指令>

LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

1
LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我们可以添加镜像的作者:

Docker Compose

Compose 简介

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

如果你还不了解 YML 文件配置,可以先阅读 YAML 入门教程

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。

docker-compose.yml 的配置案例如下(配置参数参考下文):

实例

# yaml 配置实例
version**:** ‘3’
services:
web:
build**:** .
ports**:
** - “5000:5000”
volumes**:
** - .:/code
- logvolume01:/var/log
links**:
** - redis
redis:
image**:** redis
volumes:
logvolume01**:** {}


Compose 安装

Linux 上我们可以从 Github 上下载它的二进制包来使用,最新发行的版本地址:https://github.com/docker/compose/releases。

运行以下命令以下载 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

要安装其他版本的 Compose,请替换 v2.2.2。

Docker Compose 存放在 GitHub,不太稳定。

你可以也通过执行下面的命令,高速安装 Docker Compose。

1
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /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
docker-compose version

image-20230911214418073

注意: 对于 alpine,需要以下依赖包: py-pip,python-dev,libffi-dev,openssl-dev,gcc,libc-dev,和 make。

macOS

Mac 的 Docker 桌面版和 Docker Toolbox 已经包括 Compose 和其他 Docker 应用程序,因此 Mac 用户不需要单独安装 Compose。Docker 安装说明可以参阅 MacOS Docker 安装

windows PC

Windows 的 Docker 桌面版和 Docker Toolbox 已经包括 Compose 和其他 Docker 应用程序,因此 Windows 用户不需要单独安装 Compose。Docker 安装说明可以参阅 Windows Docker 安装


使用

1、准备

创建一个测试目录:

1
2
$ mkdir composetest
$ cd composetest

在测试目录中创建一个名为 app.py 的文件,并复制粘贴以下内容:

composetest/app.py 文件代码

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。

在 composetest 目录中创建另一个名为 requirements.txt 的文件,内容如下:

1
2
flask
redis

2、创建 Dockerfile 文件

在 composetest 目录中,创建一个名为 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"]

Dockerfile 内容解释:

  • FROM python:3.7-alpine: 从 Python 3.7 映像开始构建镜像。

  • WORKDIR /code: 将工作目录设置为 /code。

  • ENV FLASK_APP app.py
    ENV FLASK_RUN_HOST 0.0.0.0
    
    1
    2
    3
    4
    5
    6
    7
    8

    设置 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。

3、创建 docker-compose.yml

在测试目录中创建一个名为 docker-compose.yml 的文件,然后粘贴以下内容:

docker-compose.yml 配置文件

# yaml 配置
version**:** ‘3’
services:
web:
build**:** .
ports**:
** - “5000:5000”
redis:
image**:** “redis:alpine”

该 Compose 文件定义了两个服务:web 和 redis。

  • web:该 web 服务使用从 Dockerfile 当前目录中构建的镜像。然后,它将容器和主机绑定到暴露的端口 5000。此示例服务使用 Flask Web 服务器的默认端口 5000 。
  • redis:该 redis 服务使用 Docker Hub 的公共 Redis 映像。

4、使用 Compose 命令构建和运行您的应用

在测试目录中,执行以下命令来启动应用程序:

1
docker-compose up

如果你想在后台执行该服务可以加上 -d 参数:

1
docker-compose up -d

一直报错我服了image-20230911222013208

yml 配置指令参考

version

指定本 yml 依从的 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 组,意味着将继承该组的资源限制。

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。
  • 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

注意:web 服务不会等待 redis db 完全启动 之后才启动。

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:指定服务提供的模式。

  • replicated:复制服务,复制指定服务到集群的机器上。

  • global:全局服务,服务将部署至集群的每个节点。

  • 图解:下图中黄色的方块是 replicated 模式的运行情况,灰色方块是 global 模式的运行情况。

    img

replicas:mode 为 replicated 时,需要使用此参数配置具体运行的节点数量。

resources:配置服务器资源使用的限制,例如上例子,配置 redis 集群运行需要的 cpu 的百分比 和 内存的占用。避免占用资源过高出现异常。

restart_policy:配置如何在退出容器时重新启动容器。

  • condition:可选 none,on-failure 或者 any(默认值:any)。
  • delay:设置多久之后重启(默认值:0)。
  • max_attempts:尝试重新启动容器的次数,超出次数,则不再尝试(默认值:一直重试)。
  • window:设置容器重启超时时间(默认值:0)。

rollback_config:配置在更新失败的情况下应如何回滚服务。

  • parallelism:一次要回滚的容器数。如果设置为0,则所有容器将同时回滚。
  • delay:每个容器组回滚之间等待的时间(默认为0s)。
  • failure_action:如果回滚失败,该怎么办。其中一个 continue 或者 pause(默认pause)。
  • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
  • max_failure_ratio:在回滚期间可以容忍的故障率(默认为0)。
  • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认 stop-first )。

update_config:配置应如何更新服务,对于配置滚动更新很有用。

  • parallelism:一次更新的容器数。
  • delay:在更新一组容器之间等待的时间。
  • failure_action:如果更新失败,该怎么办。其中一个 continue,rollback 或者pause (默认:pause)。
  • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
  • max_failure_ratio:在更新过程中可以容忍的故障率。
  • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认stop-first)。

:仅支持 V3.4 及更高版本。

devices

指定设备映射列表。

1
2
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"

dns

自定义 DNS 服务器,可以是单个值或列表的多个值。

1
2
3
4
5
dns: 8.8.8.8

dns:
- 8.8.8.8
- 9.9.9.9

自定义 DNS 搜索域。可以是单个值或列表。

1
2
3
4
5
dns_search: example.com

dns_search:
- dc1.example.com
- dc2.example.com

entrypoint

覆盖容器默认的 entrypoint。

1
entrypoint: /code/entrypoint.sh

也可以是以下格式:

1
2
3
4
5
6
7
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

从文件添加环境变量。可以是单个值或列表的多个值。

1
env_file: .env

也可以是列表格式:

1
2
3
4
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env

environment

添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。

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 地址和主机名的映射关系:

1
2
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个文件

当达到文件限制上限,会自动删除旧得文件。

syslog 驱动程序下,可以使用 syslog-address 指定日志接收地址。

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

  • no:是默认的重启策略,在任何情况下都不会重启容器。
  • always:容器总是重新启动。
  • on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
  • unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
1
2
3
4
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped

注: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 (或者任何 stop_signal 的信号),等待多久后发送 SIGKILL 信号关闭容器。

1
2
stop_grace_period: 1s # 等待 1 秒
stop_grace_period: 1m30s # 等待 1 分 30 秒

默认的等待时间是 10 秒。

stop_signal

设置停止容器的替代信号。默认情况下使用 SIGTERM 。

以下示例,使用 SIGUSR1 替代信号 SIGTERM 来停止容器。

1
stop_signal: SIGUSR1

sysctls

设置容器中的内核参数,可以使用数组或字典格式。

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

在容器内安装一个临时文件系统。可以是单个值或列表的多个值。

1
2
3
4
5
tmpfs: /run

tmpfs:
- /run
- /tmp

ulimits

覆盖容器默认的 ulimit。

1
2
3
4
5
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000

volumes

将主机的数据卷或着文件挂载到容器里。

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"