docker

第3章 镜像


012 构建镜像

对于 Docker 用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成的 Docker 官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。

使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。

当然,某些情况下我们也不得不自己构建镜像,比如:

  1. 找不到现成的镜像,比如自己开发的应用程序。
  2. 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。

所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。

Docker 容器文件系统

描述:从下面的图片可以看见出以下几点:

  • Docker 镜像代表了容器的文件系统里的内容,是容器的基础,镜像一般是通过 Dockerfile 生成的;
  • Docker 的镜像是分层的,所有的镜像(除了基础镜像)都是在之前镜像的基础上加上自己这层的内容生成的;
  • Docker 中每一层镜像的元数据都是存在 json 文件中的,除了静态的文件系统之外,还会包含动态的数据;
  • Docker 镜像生产容器后会在此基础之上加入挂载点到安装Docker宿主机文件系统之中,并提供一个读写层(Read-Write Layer),所以容器进程的所有操作都在读写层进行;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Docker 提供了两种构建镜像的方法:

  1. docker commit 命令
  2. Dockerfile 构建文件

docker commit

docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:

  1. 运行容器
  2. 修改容器
  3. 将容器保存为新的镜像

举个例子:在 ubuntu base 镜像中安装 vim并保存为新镜像。

  1. 第一步, 运行容器

    [root@docker ~]# docker run -it ubuntu
    root@8dbdff6d3d88:/#
    

    -it 参数的作用是以交互模式进入容器,并打开终端。d11014d4b667 是容器的内部 ID。

  2. 安装 vim

    确认 vim 没有安装。

    root@8dbdff6d3d88:/# vim          
    bash: vim: command not found
    

    安装 vim。

    root@8dbdff6d3d88:/# apt-get update
    root@8dbdff6d3d8:/# apt-get install -y vim  
    1. Africa  2. America  3. Antarctica  4. Arctic  5. Asia  6. Atlantic  7. Australia  8. Europe  9. Indian  10. Pacific  11. Etc
    Geographic area: 5                         
    
    Please select the city or region corresponding to your time zone.
    
      1. Aden      12. Bangkok     23. Dili         34. Istanbul   45. Krasnoyarsk   56. Novosibirsk  67. Samarkand      78. Tokyo
      2. Almaty    13. Barnaul     24. Dubai        35. Jakarta    46. Kuala_Lumpur  57. Omsk         68. Seoul          79. Tomsk
      3. Amman     14. Beirut      25. Dushanbe     36. Jayapura   47. Kuching       58. Oral         69. Shanghai       80. Ulaanbaatar
      4. Anadyr    15. Bishkek     26. Famagusta    37. Jerusalem  48. Kuwait        59. Phnom_Penh   70. Singapore      81. Urumqi
      5. Aqtau     16. Brunei      27. Gaza         38. Kabul      49. Macau         60. Pontianak    71. Srednekolymsk  82. Ust-Nera
      6. Aqtobe    17. Chita       28. Harbin       39. Kamchatka  50. Magadan       61. Pyongyang    72. Taipei         83. Vientiane
      7. Ashgabat  18. Choibalsan  29. Hebron       40. Karachi    51. Makassar      62. Qatar        73. Tashkent       84. Vladivostok
      8. Atyrau    19. Chongqing   30. Ho_Chi_Minh  41. Kashgar    52. Manila        63. Qostanay     74. Tbilisi        85. Yakutsk
      9. Baghdad   20. Colombo     31. Hong_Kong    42. Kathmandu  53. Muscat        64. Qyzylorda    75. Tehran         86. Yangon
      10. Bahrain  21. Damascus    32. Hovd         43. Khandyga   54. Nicosia       65. Riyadh       76. Tel_Aviv       87. Yekaterinburg
      11. Baku     22. Dhaka       33. Irkutsk      44. Kolkata    55. Novokuznetsk  66. Sakhalin     77. Thimphu        88. Yerevan
    Time zone: 69
    
  3. 保存为新镜像

打开一个新窗口中查看当前运行的容器。

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
8dbdff6d3d88   ubuntu    "/bin/bash"   2 minutes ago   Up 2 minutes             cool_darwin

上面查看结果的解释如下:

8dbdff6d3d88 是新创建容器的ID

cool_darwin 是 Docker 为我们的容器随机分配的名字。

执行 docker commit 命令将容器保存为镜像。

[root@docker ~]# docker commit cool_darwin ubuntu-with-vim    #cool_darwin是容器名,ubuntu-with-vim是新建的镜像名
sha256:ba18ae460c068f9bdba060350e64dcec4bc4af05b9918602ee34e6350d0369a4

新镜像命名为 ubuntu-with-vim

查看新镜像的属性。

[root@docker ~]# docker images 
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
ubuntu-with-vim              latest    acefd029083b   27 minutes ago   189MB
ubuntu                       latest    edbfe74c41f8   5 weeks ago      78.1MB

从 size 上看到镜像因为安装了软件而变大了。

从新镜像启动容器,验证 vim 已经可以使用。

[root@docker ~]# docker run -it ubuntu-with-vim    #ubuntu-with-vim是新创建的镜像名
root@4d071cf3014f:/# which vim
/usr/bin/vim
root@4d071cf3014f:/# vim file1

以上演示了如何用 docker commit 创建新镜像。然而,Docker 并不建议用户通过这种方式构建镜像。原因如下:

  1. 这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。比如要在 debian base 镜像中也加入 vim,还得重复前面的所有步骤。
  2. 更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。

既然 docker commit 不是推荐的方法,我们干嘛还要花时间学习呢?

原因是:即便是用 Dockerfile(推荐方法)构建镜像,底层也 docker commit 一层一层构建新镜像的。学习 docker commit 能够帮助我们更加深入地理解构建过程和镜像的分层结构。

下一节我们学习如何通过 Dockerfile 构建镜像。


013 Dockerfile构建镜像

Dockerfile 是一个文本文件,记录了镜像构建的所有步骤。

Dockerfile内容基础知识:

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层并对镜像进行提交

常用参数:

docker build -f [Dockerfile路径] [构建上下文路径]
参数 作用
-f--file 标志符,声明要使用自定义 Dockerfile
[Dockerfile路径] 绝对路径相对于构建上下文的路径(如 subdir/Dockerfile.dev
[构建上下文路径] Docker 打包发送给守护进程的目录(通常用 . 表示当前目录)

第一个 Dockerfile

用 Dockerfile 创建上节的 ubuntu-with-vim,其内容则为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面我们运行 docker build 命令构建镜像并详细分析每个细节。

[root@docker ~]# cd /root                     #生产环境一般新建一个目录,里面写Dockerfile,一个项目
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile .

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

① 当前目录为 /root。

② Dockerfile 准备就绪。

③ 运行 docker build 命令,-t 将新镜像命名为 ubuntu-with-vim-dockerfile,命令末尾的 . 指明 build context 为当前目录。Docker 默认会从 build context 中查找 Dockerfile 文件,我们也可以通过 -f 参数指定 Dockerfile 的位置。

④ 从这步开始就是镜像真正的构建过程。 首先 Docker 将 build context 中的所有文件发送给 Docker daemon。build context 为镜像构建提供所需要的文件或目录。
Dockerfile 中的 ADD、COPY 等命令可以将 build context 中的文件添加到镜像。此例中,build context 为当前目录 /root,该目录下的所有文件和子目录都会被发送给 Docker daemon。

所以,使用 build context 就得小心了,不要将多余文件放到 build context,特别不要把 //usr 作为 build context,否则构建过程会相当缓慢甚至失败。

⑤ Step 1:执行 FROM,将 ubuntu 作为 base 镜像。

⑥ Step 2:执行 RUN,安装 vim

⑦ 镜像构建成功。

⑧ 镜像重命名为ubuntu-with-vim-dockerfile

通过 docker images 查看镜像信息。

[root@docker ~]# docker images
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
ubuntu-with-vim-dockerfile   latest    bbc08145d011   10 minutes ago   189MB
ubuntu-with-vim              latest    acefd029083b   27 minutes ago   189MB
ubuntu                       latest    edbfe74c41f8   5 weeks ago      78.1MB

镜像 ID 为 bbc08145d011,与构建时的输出一致。

在上面的构建过程中,我们要特别注意指令 RUN 的执行过程。Docker 会在启动的临时容器中执行操作,并通过 commit 保存为新的镜像。

查看镜像分层结构

ubuntu-with-vim-dockerfile 是通过在 base 镜像的顶部添加一个新的镜像层而得到的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个新镜像层的内容由 RUN apt-get update && apt-get install -y vim 生成。这一点我们可以通过 docker history 命令验证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

docker history 会显示镜像的构建历史,也就是 Dockerfile 的执行过程。

ubuntu-with-vi-dockerfile 与 ubuntu 镜像相比,确实只是多了顶部的一层 bbc08145d011,由 apt-get 命令创建,大小为 111MB。docker history 也向我们展示了镜像的分层结构,每一层由上至下排列。

注: 表示无法获取 IMAGE ID,通常从 Docker Hub 下载的镜像会有这个问题。

下一节我们学习镜像的缓存特性。


015 调试Dockerfile

包括 Dockerfile 在内的任何脚本和程序都会出错。有错并不可怕,但必须有办法排查,所以本节讨论如何 debug Dockerfile。

先回顾一下通过 Dockerfile 构建镜像的过程:

  1. 从 base 镜像运行一个容器。
  2. 执行一条指令,对容器做修改。
  3. 执行类似 docker commit 的操作,生成一个新的镜像层。
  4. Docker 再基于刚刚提交的镜像运行一个新容器。
  5. 重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。

从这个过程可以看出,如果 Dockerfile 由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,这对调试 Dockerfile 非常有帮助。我们可以运行最新的这个镜像定位指令失败的原因。

我们来看一个调试的例子。Dockerfile 内容如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行 docker build

[root@docker ~]# ls             #查看下有没有Dockerfile和testfile
Dockerfile  testfile
[root@docker ~]# vim Dockerfile            #编辑Dockerfile,写入上图的内容
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c "echo continue to build..."
COPY testfile /

[root@docker ~]# docker build -t image-debug .   #基于刚才写的Dockerfile构建镜像image-debug

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用busybox的镜像进行调试,方式是通过 docker run -it 启动镜像的一个容器。

image-20250729153951514

手工执行 RUN 指令很容易定位失败的原因是 busybox 镜像中没有 bash,busybox中用的是sh。虽然这是个极其简单的例子,但它很好地展示了调试 Dockerfile 的方法。

# 找出错误原因,修改错误
[root@docker ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/sh -c "echo continue to builld..."          #将错误的/bin/bash修改为正确的/bin/sh
COPY testfile /

[root@docker ~]# docker build -t image-debug .   #基于刚才写的Dockerfile构建镜像image-debug

成功了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到这里相信大家对 Dockerfile 的功能和使用流程有了比较完整的印象,但还没有系统学习 Dockerfile 的各种指令和实际用法,下节会开始这个主题。


016 Dockerfile常用指令

是时候系统学习 Dockerfile 了。

下面列出了 Dockerfile 中最常用的指令,完整列表和说明可参看官方文档。

FROM

指定 base 镜像。第一条必须是FROM

MAINTAINER

设置镜像的作者,可以是任意字符串。

COPY

将文件从 build context 复制到镜像。
COPY 支持两种形式:

  1. COPY src dest
  2. COPY [“src”, “dest”]

注意:src 只能指定 build context 中的文件或目录。

ADD

与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。

ENV

设置环境变量,环境变量可被后面的指令使用。例如:

...

ENV MY_VERSION 1.3

RUN apt-get install -y mypackage=$MY_VERSION

...
EXPOSE

指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。

VOLUME

将文件或目录声明为 volume。我们会在容器存储部分详细讨论。

WORKDIR

为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。

RUN

在容器中运行指定的命令。

CMD

容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。

ENTRYPOINT

设置容器启动时运行的命令。
Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。

下面我们来看一个较为全面的 Dockerfile:

# my dockerfile
FROM busybox                     #从busybox开始构建
MAINTAINER 6946630@qq.com         #声明作者信息
WORKDIR /testdir                    #设置工作目录为/testdir
RUN touch tmpfile1                  #在新镜像中创建tmpfille1
COPY ["tmpfile2","."]               #将Dockerfile文件所在目录中的tmpfile2文件拷贝到新镜像中
ADD ["passwd.tar.gz","."]           #将Dockerfile文件所在目录中的passwd.tar.gz拷贝到新镜像中并解压缩
ENV WELCOME "You are in my container,welcome!"        #设置环境变量为WELOCME

完整的操作步骤如下:

[root@docker ~]# pwd                 #确定Dockerfile工作目录
/root
[root@docker ~]# ls                    #当前/root目录下空的
[root@docker ~]# touch tmpfile2             #创建空文档tmpfile2
[root@docker ~]# cp /etc/passwd .              #将/etc/passwd文件拷贝到/root
[root@docker ~]# tar -cvzf passwd.tar.gz passwd      #将passwd文件做出归档文件passwd.tar.gz
passwd
[root@docker ~]# rm passwd                  #删除passwd文件
rm: remove regular file 'passwd'? y
[root@docker ~]# vim Dockerfile          #编辑Dockerfile写入如下内容
# my dockerfile
FROM busybox
MAINTAINER 6946630@qq.com
WORKDIR /testdir
RUN touch tmpfile1
COPY ["tmpfile2","."]
ADD ["passwd.tar.gz","."]
ENV WELCOME "You are in my container,welcome!"

[root@docker ~]# ls                       #最后目录中有三个文件
Dockerfile  passwd.tar.gz  tmpfile2

[root@docker ~]# docker build -t my-image .    #构建新镜像my-image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

① 构建前确保 build context 中存在需要的文件。

② 依次执行 Dockerfile 指令,完成构建。

运行容器,验证镜像内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

① 进入容器,当前目录即为 WORKDIR。
如果 WORKDIR 不存在,Docker 会自动为我们创建。

② WORKDIR 中保存了我们希望的文件和目录:
文件passwd:由 ADD 指令从 build context 复制的归档文件passwd.tar.gz,已经自动解压。
文件 tmpfile1:由 RUN 指令创建。
文件 tmpfile2:由 COPY 指令从 build context 复制。

③ ENV 指令定义的环境变量已经生效。

在上面这些指令中,RUN、CMD、ENTRYPOINT 很重要且容易混淆,下节专门讨论。


019 使用公共Registry-dockerhub

Docker仓库类似于代码仓库,它是Docker集中存放镜像文件的场所。仓库注册服务器存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。

根据所存储的镜像公开分享与否,Docker仓库可以分为:

  • 公开仓库(Public)
  • 私有仓库(Private)

目前,最大的公开仓库是官方提供的Docker Hub,其中存放了数量庞大的镜像供用户下载。国内不少云服务提供商(如华为、阿里云等)也提供了仓库的本地源,可以提供稳定的国内访问。

当然,用户如果不希望公开分享自己的镜像文件,Docker也支持用户在本地网络内创建一个只能自己访问的私有仓库。当用户创建了自己的镜像之后就可以使用push命令将它上传到指定的公有或者私有仓库。这样用户下次在另外一台机器上使用该镜像时,只需要将其从仓库上pull下来就可以了。

保存和分发镜像的最直接方法就是使用 Docker Hub。

Docker Hub 是 Docker 公司维护的公共 Registry。用户可以将自己的镜像保存到 Docker Hub 免费的 repository 中。如果不希望别人访问自己的镜像,也可以购买私有 repository。

除了 Docker Hub,quay.io 是另一个公共 Registry,提供与 Docker Hub 类似的服务。

下面介绍如何用 Docker Hub 存取我们的镜像。

  1. 首先得在 Docker Hub 上注册一个账号。

  2. 在 Docker Host 上登录。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    这里用的是我自己的账号,用户名为 gaoqd,输入密码后登录成功。

  3. 修改镜像的 repository 使之与 Docker Hub 账号匹配。
    Docker Hub 为了区分不同用户的同名镜像,镜像的 registry 中要包含用户名,完整格式为:[username]/xxx:tag
    我们通过 docker tag 命令重命名镜像。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    注:Docker 官方自己维护的镜像没有用户名,比如 httpd。

  4. 通过 docker push 将镜像上传到 Docker Hub。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    Docker 会上传镜像的每一层。因为 gaoqd/httpd:v1 这个镜像实际上跟官方的 httpd 镜像一模一样,Docker Hub 上已经有了全部的镜像层,所以真正上传的数据很少。同样的,如果我们的镜像是基于 base 镜像的,也只有新增加的镜像层会被上传。如果想上传同一 repository 中所有镜像,省略 tag 部分就可以了,例如:
    docker push gaoqd/httpd

  5. 登录 https://hub.docker.com,在Public Repository 中就可以看到上传的镜像。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    如果要删除上传的镜像,只能在 Docker Hub 界面上操作。

  6. 这个镜像可被其他 Docker host 下载使用了。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


使用公共Registry-华为云

登录华为云

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

选择区域,选择离自己近的数据中心,创建组织

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进入新创建的组织

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来登录华为云,上传自己的镜像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

复制登录指令

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过上面获取的登录指令,回到docker上登陆

[root@docker ~]# docker login -u cn-east-3@HST3WGZY13FUUTQ9ZC32 -p b8e7d74da04a90cb0b1ac08ff894cebe6a8fc039f494dedd08cbc64095761aab swr.cn-east-3.myhuaweicloud.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@docker ~]#

上传镜像

#命令格式
sudo docker tag {镜像名称}:{版本名称} swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}
sudo docker push swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}
#刚才Dockerfile制作的httpd:centos镜像 用来上传
[root@docker ~]# docker images httpd:centos
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
httpd        centos    973cac3a687f   4 hours ago   288MB

#修改镜像名
[root@docker ~]# docker tag httpd:centos swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1

[root@docker ~]# docker images
REPOSITORY                                                 TAG        IMAGE ID       CREATED         SIZE
httpd                                                      centos     973cac3a687f   4 hours ago     288MB
swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd   v1         973cac3a687f   4 hours ago     288MB

#上传镜像
[root@docker ~]# docker push swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1
The push refers to repository [swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd]
63f254ce601f: Pushed
ca98143f89dc: Pushed
7d3485567b78: Pushed
717a93ee4ccf: Pushed
74ddd0ec08fa: Layer already exists
v1: digest: sha256:49c69273c49ab25e17ad54d2bb74412ae09a699dc3ee91f72c1cef9ba8ce405e size: 1363
[root@docker ~]#

上传成功登录华为云查看:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下载自己上传的镜像

本地先把镜像删除再下载

[root@docker ~]# docker rmi swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

复制pull命令

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[root@docker ~]# docker pull swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1

[root@docker ~]# docker images
REPOSITORY                                                 TAG        IMAGE ID       CREATED         SIZE
swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd   v1         973cac3a687f   4 hours ago     288MB

设置为公开

点击右上角**…**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

020 搭建本地Registry

Docker Hub 虽然非常方便,但还是有些限制,比如:

  1. 需要 internet 连接,而且下载和上传速度慢。

  2. 上传到 Docker Hub 的镜像任何人都能够访问,虽然可以用私有 repository,但不是免费的。

  3. 安全原因很多组织不允许将镜像放到外网。

解决方案就是搭建本地的 Registry。

Registry

Docker 已经将 Registry 开源了,同时在 Docker Hub 上也有官方的镜像 registry。下面我们就在 Docker 中运行自己的 registry。

  1. 启动 registry 容器。

    [root@docker ~]# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
    Unable to find image 'registry:2' locally
    2: Pulling from library/registry
    1cc3d825d8b2: Pull complete
    85ab09421e5a: Pull complete
    40960af72c1c: Pull complete
    e7bb1dbb377e: Pull complete
    a538cc9b1ae3: Pull complete
    Digest: sha256:ac0192b549007e22998eb74e8d8488dcfe70f1489520c3b144a6047ac5efbe90
    Status: Downloaded newer image for registry:2
    a8214201171f28a13803c647ef84acdc982465c230cb5c6a034bd05574948408
    [root@docker ~]#
    

    我们使用的镜像是 registry:2

    -d 是后台启动容器。

    -p 将容器的 5000 端口映射到 Host 的 5000 端口。5000 是 registry 服务端口。端口映射我们会在容器网络章节详细讨论。

    -v 将容器 /var/lib/registry 目录映射到 Host 的 /myregistry,用于存放镜像数据。-v 的使用我们会在容器存储章节详细讨论。

  2. 通过 docker tag 重命名镜像,使之与 registry 匹配。

    [root@docker ~]# docker images
    REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
    httpd                                                     latest     5daf6a4bfe74   2 months ago    148MB
    
    [root@docker ~]# docker tag httpd:latest localhost:5000/httpd:v1
    [root@docker ~]# docker images
    REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
    httpd                                                     latest     5daf6a4bfe74   2 months ago    148MB
    localhost:5000/httpd                                      v1         5daf6a4bfe74   2 months ago    148MB
    

    我们在镜像的前面加上了运行 registry 的主机名称和端口。

    前面已经讨论了镜像名称由 repository 和 tag 两部分组成。而 repository 的完整格式为**:[registry-host]:[port]/[username]/xxx**

    只有 Docker Hub 上的镜像可以省略 [registry-host]:[port]

  3. 通过 docker push 上传镜像。

    [root@docker ~]# docker push localhost:5000/httpd:v1
    The push refers to repository [localhost:5000/httpd]
    85d0eb049481: Pushed
    53a350bcb78a: Pushed
    db9328cd0153: Pushed
    5f70bf18a086: Pushed
    3bbc250aae52: Pushed
    8d853c8add5d: Pushed
    v1: digest: sha256:f432c26db81bdb6eb2c60c61d5d607615398f2e983eaaaff87ade6bbb2fec875 size: 1572
    
    [root@docker httpd]# curl http://localhost:5000/v2/_catalog
    {"repositories":["httpd"]}
    
  4. 现在已经可通过 docker pull 从本地 registry 下载镜像了。

    #下载之前先删除本地的镜像
    [root@docker ~]# docker rmi httpd:latest
    [root@docker ~]# docker rmi localhost:5000/httpd:v1
    
    #从自建仓库下载镜像
    [root@docker ~]# docker pull localhost:5000/httpd:v1
    v1: Pulling from httpd
    302e3ee49805: Already exists
    4669bea11670: Pull complete
    4f4fb700ef54: Pull complete
    ca8887d72588: Pull complete
    c7c900975bf7: Pull complete
    95eac36196b2: Pull complete
    Digest: sha256:f432c26db81bdb6eb2c60c61d5d607615398f2e983eaaaff87ade6bbb2fec875
    
    #验证从自建仓库下载的镜像
    [root@docker ~]# docker images localhost:5000/httpd
    REPOSITORY             TAG       IMAGE ID       CREATED        SIZE
    localhost:5000/httpd   v1        5daf6a4bfe74   2 months ago   148MB
    

    除了镜像的名称长一些(包含 registry host 和 port),使用方式完全一样。

以上是搭建本地 registry 的简要步骤。当然 registry 也支持认证,https 安全传输等特性,具体可以参考官方文档 https://docs.docker.com/registry/configuration/


企业级私有仓库Harbor

我们如果需要部署一个私有镜像仓库来使用,最简单的就是 registry ,一行命令就可以运行在 Docker 中,但功能也比较弱,如果想要私有镜像仓库功能更丰富些,可以使用 Harbor。

本文简单介绍下 Harbor 的安装和使用。

Harbor是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库。

harbor下载:https://github.com/goharbor/harbor/releases

安装

[root@docker ~]# wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz

如果无法通过 wget 进行下载,可以直接到 Github 网站:https://github.com/goharbor/harbor/releases/ 进行下载,然后拷贝到服务器中

  [root@docker ~]# ls
harbor-offline-installer-v2.9.1.tgz

执行下面命令进行解压

[root@docker ~]# tar -xvf harbor-offline-installer-v2.9.1.tgz
harbor/harbor.v2.9.1.tar.gz
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl

执行下面命令新建目录,并将程序文件复制到目录中:

[root@docker ~]# mkdir /opt/harbor
[root@docker ~]# mv harbor/* /opt/harbor/

导入Harbor镜像

[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker load -i harbor.v2.9.1.tar.gz     

修改 Harbor 配置文件

[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# cp -ar harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**hostname:**如果只是内网访问,设置为内网 IP,如果需要外网访问,就必须设置为外网域名或 IP

https: #注释掉

harbor_admin_password: harbor登录密码

编辑完配置文件,接下来在 harbor 目录下安装 Harbor。先进行预处理更新配置文件

[root@docker harbor]# ./prepare
prepare base dir is set to /opt/harbor
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir

执行下面命令进行安装

[root@docker harbor]# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 26.1.3

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.27.0

[Step 2]: loading Harbor images ...
Loaded image: goharbor/harbor-jobservice:v2.9.1
Loaded image: goharbor/harbor-registryctl:v2.9.1
Loaded image: goharbor/harbor-core:v2.9.1
Loaded image: goharbor/harbor-log:v2.9.1
Loaded image: goharbor/harbor-db:v2.9.1
Loaded image: goharbor/harbor-exporter:v2.9.1
Loaded image: goharbor/redis-photon:v2.9.1
Loaded image: goharbor/nginx-photon:v2.9.1
Loaded image: goharbor/registry-photon:v2.9.1
Loaded image: goharbor/trivy-adapter-photon:v2.9.1
Loaded image: goharbor/prepare:v2.9.1
Loaded image: goharbor/harbor-portal:v2.9.1


[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...
prepare base dir is set to /opt/harbor
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Clearing the configuration file: /config/portal/nginx.conf
Clearing the configuration file: /config/log/logrotate.conf
Clearing the configuration file: /config/log/rsyslog_docker.conf
Clearing the configuration file: /config/nginx/nginx.conf
Clearing the configuration file: /config/core/env
Clearing the configuration file: /config/core/app.conf
Clearing the configuration file: /config/registry/passwd
Clearing the configuration file: /config/registry/config.yml
Clearing the configuration file: /config/registryctl/env
Clearing the configuration file: /config/registryctl/config.yml
Clearing the configuration file: /config/db/env
Clearing the configuration file: /config/jobservice/env
Clearing the configuration file: /config/jobservice/config.yml
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
loaded secret from file: /data/secret/keys/secretkey
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir


Note: stopping existing Harbor instance ...
WARN[0000] /opt/harbor/docker-compose.yml: `version` is obsolete


[Step 5]: starting Harbor ...
WARN[0000] /opt/harbor/docker-compose.yml: `version` is obsolete
[+] Running 10/10
 ✔ Network harbor_harbor        Created                                                                                 0.2s
 ✔ Container harbor-log         Started                                                                                 1.1s
 ✔ Container registry           Started                                                                                 3.2s
 ✔ Container redis              Started                                                                                 3.4s
 ✔ Container harbor-db          Started                                                                                 3.4s
 ✔ Container registryctl        Started                                                                                 3.2s
 ✔ Container harbor-portal      Started                                                                                 3.0s
 ✔ Container harbor-core        Started                                                                                 4.2s
 ✔ Container harbor-jobservice  Started                                                                                 5.3s
 ✔ Container nginx              Started                                                                                 5.1s
✔ ----Harbor has been installed and started successfully.----

稍等一会,如果所有容器的状态都是 healthy ,说明正常

登录WEB界面:http://192.168.108.30

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用

Harbor 里功能比较多,常用的有项目、用户管理、项目定额。

  • 项目:可以针对不同的项目单独创建,每个项目都有自己的镜像地址
  • 用户管理:可以维护用户,不同的项目可以设置不同的维护人员
  • 项目定额:设置项目对应的镜像仓库最大空间容量

下面就按照步骤将一个镜像推送到 Harbor 中。

1、在用户管理中创建名称为 images_admin 的用户:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在项目中创建名称为cloud的项目,并添加 images_admin 为项目管理员

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将内网服务器 IP 和端口配置到 daemon.json 文件中,执行下面命令进行配置

[root@docker ~]# vim /etc/docker/daemon.json
{
    "insecure-registries": ["192.168.108.30"],
    "registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}

[root@docker ~]# systemctl restart docker

#重新执行安装命令
[root@docker harbor]# ./install.sh

登录服务器

[root@docker ~]# docker login 192.168.108.30
Username: images_admin
Password:Cloud12#$
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

登录后家目录下会有一个.docker文件夹

[root@docker ~]# cd ~/.docker/
[root@docker .docker]# pwd
/root/.docker
[root@docker .docker]# cat config.json
{
        "auths": {
                "192.168.108.30": {
                        "auth": "aW1hZ2VzX2FkbWluOkNsb3VkMTIjJA=="
                },
                "swr.cn-north-4.myhuaweicloud.com": {
                        "auth": "Y24tbm9ydGgtNEBMUVhBVjU4MENES1A3SUoxTDREMzpmM2NlMTJlODY4ODVkN2JkZWZlYmFiMWI1N2RmZDBiYjJiM2MxZTEyNjUxYWQ1ZTk1ODY1Nzg4MTczYzI4OTJj"
                }
        }
}

上传镜像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[root@docker .docker]# docker tag nginx:latest 192.168.108.30/cloud/nginx:latest
[root@docker .docker]# docker push 192.168.108.30/cloud/nginx:latest
The push refers to repository [192.168.108.30/cloud/nginx]
11de3d47036d: Pushed
16907864a2d0: Pushed
2bdf51597158: Pushed
0fc6bb94eec5: Pushed
eda13eb24d4c: Pushed
67796e30ff04: Pushed
8e2ab394fabf: Pushed
latest: digest: sha256:596c783ac62b9a43c60edb876fe807376cd5022a4e25e89b9a9ae06c374299d4 size: 1778

镜像格式:SERVER/PROJECT/PATH/TO/IMAGE/IMAGE:TAG

下载镜像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[root@docker .docker]# docker pull 192.168.108.30/cloud/nginx
Using default tag: latest
latest: Pulling from cloud/nginx
a2318d6c47ec: Pull complete
095d327c79ae: Pull complete
bbfaa25db775: Pull complete
7bb6fb0cfb2b: Pull complete
0723edc10c17: Pull complete
24b3fdc4d1e3: Pull complete
3122471704d5: Pull complete
Digest: sha256:596c783ac62b9a43c60edb876fe807376cd5022a4e25e89b9a9ae06c374299d4
Status: Downloaded newer image for 192.168.108.30/cloud/nginx:latest
192.168.108.30/cloud/nginx:latest

卸载harbor

清理容器

[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker compose down
WARN[0000] /opt/harbor/docker-compose.yml: `version` is obsolete
[+] Running 10/10
 ✔ Container nginx              Removed                                                                                 0.5s
 ✔ Container registryctl        Removed                                                                                 0.5s
 ✔ Container harbor-jobservice  Removed                                                                                 0.0s
 ✔ Container harbor-core        Removed                                                                                 0.4s
 ✔ Container harbor-portal      Removed                                                                                 0.4s
 ✔ Container redis              Removed                                                                                 0.5s
 ✔ Container registry           Removed                                                                                 0.4s
 ✔ Container harbor-db          Removed                                                                                 0.5s
 ✔ Container harbor-log         Removed                                                                                10.5s
 ✔ Network harbor_harbor        Removed 

清理镜像

[root@docker harbor]# docker images |grep harbor|awk '{print $1":"$2}' | xargs docker rmi

清理harbor使用的目录/data,由prepare脚本定义

[root@docker harbor]# rm -rf /data

删除软件包

[root@docker opt]# cd
[root@docker ~]# ls
anaconda-ks.cfg  harbor  harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -f harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -rf /opt/harbor/

至此,Docker 镜像的内容就讨论完了,下节我们对这部分做个小结。


021 Docker镜像小结

本节我们对 Docker 镜像做个小结。

这一部分我们首先讨论了镜像的分层结构,然后学习了如何构建镜像,最后实践使用 Docker Hub 和本地 registry。

下面是镜像的常用操作子命令:

images 显示镜像列表

history 显示镜像构建历史

commit 从容器创建新镜像

build 从 Dockerfile 构建镜像

tag 给镜像打 tag

pull 从 registry 下载镜像

push 将 镜像 上传到 registry

rmi 删除 Docker host 中的镜像

search 搜索 Docker Hub 中的镜像

除了 rmi 和 search,其他命令都已经用过了。

rmi

rmi 只能删除 host 上的镜像,不会删除 registry 的镜像。

如果一个镜像对应了多个 tag,只有当最后一个 tag 被删除时,镜像才被真正删除。例如 host 中 busybox镜像有三个 tag:

[root@docker ~]# docker images busybox
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
busybox      latest    6fd955f66c23   16 months ago   4.26MB

[root@docker ~]# docker tag busybox:latest busybox:v1

[root@docker ~]# docker tag busybox:latest busybox:v2

[root@docker ~]# docker images busybox
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
busybox      latest    6fd955f66c23   16 months ago   4.26MB
busybox      v1        6fd955f66c23   16 months ago   4.26MB
busybox      v2        6fd955f66c23   16 months ago   4.26MB

删除其中 busybox:latest 只是删除了 latest tag,镜像本身没有删除。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

只有当 busybox:v1busybox:v2也被删除时,整个镜像才会被删除。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

search

search 让我们无需打开浏览器,在命令行中就可以搜索 Docker Hub 中的镜像。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当然,如果想知道镜像都有哪些 tag,还是得访问 Docker Hub。

保存本地镜像为文件-save

docker默认使用overlay2存储驱动存储镜像。

[root@docker ~]# docker info | grep 'Storage Driver'
 Storage Driver: overlay2

镜像存储在本地/var/lib/docker/overlay2,通过文件系统层面拷贝image,操作复杂。可以使用save命令,将本地镜像保存为单个文件,并分享给他人使用。

[root@docker ~]# docker save --help

Usage:  docker save [OPTIONS] IMAGE [IMAGE...]

Save one or more images to a tar archive (streamed to STDOUT by default)

Aliases:
  docker image save, docker save

Options:
  -o, --output string   Write to a file, instead of STDOUT

示例:

[root@docker ~]# docker save httpd -o httpd.tar         #httpd是镜像名  httpd.tar是要保存的文件名
[root@docker ~]# docker save httpd hello-world -o images.tar   #将httpd,hello-world镜像保存为images.tar
[root@docker ~]# ls
httpd.tar  images.tar
将本地镜像文件导入本地-load
[root@docker ~]# docker load --help

Usage:  docker load [OPTIONS]

Load an image from a tar archive or STDIN

Aliases:
  docker image load, docker load

Options:
  -i, --input string   Read from tar archive file, instead of STDIN
  -q, --quiet          Suppress the load output

示例:删除本地镜像,并导入本地镜像文件

[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
httpd         latest    90f191b9781e   11 days ago    148MB
hello-world   latest    74cc54e27dc4   6 months ago   10.1kB
[root@docker ~]# docker rmi httpd:latest hello-world:latest
Untagged: httpd:latest
Untagged: httpd@sha256:f84fe51ff5d35124e024f51215b443b16c939b24eae747025a515200e71c7d07
Deleted: sha256:90f191b9781e01f5cd601af7b32d4ebb46770d1a98fa9170c328f9a78458b758
Deleted: sha256:8cbdaf91f3d9b2916bd85a36c608c8b652176b92266a6c51ead6c52f487b9eb5
Deleted: sha256:352b0ea3b9e318a2111200ed85540548a23873ce5ab5e6076b1dcef0110724ce
Deleted: sha256:7810a27010681e9307dae49c3673a021928add80b99e43937d79a3c5322cb862
Deleted: sha256:3c75e1b632ae15a9a14d7527fb134de5d45b2abcf3eef1cfaa057d702b957dba
Deleted: sha256:4eabd365f7baf2356d8d27adb4a182e45fca9dfc1d5533e93832c243135a5aa9
Deleted: sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3
Untagged: hello-world:latest
Untagged: hello-world@sha256:ec153840d1e635ac434fab5e377081f17e0e15afab27beb3f726c3265039cfff
Deleted: sha256:74cc54e27dc41bb10dc4b2226072d469509f2f22f1a3ce74f4a59661a1d44602
Deleted: sha256:63a41026379f4391a306242eb0b9f26dc3550d863b7fdbb97d899f6eb89efe72
[root@docker ~]# docker images         #本地没有镜像
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

删除本地正在使用的镜像需要选项-f

导入镜像

[root@docker ~]# docker load -i images.tar
1bb35e8b4de1: Loading layer  77.88MB/77.88MB
6c5ea8a96778: Loading layer   2.56kB/2.56kB
5f70bf18a086: Loading layer  1.024kB/1.024kB
785236f38f5b: Loading layer  11.41MB/11.41MB
5ca968893b91: Loading layer  62.99MB/62.99MB
b4558c4e936a: Loading layer  3.584kB/3.584kB
Loaded image: httpd:latest
63a41026379f: Loading layer  11.78kB/11.78kB
Loaded image: hello-world:latest
[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
httpd         latest    90f191b9781e   11 days ago    148MB
hello-world   latest    74cc54e27dc4   6 months ago   10.1kB

说明:如果本地镜像名与导入的镜像重名,则本地的镜像会被覆盖。

[root@docker ~]# docker rm -f $(docker ps -aq)      #删除所有容器

[root@docker ~]# docker rmi -f $(docker images -aq)   #删除所有镜像

至此,Docker 镜像已经讨论完了,下节我们深入讨论容器。


第9章 Docker-compose

我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。如果每个容器都要按顺序手动启停,那么维护工作量将会很大,而且工作效率也很低。

Docker Compose 可以轻松、高效地管理容器,它是一个用于定义和运行多容器的管理工具。

它通过一个单独的 docker-compose.yml 模板文件(YAML 格式)定义一组相关联资源集。

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

Compose 项目由 Python 编写(后用Go语言重写),实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。

image-20250730185150375

命令说明

[root@docker ~]# docker compose -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker compose [OPTIONS] COMMAND

Define and run multi-container applications with Docker

Options:
      --all-resources              Include all resources, even those not used by services
      --ansi string                Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --dry-run                    Execute command in dry run mode
      --env-file stringArray       Specify an alternate environment file
  -f, --file stringArray           Compose configuration files
      --parallel int               Control max parallelism, -1 for unlimited (default -1)
      --profile stringArray        Specify a profile to enable
      --progress string            Set type of progress output (auto, tty, plain, quiet) (default "auto")
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the, first specified, Compose file)
  -p, --project-name string        Project name

Commands:
  attach      Attach local standard input, output, and error streams to a service's running container
  build       Build or rebuild services
  config      Parse, resolve and render compose file in canonical format
  cp          Copy files/folders between a service container and the local filesystem
  create      Creates containers for a service
  down        Stop and remove containers, networks
  events      Receive real time events from containers
  exec        Execute a command in a running container
  images      List images used by the created containers
  kill        Force stop service containers
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart service containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service
  scale       Scale services
  start       Start services
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information
  wait        Block until the first service container stops
  watch       Watch build context for service and rebuild/refresh containers when files are updated

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

version

[root@docker ~]# docker compose version
Docker Compose version v2.27.0

Compose 模板

模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。但大家不用担心,这里面大部分指令跟 docker run 相关参数的含义都是类似的。

默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。

模板文件结构

  • version:用来定义模板文件的版本,不同版本的模板,格式也不一样。
  • 资源列表:用来定义资源清单,包括service、secret、network、volume等。
  • 注释行: # 开头的注释行。

示例:使用版本2模板,定义一个使用httpd镜像的services。

version: "2"

services:
  webapp:
    image: httpd

详细结构参考官方

Compose文档

实战-Wordpress

回顾一下如果用docker run改如何操作:

[root@docker ~]# docker run -tid --name db --restart always -v /db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 -e MYSQL_DATABASE=wordpress mysql
d3fa1d9e6ecc285427b38bca95130cade90ca69ee9487825db92b3bc8af4c995
[root@docker ~]# docker run -tid --name blog -v /web:/var/www/html -p 80:80 --link db -e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=huawei -e WORDPRESS_DB_NAME=wordpress wordpress
b5b80bd69f57bff576415f2e449a23fe6cb37be353f9b4b69d24d60a2fb9a6e1
[root@docker ~]#
[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                               NAMES
b5b80bd69f57   wordpress   "docker-entrypoint.s…"   13 seconds ago   Up 12 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   blog
d3fa1d9e6ecc   mysql       "docker-entrypoint.s…"   26 seconds ago   Up 25 seconds   3306/tcp, 33060/tcp                 db

MYSQL_DATABASE=wordpress

测试效果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过docker compose来统一管理这两个容器呢?

假设新建一个名为 wordpress 的文件夹,然后进入这个文件夹,创建 docker-compose.yml 文件

# 删除之前的环境
[root@docker ~]# docker rm -f $(docker ps -aq)

# 通过docker compose实现多个容器一起启动
[root@docker ~]# mkdir wordpress
[root@docker ~]# cd wordpress/
[root@docker wordpress]# vim docker-compose.yml
services:
  blog:                                  #服务名字,相当于docker run的时候指定的一个名称
    image: wordpress:latest            #必选,镜像的名字
    restart: always
    links:
      - db
    ports:                            #可选,等价于 docker run 里的 -p 选项指定端口映射
      - "80:80"
    environment:           #可选,等价于 docker run 里的 --env 选项设置环境变量
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=huawei
      - WORDPRESS_DB_NAME=wordpress

  db:
    image: mysql:latest
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=huawei
      - MYSQL_DATABASE=wordpress
            
[root@docker wordpress]# docker compose config -q    #检测语法

后端运行

[root@docker wordpress]# docker compose up -d
[+] Running 3/3
 ✔ Network wordpress_default   Created     0.0s                                                                                 
 ✔ Container wordpress-db-1    Started     0.3s                                                                                 
 ✔ Container wordpress-blog-1  Started     0.6s                                                                           

查看现象

[root@docker wordpress]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED              STATUS              PORTS                               NAMES
85b438b2ff89   wordpress:latest   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   wordpress-blog-1
3c340ed1e299   mysql:latest       "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp                 wordpress-db-1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

nt: #可选,等价于 docker run 里的 --env 选项设置环境变量
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=huawei
- WORDPRESS_DB_NAME=wordpress

db:
image: mysql:latest
restart: always
environment:
- MYSQL_ROOT_PASSWORD=huawei
- MYSQL_DATABASE=wordpress

[root@docker wordpress]# docker compose config -q #检测语法


后端运行

```bash
[root@docker wordpress]# docker compose up -d
[+] Running 3/3
 ✔ Network wordpress_default   Created     0.0s                                                                                 
 ✔ Container wordpress-db-1    Started     0.3s                                                                                 
 ✔ Container wordpress-blog-1  Started     0.6s                                                                           

查看现象

[root@docker wordpress]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED              STATUS              PORTS                               NAMES
85b438b2ff89   wordpress:latest   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   wordpress-blog-1
3c340ed1e299   mysql:latest       "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp                 wordpress-db-1

[外链图片转存中…(img-hvAD6Viv-1778760612185)]

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐