Skip to content

Docker Containers

Container 表示容器,他们彼此是隔离的。Docker 整个使用过程的核心就是对 Container 的生命周期管理。

docker container

通过 docker container 命令来管理容器,它可以包含的子命令包括:

子命令 说明
docker container create 创建一个新容器
docker container run 创建并运行一个容器
docker container start 运行容器
docker container restart 重新运行容器
docker container stop 停止一个容器
docker container stats 显示容器资源使用情况
docker container port 列出所有发布的端口
docker container ls 列出所有容器
docker container rm 删除容器
docker container prune 删除所有未启动的容器

创建并运行容器: container run | container create/start/stop

最常见的创建容器命令就是docker run命令,它是 docker container run 的简写形式,它创建并运行一个容器(相当于 create -> start,如果映像不存在还会执行 pull):

Bash
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

该命令使用指定的images创建一个容器(container)。

Notes

默认情况下必须 sudo 执行,可以通过配置来实现非 root 用户创建容器

与容器进行交互: -a stdout/stdin/stderr | -it

在终端下交互我们通过 STDIN 来输入、STDOUT 来输出以及 STDERR 来显示错误信息。如果我们想要与容器进行交互就需要将容器内的 stdin/stdout/stderr 附加到当前终端下,而则就可以通过 -a/--attach 来实现:

Bash
# echo 输出内容到 stdin,
# 而 -a stdin 将容器的 stdin 附加到终端的 stdin
# 因此实现了 terminal -> docker 的数据传输
echo "test" | docker run -i -a stdin ubuntu cat -

# 下面的示例没有任何输出,除非出现了错误
# 想要看到输出必须附加到 stdout
docker run -a stderr ubuntu echo test

有时候我们希望保持 stdin 一直打开,此时可以通过 -i/--interactive 选项来实现,它能够实现 input 的管道传递:

Bash
docker run --rm -i busybox echo "foo bar baz" \
  | docker run --rm -i busybox awk '{ print $2 }' \
  | docker run --rm -i busybox rev
rab

-i 通常还会与 -t/--tty 一起使用来将容器的伪终端和当前控制台 I/O 绑定,实现真正的容器环境的交互式会话:

Bash
docker run -it debian
root@10a3e71492b0:/# factor 90
90: 2 3 3 5
root@10a3e71492b0:/# exit
exit

Note

单独使用 -t,这样容器仍然会被分配一个伪 TTY 但是无法写入 stdin,表现就是执行命令没有输出。唯一可能有用的情况就是哈容器的输出需要 tty 环境

后台运行: -d/--detach

启动容器时,默认在前台运行(此时要想交互需要 -it),如果想要更改容器为后台运行需要使用 -d/--detach 命令:

Bash
$ docker run -d nginx
0246aa4d1448a401cabd2ce8f242192b6e7af721527e48a810463366c7ff54f1
$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS        PORTS     NAMES
0246aa4d1448   nginx     "/docker-entrypoint.…"   2 seconds ago   Up 1 second   80/tcp    pedantic_liskov
$ docker logs -n 5 0246aa4d1448
2023/11/06 15:58:23 [notice] 1#1: start worker process 33
2023/11/06 15:58:23 [notice] 1#1: start worker process 34
2023/11/06 15:58:23 [notice] 1#1: start worker process 35
2023/11/06 15:58:23 [notice] 1#1: start worker process 36
2023/11/06 15:58:23 [notice] 1#1: start worker process 37
$ docker attach 0246aa4d1448
^C
2023/11/06 15:58:40 [notice] 1#1: signal 2 (SIGINT) received, exiting
...

Note

docker container attach CONTAINER 用于将后台运行的容器连接到 stdin stdout 和 stderr

不阻塞命令的后台运行

有时候我们启动容器即使指定了 -d 但是 docker ps 后依然没有看到正在运行的容器,这是因为运行的命令是非阻塞的。例如 ping bash 等都属于这种情况。容器在命令执行完毕后一定是会推出的,即使位于后台:

Bash
# bash 是非阻塞命令他运行后自动推出
docker run -d debian bash

# sleep 阻塞 9999 秒,在 sleep 完成前不会退出
docker run -d debian sleep 9999

而对于 bash 还比较特殊,如果它连接到虚拟终端就不会自动退出,因此如果执行:

Bash
# 这个时候就会一直在后台运行
docker run -itd debian bash

Tips

还有就是如果我们 docker run -it debian bash 即在前台运行了一个命令,如果想要让他切换到后台可以执行 chtl + p + q

命令执行: COMMAND/--entrypoint

运行容器核心是为了运行某个命令,它可以直接在后面通过 [COMMAND] 来指定。

Tips

默认情况下会执行 Dockerfile 文件中的 CMD 指令,[COMMAND] 实际上覆盖这个 CMD 指令

Bash
docker run -it bash

还有一个称为入口点的概念,可以通过 --entrypoint 选项来指定,该参数必须包含一个字符串值,他就是我们要在容器中运行的命令,并且 CMD/[COMMAND] 将作为参数附加到 ENTYPOINT 上

Tips

实际上就是 Dockerfile 中的 ENTRYPOINT 指令,类似于 CMD 指令

Bash
docker run -it --entrypoint /bin/bash example/redis

工作目录: -w/--workdir

容器中运行命令默认的工作目录是根目录(/),可以通过-w/--workdir来设置其他目录作为工作目录:

Bash
# 如果容器中尚不存在该目录的,则会创建该目录
docker run --rm -w /my/workdir alpine pwd
/my/workdir

Tips

在 Dockerfile 中使用 WORKDIR 指令设置工作目录

设置环境变量: -e

Docker 在创建 Linux 容器时会自动设置一些环境变量:

  • HOME: 根据 USER 设置
  • HOSTNAME: 与容器关联的主机名
  • PATH: 包括常用的运行目录(/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
  • TERM: 如果为容器分配了伪 tty 该环境变量是 xterm

此外还可以使用一个或多个 -e 来在容器中设置任何环境变量,甚至能够覆盖上述变量:

Bash
export today=Wednesday
docker run -e "deep=purple" -e today --rm alpine env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d2219b854598
deep=purple
today=Wednesday
HOME=/root

Tips

在 Dockerfile 中使用 ENV 指令设置环境变量

自动启动容器: --restart

可以使用 --restart 来定义如何自动重启容器:

  • no: 不自动重启,这也是默认行为
  • on-failure[:max-retries]: 如果容器因为错误而退出,请自动重启容器。其中可选的max-retries 来限制重启的次数
  • always: 如果容器停止,请始终重启容器。有个特殊情况就是如果手动停止了容器,这仅当 Docker 守护进程重新启动或手动启动容器本身才会重新启动
  • unless-stopped: 如果容器停止,请始终重启容器,这与 always 是一样的。区别在于如果手动停止了容器,即使 Docker 守护进程重新启动也不会重新启动。也就是说手动停止也必须手动启动

手动启动容器: container start

手动启动停止的容器最核心的就是需要知道停止的容器,这可以使用 docker ps --all 来实现。

Tips

容器启动本质上就是重新运行了 docker run [cmd] 命令。

其他

还有一些容器的其他设置参数:

显示容器资源使用: container stats

docker container stats 命令返回正在运行的容器的实时资源数据流:

Bash
$ docker stats

CONTAINER ID        NAME                                    CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
b95a83497c91        awesome_brattain                        0.28%               5.629MiB / 1.952GiB   0.28%               916B / 0B           147kB / 0B          9
67b2525d8ad1        foobar                                  0.00%               1.727MiB / 1.952GiB   0.09%               2.48kB / 0B         4.11MB / 0B         2
e5c383697914        test-1951.1.kay7x1lh1twk9c0oig50sd5tr   0.00%               196KiB / 1.952GiB     0.01%               71.2kB / 0B         770kB / 0B          1
4bda148efbc0        random.1.vnc8on831idyr42slu578u3cr      0.00%               1.672MiB / 1.952GiB   0.08%               110kB / 0B          578kB / 0B          2

删除容器: --rm | container rm | container prune

container run --rm 能够在运行完容器后删除与容器关联的匿名卷。类似的标准操作就是 docker container rm -v my-container

Tips

这个通常是用来调试使用的,注意它只能删除匿名卷,对于命名卷来说必须手动删除

docker container prune 能够删除所有已停止的容器。

在运行的容器中执行命令: container exec

如果想要在正在运行的容器中运行新命令:

Bash
docker exec -d mycontainer touch /tmp/execWorks

# 甚至可以直接执行交互式 shell
docker exec -it mycontainer sh

需要注意的是命令必须是可执行文件,而不能是 chained 命令:

Bash
# 不起作用
docker exec -it my_container "echo a && echo b"

# 正在应该
docker exec -it my_container sh -c "echo a && echo b"

该命令默认会在容器的默认工作目录上执行,并且使用默认环境变量,此时可以通过一些参数来修改:

  • -e/--env: 设置环境变量
  • -w/--workdir: 设置工作目录

列出所有容器: container ls

docker container ls用于列出所用容器,他有一个非常常见的别名就是 docker ps:

Bash
(own) yangguodong@debian:~/Documents/pycrawler/google_patent$ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED       STATUS          PORTSNAMES
53b52cd3d054   mzz2017/v2raya   "v2raya"                 3 weeks ago   Up 2 hours      0.0.0.0:2017->2017/tcp, :::2017->2017/tcp, 0.0.0.0:20170-20172->20170-20172/tcp, :::20170-20172->20170-20172/tcpv2raya

Tips

默认情况下他会列出正在运行的命令,如果想要列出所有的需要指定 --all 参数,其中的 STATUS 会指出他们的状态。这在启动停止的容器时很有用。

参考