容器化和 Docker 简介

容器化意味着封装或打包软件代码及其所有依赖项,以便它可以在任何基础架构上统一且一致地运行。

版本查看

docker —version docker-compose —version

初识 Docker - 介绍 Docker 基本知识

运行第一个容器

  1. docker run hello-world
  2. # Unable to find image 'hello-world:latest' locally
  3. # latest: Pulling from library/hello-world
  4. # 0e03bdcc26d7: Pull complete
  5. # Digest: sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc
  6. # Status: Downloaded newer image for hello-world:latest
  7. #
  8. # Hello from Docker!
  9. # This message shows that your installation appears to be working correctly.
  10. #
  11. # To generate this message, Docker took the following steps:
  12. # 1. The Docker client contacted the Docker daemon.
  13. # 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
  14. # (amd64)
  15. # 3. The Docker daemon created a new container from that image which runs the
  16. # executable that produces the output you are currently reading.
  17. # 4. The Docker daemon streamed that output to the Docker client, which sent it
  18. # to your terminal.
  19. #
  20. # To try something more ambitious, you can run an Ubuntu container with:
  21. # $ docker run -it ubuntu bash
  22. #
  23. # Share images, automate workflows, and more with a free Docker ID:
  24. # https://hub.docker.com/
  25. #
  26. # For more examples and ideas, visit:
  27. # https://docs.docker.com/get-started/

hello-world 镜像是使用 Docker 进行最小化容器化的一个示例。它有一个从 hello.c 文件编译的程序,负责打印出终端看到的消息。
现在,在终端中,可以使用 docker ps -a 命令查看当前正在运行或过去运行的所有容器:

  1. docker ps -a
  2. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. # 128ec8ceab71 hello-world "/hello" 14 seconds ago Exited (0) 13 seconds ago exciting_chebyshev

在输出中,使用 hello-world 镜像运行了名为 exciting_chebyshev 的容器,其容器标识为 128ec8ceab71。它已经在 Exited (0) 13 seconds ago,其中 (0) 退出代码表示在容器运行时未发生任何错误。
Docker 体系结构和三个非常基本的容器化概念,如下所示:

  • 容器
  • 镜像
  • 仓库

    什么是容器?

    容器是应用程序层的抽象,可以将代码和依赖项打包在一起。容器不虚拟化整个物理机,仅虚拟化主机操作系统。

什么是 Docker 镜像?

镜像是分层的自包含文件,充当创建容器的模板。它们就像容器的冻结只读副本。 镜像可以通过仓库进行共享。

什么是仓库?

镜像仓库是一个集中式的位置,可以在其中上传镜像,也可以下载其他人创建的镜像。 Docker Hub 是 Docker 的默认公共仓库。另一个非常流行的镜像仓库是 Red Hat 的 Quay。 除了 Docker Hub 或 Quay,还可以创建自己的镜像仓库来托管私有镜像。计算机中还运行着一个本地仓库,该仓库缓存从远程仓库提取的镜像。

image.png

Docker 架构概述

既然已经熟悉了有关容器化和 Docker 的大多数基本概念,那么现在是时候了解 Docker 作为软件的架构了。
该引擎包括三个主要组件:

  1. Docker 守护程序: 守护程序(dockerd)是一个始终在后台运行并等待来自客户端的命令的进程。守护程序能够管理各种 Docker 对象。
  2. Docker 客户端: 客户端(docker)是一个命令行界面程序,主要负责传输用户发出的命令。
  3. REST API: REST API 充当守护程序和客户端之间的桥梁。使用客户端发出的任何命令都将通过 API 传递,最终到达守护程序。

根据官方文档,

“ Docker 使用客户端-服务器体系结构。Docker client 与 Docker daemon 对话,daemon 繁重地构建、运行和分发 Docker 容器”。

作为用户,通常将使用客户端组件执行命令。然后,客户端使用 REST API 来访问长期运行的守护程序并完成工作。

全景图

好吧,说的够多了。 现在是时候了解刚刚学习的所有这些知识如何和谐地工作了。在深入解释运行 docker run hello-world 命令时实际发生的情况之前,看一下下面的图片:
Docker 使用 - 图2
该图像是在官方文档中找到的图像的略微修改版本。 执行命令时发生的事件如下:

  1. 执行 docker run hello-world 命令,其中 hello-world 是镜像的名称。
  2. Docker 客户端访问守护程序,告诉它获取 hello-world 镜像并从中运行一个容器。
  3. Docker 守护程序在本地仓库中查找镜像,并发现它不存在,所以在终端上打印 Unable to find image ‘hello-world:latest’ locally。
  4. 然后,守护程序访问默认的公共仓库 Docker Hub,拉取 hello-world 镜像的最新副本,并在命令行中展示 Unable to find image ‘hello-world:latest’ locally。
  5. Docker 守护程序根据新拉取的镜像创建一个新容器。
  6. 最后,Docker 守护程序运行使用 hello-world 镜像创建的容器,该镜像在终端上输出文本。

Docker 守护程序的默认行为是在 hub 中查找本地不存在的镜像。但是,拉取了镜像之后,它将保留在本地缓存中。因此,如果再次执行该命令,则在输出中将看不到以下几行:

  1. Unable to find image 'hello-world:latest' locally
  2. latest: Pulling from library/hello-world
  3. 0e03bdcc26d7: Pull complete
  4. Digest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9
  5. Status: Downloaded newer image for hello-world:latest

如果公共仓库中有可用镜像的更新版本,则守护程序将再次拉取该镜像。那个 :latest 是一个标记。镜像通常包含有意义的标记以指示版本或内部版本。

Docker 容器操作基础知识

怎样运行容器

1.13版本之前,通用语法:docker run Docker 使用 - 图3 1.13版本之后,命令行重构后语法:docker

使用以下语法:

  • object表示将要操作的 Docker 对象的类型。这可以是 container、image、network 或者 volume 对象。
  • command表示守护程序要执行的任务,即 run 命令。
  • options可以是任何可以覆盖命令默认行为的有效参数,例如端口映射的 —publish 选项。

现在,遵循此语法,可以将 run 命令编写如下:

docker container run Docker 使用 - 图4

image name 可以是在线仓库或本地系统中的任何镜像。例如,可以尝试使用fhsinchy / hello-dock 镜像运行容器。 该镜像包含一个简单的 Vue.js应用程序,该应用程序在容器内部的端口 80 上运行。
请在终端上执行以下命令以使用此镜像运行容器:

  1. docker container run --publish 8080:80 fhsinchy/hello-dock
  2. # /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
  3. # /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
  4. # /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
  5. # 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
  6. # 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
  7. # /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
  8. # /docker-entrypoint.sh: Configuration complete; ready for start up

怎样公开端口

容器是隔离的环境。主机系统对容器内部发生的事情一无所知。因此,从外部无法访问在容器内部运行的应用程序。
要允许从容器外部进行访问,必须将容器内的相应端口发布到本地网络上的端口。—publish 或 -p 选项的通用语法如下:

—publish :

在上一小节中编写了--publish 8080:80 时,这意味着发送到主机系统端口 8080 的任何请求都将转发到容器内的端口 80。
现在要在浏览器上访问该应用程序,只需访问 http://127.0.0.1:8080Docker 使用 - 图5
可以在终端窗口按下 ctrl + c 组合键或关闭终端窗口来停止容器。

如何使用分离模式

run 命令的另一个非常流行的选项是 —-detach 或 -d 选项。 在上面的示例中,为了使容器继续运行,必须将终端窗口保持打开状态。关闭终端窗口会停止正在运行的容器。
这是因为,默认情况下,容器在前台运行,并像从终端调用的任何其他普通程序一样将其自身附加到终端。
为了覆盖此行为并保持容器在后台运行,可以在 run 命令中包含 —detach 选项,如下所示:

  1. docker container run --detach --publish 8080:80 fhsinchy/hello-dock
  2. # 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc

与前面的示例不同,这次不会看到很多文字,而只获得新创建的容器的 ID。
提供选项的顺序并不重要。 如果将--publish 选项放在--detach 选项之前,效果相同。
使用 run 命令时必须记住的一件事是镜像名称必须最后出现。如果在镜像名称后放置任何内容,则将其作为参数传递给容器入口点,可能会导致意外情况。

怎样列表展示容器

container ls 命令可用于列出当前正在运行的容器。执行以下命令:

  1. docker container ls
  2. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp gifted_sammet

一个名为 gifted_sammet 的容器正在运行。它是在 5 seconds ago 前创建的,状态为 Up 5 seconds,这表明自创建以来,该容器一直运行良好。
CONTAINER ID 为 9f21cb777058,这是完整容器 ID 的前 12 个字符。完整的容器 ID 是 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc,该字符长 64 个字符。在上一节中 docker container run 命令行的输的就是完整的容器 ID 。
列表的 PORTS 列下,本地网络的端口 8080 指向容器内的端口 80。name gifted_sammet 是由 Docker 生成的,可能与你的计算机的不同。
container ls 命令仅列出系统上当前正在运行的容器。为了列出过去运行的所有容器,可以使用 —all 或 -a 选项。

  1. docker container ls --all
  2. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp gifted_sammet
  4. # 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 3 minutes ago Exited (0) 3 minutes ago reverent_torvalds
  5. # 128ec8ceab71 hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago exciting_chebyshev

如你所见,列表 reverent_torvalds 中的第二个容器是较早创建的,并以状态代码 0 退出,这表明在容器运行期间未产生任何错误。

怎样命名或者重命名一个容器

默认情况下,每个容器都有两个标识符。 如下:

  • CONTAINER ID - 64 个字符的随机字符串。
  • NAME - 两个随机词的组合,下划线连接。

基于这两个随机标识符来引用容器非常不方便。如果可以使用自定义的名称来引用容器,那就太好了。
可以使用 —name 选项来命名容器。要使用名为 hello-dock-container 的 fhsinchy/hello-dock 镜像运行另一个容器,可以执行以下命令:

  1. docker container run --detach --publish 8888:80 --name hello-dock-container fhsinchy/hello-dock
  2. # b1db06e400c4c5e81a93a64d30acc1bf821bed63af36cab5cdb95d25e114f5fb

本地网络上的 8080 端口被 gifted_sammet 容器(在上一小节中创建的容器)占用了。这就是为什么必须使用其他端口号(例如 8888)的原因。要进行验证,执行 container ls 命令:

  1. docker container ls
  2. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 28 seconds ago Up 26 seconds 0.0.0.0:8888->80/tcp hello-dock-container
  4. # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:8080->80/tcp gifted_sammet

重命名

docker container rename 实例:docker container rename gifted_sammet hello-dock-container-2

怎样停止或者杀死运行中的容器

docker container stop

可以是容器 ID 或名称 实例:docker container stop hello-dock-container

如果使用 name 作为标识符,则 name 将作为输出返回。stop 命令通过发送信号SIGTERM 来正常关闭容器。如果容器在一定时间内没有停止运行,则会发出 SIGKILL 信号,该信号会立即关闭容器。
如果要发送 SIGKILL 信号而不是 SIGTERM 信号,则可以改用 container kill 命令。container kill 命令遵循与 stop 命令相同的语法。

docker container kill hello-dock-container-2

怎样重新启动容器

当我说重启时,我指的如下是两种情况:

  • 重新启动先前已停止或终止的容器。
  • 重新启动正在运行的容器。

    docker container start 实例:docker container start hello-dock-container

    1. docker container restart hello-dock-container-2

怎样创建而不运行容器

container run 命令启动了容器,该命令实际上是两个单独命令的组合。这两个命令如下:

  • container create 命令从给定的镜像创建一个容器。
  • container start 命令将启动一个已经创建的容器。 ```shell docker container create —publish 8080:80 fhsinchy/hello-dock

2e7ef5098bab92f4536eb9a372d9b99ed852a9a816c341127399f51a6d053856

docker container ls —all

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

2e7ef5098bab fhsinchy/hello-dock “/docker-entrypoint.…” 30 seconds ago Created hello-dock

docker container start hello-dock

hello-dock

docker container ls

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

2e7ef5098bab fhsinchy/hello-dock “/docker-entrypoint.…” About a minute ago Up 29 seconds 0.0.0.0:8080->80/tcp hello-dock

  1. 容器 STATUS 已从 Created 更改为 Up 29 seconds,这表明容器现在处于运行状态。端口配置也显示在以前为空的 PORTS 列中。
  2. <a name="hrN2P"></a>
  3. ### 怎样移除挂起的容器
  4. container rm 命令删除停止的容器
  5. > **docker container rm <container identifier>**
  6. ```shell
  7. docker container ls --all
  8. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  9. # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 6 minutes ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-container
  10. # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Up About a minute 0.0.0.0:8080->80/tcp hello-dock-container-2
  11. # 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Exited (0) 10 minutes ago reverent_torvalds
  12. # 128ec8ceab71 hello-world "/hello" 12 minutes ago Exited (0) 12 minutes ago exciting_chebyshev

从输出中可以看到,ID为 6cf52771dde1 和 128ec8ceab71 的容器未运行。要删除 6cf52771dde1,可以执行以下命令:

  1. docker container rm 6cf52771dde1
  2. # 6cf52771dde1

可以使用 container ls 命令检查容器是否被删除。也可以一次删除多个容器,方法是将其标识符一个接一个地传递,每个标识符之间用空格隔开。
也可以使用 container prune 命令来一次性删除所有挂起的容器。
可以使用 container ls —all 命令检查容器列表,以确保已删除了挂起的容器:

  1. docker container ls --all
  2. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 8 minutes ago Up 3 minutes 0.0.0.0:8888->80/tcp hello-dock-container
  4. # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 12 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp hello-dock-container-2

现在列表中看到 hello-dock-container 和 hello-dock-container-2。 建议停止并删除两个容器,然后再继续进行下一部分。
container run 和 container start 命令还有 —rm 选项,它们表示希望容器在停止后立即被移除。 执行以下命令,使用 —rm 选项启动另一个 hello-dock 容器:

  1. docker container run --rm --detach --publish 8888:80 --name hello-dock-volatile fhsinchy/hello-dock
  2. # 0d74e14091dc6262732bee226d95702c21894678efb4043663f7911c53fb79f3
  3. docker container ls
  4. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. # 0d74e14091dc fhsinchy/hello-dock "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-volatile
  6. docker container stop hello-dock-volatile
  7. # hello-dock-volatile
  8. docker container ls --all
  9. # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

该容器已被自动删除。从现在开始,我将对大多数容器使用 —rm 选项。不需要的地方我会明确提到。

怎样以交互式模式运行容器

怎样创建 Docker 镜像