Docker 基础使用

内容纲要

查看「Docker & Kubernetes 专题」获取更多相关内容


Docker 的基本使用和日常使用应用软件有些类似:

  1. 先在软件中心(仓库,一般默认使用 Docker Hub)获取安装包,也就是映像;
  2. 映像是只读的,它不仅像软件安装包一样包含需要的可执行文件,还有应用运行时的整个系统环境;
  3. 提取映像中的信息,然后运用 namespace、cgroup、chroot 技术创建出隔离环境并运行,当然因为是隔离环境所以如果需要在网络或文件上需要与之访问还需要一些设置;

容器管理

运行容器

前往 Docker Hub 或者打开 Docker Desktop,在顶部的搜索框查找想要的映像,例如 nginx、debian 等等,以 https://hub.docker.com/_/nginx 为例,可以关注几个部分:

  1. Docker Hub 就类似于 Github 有着各种各样的映像,在挑选的时候可以注意分为几类:
    • 标注有「Docker Official Image」的为 Docker 官方映像,是很可靠的选择。
    • 标注为「Verified publisher」的是通过认证的认证发行商 (一般是一些大公司)。但并不是说没有这个认证的就一定不可靠,因为这个认证是需要交钱的,一些项目就没有去做这个认证。
    • 其他个人上传的映像,这些映像的使用就需要谨慎了
  2. 「Overview」一般用于说明如何使用改映像;
  3. 「Tags」为映像的版本;

在 Docker Desktop 页面点击「Run」
Docker 基础使用

或者使用命令:

# --name 表示给容器起一个名字方便管理,如果省略 Docker 会随机一个名字
docker run --name webserver nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
3f4ca61aafcd: Already exists
50c68654b16f: Pull complete
3ed295c083ec: Pull complete
40b838968eea: Pull complete
88d3ab68332d: Pull complete
5f63362a3fa3: Pull complete
Digest: sha256:b4b4cfb61ce2c6d57fc87536ab718217a0099cb863030eebad4fd7f7db43c2ff
Status: Downloaded newer image for nginx:latest
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/12/21 12:16:58 [notice] 1#1: using the "epoll" event method
2022/12/21 12:16:58 [notice] 1#1: nginx/1.23.3
2022/12/21 12:16:58 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/12/21 12:16:58 [notice] 1#1: OS: Linux 5.15.49-linuxkit
2022/12/21 12:16:58 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/12/21 12:16:58 [notice] 1#1: start worker processes
2022/12/21 12:16:58 [notice] 1#1: start worker process 28
2022/12/21 12:16:58 [notice] 1#1: start worker process 29
2022/12/21 12:16:58 [notice] 1#1: start worker process 30
2022/12/21 12:16:58 [notice] 1#1: start worker process 31

等等,怎么就跑起来了?这是怎么来的容器?

在这里你可以按 Ctrl + C 终止并退出这个容器

在运行 docker run nginx 的时候,实际上经历了以下三个步骤(你可以不用跟着做):

  1. 如果本地上没有要运行的映像,就会从注册表的远程仓库中查找并获取,默认的远程仓库就是 Docker Hub,你可以在返回结果的第一行看到 Unable to find image 'nginx:latest' locally 表示在本地没有找到 nginx:latest 所以去远程仓库获取了;
  2. 然后就会创建容器,如 docker create --name webserver nginx,此时会返回容器 ID 如:d02c64483acc26ca0c40d65ab7060c22b9a70ca280f86ce8731ac65d356fd6ad

    如果你跟着做了,在执行第二步前需要先删除名为 webserver 的容器:docker rm -f webserver,否则 Docker 会告诉你这个名称已被另一个容器使用

  3. 然后使用运行容器,如:docker start -a d02c64483acc26ca0c40d65ab7060c22b9a70ca280f86ce8731ac65d356fd6ad

    如果是你自己操作可以使用容器名称 docker start -a webserver 或 ID 简写 docker start -a d0

最后启动容器时的 -a 选项是什么?

attached 和 detached 模式

这里的 -a 是 attached 模式,它表示将容器在前台运行,这样容器会附加标准输出和错误结果,并且转发信号。

如果不想看到输出结果也不想让容器占着终端(我还要干别的事呢?),那么假设使用 docker start 命令则在启动时不加任何选项直接加上映像名称即可,如 docker start d02c64483acc26ca0c40d65ab7060c22b9a70ca280f86ce8731ac65d356fd6ad

还有一种情况,如果一个容器是 detached 模式,想要转成 attached 模式呢?使用命令:

docker attach d02c64483acc26ca0c40d65ab7060c22b9a70ca280f86ce8731ac65d356fd6ad
# 可以简写,如
docker attach d0

好了这些暂时不重要以后用到再回过头看,回到 NGINX 上来,如果你比较熟悉 NGINX 通过返回结果就知道 NGINX 已经跑起来了,但尝试从浏览器访问 http://localhost 却没有任何反应啊?这是因为隔离了

网络与文件访问限制

如果是使用 Docker Desktop 运行一个容器,在点击播放键 ▶️ 图标时会看到一个可选项设置(Optional settings),展开后是这样的:
Docker 基础使用

  • 第一段是容器名称,也就是使用 docker run 命令时加上的 --name 选项;
  • 第二段是端口映射,并且它告诉了你容器所使用的端口及协议,这里填写的是宿主机所要映射到容器的端口;
  • 第三段是卷,挂载宿主机的指定目录到容器的指定目录;
  • 第四段是环境变量设置;

以创建一个带有端口映射的 NGINX 容器为例:

# -d, --detach
# -p, --publish
docker run -d -p 8080:80 --name webserver nginx

同样的此处需要先 docker rm -f webserver 否则会提示 webserver 名称已被别的容器使用

-d 使容器以 detach 模式在后台运行,-p 将宿主机 8080 端口映射到容器的 80 端口,然后浏览器刷新访问 http://localhost 就可以看到 NGINX 的欢迎页面了

在容器和本地文件系统之间复制文件或文件夹:

# 从宿主机传输文件到容器内
# docker cp <宿主机文件路径> <容器名称或 ID>:<容器文件路径>
docker cp config.json webserver:/tmp

# 从容器内传输文件到宿主机
# docker cp <容器名称或 ID>:<容器文件路径> <宿主机文件路径>
docker cp webserver:/etc/hosts . # 复制容器内的 hosts 文件到宿主机终端当前所在的目录

使用容器的名称或 ID 及建议使用文件的绝对路径,如果是宿主机终端当前的文件可以使用相对路径

篇幅有限这里只介绍了端口映射和文件复制的方法,更多关于存储与网络可以看以下文章:

查看、停止、启动、删除容器

使用 docker ps 可以查看容器,默认不加参数的情况下只能看到正在运行的容器,如果想要查看所有容器可以加上 -a

# -a, --all
docker ps -a
CONTAINER ID   IMAGE   COMMAND                  CREATED          STATUS                      PORTS   NAMES
d02c64483acc   nginx   "/docker-entrypoint.…"   17 minutes ago   Exited (0) 15 minutes ago           webserver

注意容器最后的名称 webserver 就是通过 --name 设置的,如果不设置 Docker 会随机命名

停止及启动容器可以使用命令:

# 停止一个容器
docker stop <容器名称或 ID>
# 多个容器可以以空格开个如
docker stop d6 9x 7c
# 如果想要停掉所有的容器
docker stop $(docker ps -q)

docker stop 会发送 SIGTERM 信号,但有时不起作用怎么办?可以使用发送 SIGKILLdocker kill 命令:

docker kill <容器名称或 ID>

一般来说使用 docker stop 的 10 秒后没有自动停止,那么 Docker 会回退使用docker kill

那如果将一个关闭的容器再次开启呢?

# 开启一个容器
docker start <容器名称或 ID>

删除容器可以使用命令:

# 删除容器前需要停止容器,或使用 -f 强制删除
docker rm <容器名称或 ID>

删除所有未使用的容器还可以使用这个命令,但它很危险请确认你需要这么做,它还有一个 -a 选项加上后会讲未使用的映像也一起删除

docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]

当然你也可以通过 Docker Desktop 进行管理:
Docker 基础使用

容器运行完成后自动删除

有时候可能会需要一次性容器,比如某个软件用完推出后容器就不再需要了,那么可以使用 --rm 选项:

docker run -d --rm -p 80:80 docker/getting-started

可以看到在使用 docker run 创建容器时修改的默认命令,即便容器退出后再次启动仍然生效

查看容器日志

如果启动容器时没有使用 -a,或者说这本来就是一个常用于 detached 模式的容器,我要怎么查看其标准输出,如日志内容呢?

docker logs <容器名称或 ID>

使用 Docker Desktop 也很方便
Docker 基础使用

在容器的右侧点开菜单选择「View details」

Docker 基础使用

在容器中运行命令

对于一个已经在运行的容器,想要在其中运行命令,可以这样:

# 以在后台运行一个 nginx 容器并命名为 webserver 为例
docker run -d --name webserver nginx

# docker exec <容器 ID 或名称> <命令>
docker exec webserver ls # 使用 ls 命令

但这样每次使用一个命令前都要加上 docker exec <容器 ID 或名称> 也太麻烦了

所以可以使用交互式:

# -i --interactive
# -t --tty
# docker exec -it <容器 ID 或名称> <命令>
docker exec -it webserver sh

这样就像打开终端时随意使用命令了,只是环境变到了容器里,想要从中退出来输入 exit 或使用快捷键 Ctrl + D

什么是 sh?sh 是 Shell 的一种,Shell 是一个接收由键盘输入的命令并将其传递给操作系统来执行的程序,比如 macOS 的 zsh,大多数 Linux 发行版默认使用的 Bash 和 Windows 的 Powershell

在 Docker Desktop 容器列表右侧菜单的「Open in terminal」也可以很方便的在容器内使用命令:
Docker 基础使用

除了对一个正在运行的容器操作,也可以在运行创建容器时就指定为交互式的容器:

# -i --interactive
# -t  --tty
# docker run -it <映像名称> <要运行的命令>
docker run -it debian:stable-slim sh

和上面一样,想要从中退出来输入 exit 或使用快捷键 Ctrl + D

默认命令

在启动容器时有一个可选项就是默认命令,有的容器在启动时会默认运行一条命令,而你可以指定别的命令来代替它,来看一个例子:

# docker run <映像名称> [命令]
docker run busybox
docker run busybox echo hi

运行第二个容器的时候它会返回 hiecho 用于将参数写入到标准输出上),这时看一下容器:

docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                      PORTS     NAMES
f96d932b38ae   busybox        "echo hi"                2 seconds ago    Exited (0) 1 second ago               gifted_saha
eab599f94ac7   busybox        "sh"                     37 seconds ago   Exited (0) 36 seconds ago             funny_herschel

可以看到 busybox 的默认 COMMAND 命令为 "sh",并且随后创建并修改默认命令为 echo hi 的第二个容器也在

现在这两个容器都是退出状态,再次运行修改过的第二个容器:

docker start -a f96d
hi

也就是说,默认命令的修改会伴随着容器,即便停止后再次开启

映像管理

获取映像

在文章开头我们知道了可以通过 docker pull 获取一个映像:

docker pull
Using default tag: latest
latest: Pulling from library/nginx
3f4ca61aafcd: Pull complete
50c68654b16f: Pull complete
3ed295c083ec: Pull complete
40b838968eea: Pull complete
88d3ab68332d: Pull complete
5f63362a3fa3: Pull complete
Digest: sha256:0047b729188a15da49380d9506d65959cce6d40291ccfb4e039f5dc7efd33286
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

开头说过标签一般就是容器的版本,如果不指定会默认使用 latest 也就是最新版

还有一个重点是返回结果的最后一行,实际上一条比较完整的命令应该是这样的:

# docker [image] pull [远程仓库][作者]<映像名称>[:标签]
docker pull docker.io/library/nginx:latest

这里的 docker.io 为远程仓库,也就是默认的 Docker Hub,除了它还有其他的远程仓库只是影响力都不如 Docker Hub,例如使用 Red Hat 的 Quay:

docker pull quay.io/fedora/fedora

library 是映像的作者名称,例如本文的 nginx 映像用的是 Docker 官方的,而你也打算弄个 nginx 不就重名了吗?所以一般会通过帐户进行区分,例如 DivineEngine 做了一个 NGINX 映像那么在拉取时就是:

docker pull divineengine/nginx

library 为 Docker 官方帐户所以可以省去而其他帐户的映像就需要加上以进行区分,就像在拉取 Docker Hub 映像时可以省去 docker.io 一样

查看映像

docker images # 或 docker image ls

当然也可以使用 Docker Desktop:
Docker 基础使用

在映像右侧菜单选择「View details」可以看到更多细节

Docker 基础使用

例如上图可以看到这个 NGINX 映像是基于 debian:11-slim

删除不再使用的映像

docker image rm <映像名称>
# 或简写
docker rmi <映像名称>

小结

基本的使用 Docker 就像平常使用软件那样:

  1. 在注册表上查找需要的映像;
  2. 使用 docker pull 拉取一个注册表上的映像到本地;
  3. 使用 docker run 运行一个容器;

使用 docker [container] 命令管理容器:

  • docker run <映像> 运行一个容器,--name 指定容器名称方便管理、-d 用于后台运行、-it 用于交互式运行、-p 用于映射端口、--rm 用于一次性容器,在退出后自动删除;
  • docker <start | stop> <容器名称或 ID> 用于启动或停止容器,停止所有容器可以使用 docker stop $(docker ps -q)
  • docker rm <容器名称或 ID> 用于删除指定容易,删除多个容器可以用空格隔开容器名称或 ID,删除容器时容器需为停止状态或使用 -f 选项,docker prune 可用于删除所有容器;
  • docker ps 用于查看当前正在运行的容器,-a 选项用于查看所以容器;
  • docker logs <容器名称或 ID> 用于查看容器日志,-f 选项用于实时查看;
  • docker exec -it <容器名称或 ID> <在容器中运行的命令> 用于「登录」进一个已经运行的容器进行命令操作;

使用 docker [image] 命令管理映像:

  • docker pull 用于拉取一个映像;
  • docker images 用于查看当前本地的映像;
  • dcoker rmi <映像名称> 用于删除指定映像;