当前位置:   article > 正文

Linux——Dockerfile部分参数(1)

Linux——Dockerfile部分参数(1)

在这里我们来整理一下docker容器、dockerfile、docker镜像的关系:

dockerfile是面向开发的,发布项目做镜像的时候就要编写dockerfile文件。
dockerfile:构建文件,定义了一切的步骤,源代码。
dockerImanges:通过dockerfile构建生成的镜像,最终发布和运行的产品。
docker容器:容器就是镜像运行起来提供服务的

一、Dockerfile 指令选项。

  1. Dockerfile 指令选项:
  2. FROM #基础镜像 。 (centos)
  3. MAINTAINER #镜像的作者和邮箱。(已被弃用,结尾介绍代替词)
  4. RUN #镜像构建的时候需要执行的命令。
  5. CMD #类似于 RUN 指令,用于运行程序(只有最后一个会生效,可被替代)
  6. EXPOSE #对外开放的端口。
  7. ENV #设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
  8. ADD # 步骤:tomcat镜像,这个tomcat压缩包。添加内容。
  9. COPY #复制指令,将文件拷贝到镜像中。
  10. VOLUME #设置卷,挂载的主机目录。
  11. USER #用于指定执行后续命令的用户和用户组,
  12. 这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
  13. WORKDIR #工作目录(类似CD命令)。
  14. ENTRYPOINT #类似于 CMD 指令,但其不会被 docker run
  15. 的命令行参数指定的指令所覆盖,会追加命令。
  16. ONBUILD #当构建一个被继承Dokcerfile,就会运行ONBUILD的指令。出发执行。
  17. 注意:CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
  18. CMD 在docker run 时运行。
  19. RUN 是在 docker build。
  20. 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
  21. CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
  22. 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
  23. LABEL(MAINTALNER已经被弃用了,目前是使用LABEL代替)
  24. LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
  25. LABEL <key>=<value> <key>=<value> <key>=<value> ...
  26. 比如我们可以添加镜像的作者:
  27. LABEL org.opencontainers.image.authors="runoob"

ENV 设置环境变量:

格式有两种:

    ENV <key> <value>

ENV <key1>=<value1> <key2>=<value2>...

这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

ARG 构建参数:

格式:ARG <参数名>[=<默认值>]

构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

EXPOSE 声明端口:

格式为 EXPOSE <端口1> [<端口2>...]。

EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

WORKDIR 指定工作目录:

格式为 WORKDIR <工作目录路径>。

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录

  1. [root@docker1 ~]# mkdir /test-multi
  2. [root@docker1 ~]# cd /test-multi
  3. [root@docker1 test-multi]# vim Dockerfile
  4. [root@docker1 test-multi]# cat Dockerfile
  5. FROM centos
  6. ENV aa=1 bb=2 cc=3 envdir=/a/b/c
  7. ARG dd=4 ee=5 ff=6 argdir=/a/b/c
  8. WORKDIR $argdir
  9. COPY test.sh $envdir
  10. RUN echo $aa $bb $cc $dd $dd $ff > /var.txt
  11. CMD ["./test.sh"]
  12. [root@docker1 test-multi]#
  13. [root@docker1 test-multi]# vim test.sh
  14. [root@docker1 test-multi]# cat test.sh
  15. #! /bin/bash
  16. echo output env vars:
  17. echo $aa $bb $cc
  18. echo output arg vars:
  19. echo $dd $ee $ff
  20. echo current work directory:
  21. pwd
  22. [root@docker1 test-multi]#
  23. [root@docker1 test-multi]# chmod +x test.sh
  24. [root@docker1 test-multi]# docker build -t mymulti:v1 .
  25. ……
  26. => [2/4] WORKDIR /a/b/c 0.1s
  27. => [3/4] COPY test.sh /a/b/c 0.0s
  28. => [4/4] RUN echo 1 2 3 4 4 6 > /var.txt
  29. ……
  30. 验证:
  31. [root@docker1 test-multi]# docker run --rm mymulti:v1
  32. output env vars:
  33. 1 2 3
  34. output arg vars:
  35. current work directory:
  36. /a/b/c
  37. [root@docker1 test-multi]#

VOLUME 定义匿名卷:

格式为:

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

    VOLUME <路径>

之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

  1. [root@docker1 ~]# mkdir /test_volume
  2. [root@docker1 ~]# cd /test_volume
  3. [root@docker1 test_volume]#
  4. [root@docker1 test_volume]# cat Dockerfile
  5. from alpine
  6. RUN mkdir /test && touch /test/test.txt
  7. [root@docker1 test_volume]# docker build -t myvolume:v1 .
  8. [root@docker1 test_volume]# docker run -it myvolume:v1 sh
  9. / # cat /test/test.txt
  10. / # echo 123 > /test/test.txt
  11. / # cat /test/test.txt
  12. 123
  13. / # exit
  14. [root@docker1 test_volume]# docker ps -a
  15. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  16. c2de419ef2d3 myvolume:v1 "sh" 36 seconds ago Exited (0) 3 seconds ago zealous_lumiere
  17. [root@docker1 test_volume]#
  18. [root@docker1 test_volume]# docker start zealous_lumiere
  19. zealous_lumiere
  20. [root@docker1 test_volume]# docker ps -a
  21. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  22. c2de419ef2d3 myvolume:v1 "sh" About a minute ago Up 7 seconds zealous_lumiere
  23. [root@docker1 test_volume]# docker exec -it zealous_lumiere sh
  24. / # cat /test/test.txt
  25. 123
  26. / # exit
  27. [root@docker1 test_volume]# docker stop zealous_lumiere
  28. zealous_lumiere
  29. [root@docker1 test_volume]# docker rm zealous_lumiere
  30. zealous_lumiere
  31. [root@docker1 test_volume]#注:容器没删除,则数据存在
  32. 重新创建的容器没有之前的数据,数据是非持久化的:
  33. [root@docker1 test_volume]# docker run -it --name mv1 myvolume:v1 sh
  34. / # cat /test/test.txt
  35. / # exit
  36. [root@docker1 test_volume]# docker rm mv1
  37. mv1
  38. [root@docker1 test_volume]#

匿名卷:

[root@docker1 test_volume]# cat Dockerfile

from alpine

RUN mkdir /test && touch /test/test.txt

VOLUME /test

[root@docker1 test_volume]#

[root@docker1 test_volume]# docker build -t myvolume:v2 .

[root@docker1 test_volume]# docker run --rm -d myvolume:v2 sleep 100

2b2922070b503298b4195c7fa7007a6b0f3f51528f035098beb4d32801288c11

[root@docker1 test_volume]#

[root@docker1 test_volume]# docker run --rm -d myvolume:v2 sleep 100

2b2922070b503298b4195c7fa7007a6b0f3f51528f035098beb4d32801288c11

[root@docker1 test_volume]# docker ps -a

CONTAINER ID   IMAGE         COMMAND       CREATED          STATUS          PORTS     NAMES

2b2922070b50   myvolume:v2   "sleep 100"   13 seconds ago   Up 13 seconds             eloquent_agnesi

[root@docker1 test_volume]# docker inspect eloquent_agnesi | grep -i -A 5 mounts

        "Mounts": [

            {

                "Type": "volume",

                "Name": "581af512e8399049c748fb8f2918df6041435aba355b83618537accbada60f72",

                "Source": "/var/lib/docker/volumes/581af512e8399049c748fb8f2918df6041435aba355b83618537accbada60f72/_data",

                "Destination": "/test",

[root@docker1 test_volume]# docker volume ls

DRIVER    VOLUME NAME

local     581af512e8399049c748fb8f2918df6041435aba355b83618537accbada60f72

[root@docker1 test_volume]#

[root@docker1 test_volume]# docker ps -a(容器停止后自动删除了)

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

[root@docker1 test_volume]# docker volume ls 匿名卷生命周期跟随容器

DRIVER    VOLUME NAME

[root@docker1 test_volume]#

不在dockerfile定义volume也可以启用匿名卷:

[root@docker1 test_volume]# docker run -d -v /opt alpine sleep 200

37d9216c975dac39d75845bfa14db0b983d8eb710d1072ce75d16b5d609d54db

[root@docker1 test_volume]# docker volume ls

DRIVER    VOLUME NAME

local     847f7e6cc35beca7f50a9a6b41c28a84b7d60abfabd3e7677636f84f5d8694a4

[root@docker1 test_volume]#

[root@docker1 test_volume]# docker rmi myvolume:v2

Untagged: myvolume:v2

Deleted: sha256:6ccc8e360eed876906d7bf5fdd8109a995e7afe11b8595f00ec594db81760664

[root@docker1 test_volume]#

持久存储:推荐使用命名卷或者宿主机目录(或共享的目录)

数据卷管理:数据持久化

这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

    数据卷(Volumes)

挂载主机目录 (Bind mounts)

  1. [root@docker1 test_volume]# docker volume ls
  2. DRIVER VOLUME NAME
  3. [root@docker1 test_volume]#
  4. [root@docker1 test_volume]# docker volume create my-vol1
  5. my-vol1
  6. [root@docker1 test_volume]# docker volume ls
  7. DRIVER VOLUME NAME
  8. local my-vol1
  9. [root@docker1 test_volume]#
  10. [root@docker1 test_volume]# docker inspect my-vol1
  11. [
  12. {
  13. "CreatedAt": "2024-05-21T09:32:49+08:00",
  14. "Driver": "local",
  15. "Labels": null,
  16. "Mountpoint": "/var/lib/docker/volumes/my-vol1/_data",
  17. "Name": "my-vol1",
  18. "Options": null,
  19. "Scope": "local"
  20. }
  21. ]
  22. [root@docker1 test_volume]#
  23. [root@docker1 test_volume]# cat Dockerfile
  24. from alpine
  25. RUN mkdir /test && touch /test/test.txt
  26. VOLUME /test
  27. [root@docker1 test_volume]#
  28. [root@docker1 test_volume]# docker build -t myvolume:v2 .
  29. [root@docker1 test_volume]# docker inspect myvolume:v2| grep -i -A 2 volumes
  30. "Volumes": {
  31. "/test": {}
  32. },
  33. [root@docker1 test_volume]#
  34. [root@docker1 test_volume]# docker run -it --rm -v my-vol1:/test myvolume:v2 sh
  35. / # cat /test/test.txt
  36. / # echo 123 > /test/test.txt
  37. / # echo 456 > /test/test2.txt
  38. / # exit
  39. [root@docker1 test_volume]# docker ps -a
  40. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  41. [root@docker1 test_volume]# docker run -it --rm -v my-vol1:/test myvolume:v2 sh
  42. / # cat /test/test.txt
  43. 123
  44. / # cat /test/test2.txt
  45. 456
  46. / # exit
  47. [root@docker1 test_volume]#
  48. [root@docker1 ~]# ls /var/lib/docker/volumes/my-vol1/_data
  49. test2.txt test.txt
  50. [root@docker1 ~]#

  1. [root@docker1 test_volume]# docker run -it --rm --mount source=my-vol1,target=/test myvolume:v2 sh
  2. / # cat /test/test2.txt
  3. 456
  4. / # exit
  5. [root@docker1 test_volume]#

  1. Linux目录挂载:加bind选项
  2. [root@docker1 ~]# mkdir /a /b
  3. [root@docker1 ~]# touch /b/b.txt
  4. [root@docker1 ~]# mount /a /b
  5. mount: /b: /a is not a block device.
  6. [root@docker1 ~]# mount -o bind /a /b
  7. [root@docker1 ~]# ls /b
  8. [root@docker1 ~]# umount /b
  9. [root@docker1 ~]# ls /b
  10. b.txt
  11. [root@docker1 ~]#

  1. [root@docker1 test_volume]# mkdir /testmount
  2. [root@docker1 test_volume]# echo 3 > /testmount/3.txt
  3. [root@docker1 test_volume]# docker run -it --rm --mount type=bind,source=/testmount,target=/test myvolume:v2 sh
  4. / # ls /test
  5. 3.txt
  6. / # echo 33 > /test/3.txt
  7. / # exit
  8. [root@docker1 test_volume]# docker run -it --rm --mount type=bind,source=/testmount,target=/test,readonly myvolume:v2 sh
  9. / # cat /test/3.txt
  10. 33
  11. / # echo 333 > /test/3.txt
  12. sh: can't create /test/3.txt: Read-only file system
  13. / # exit
  14. [root@docker1 test_volume]#

容器共享存储:

  1. [root@docker1 ~]# ls /webdir/
  2. Dockerfile page1.html page2.html
  3. [root@docker1 ~]# cat /webdir/page1.html
  4. page1
  5. [root@docker1 ~]# cat /webdir/page2.html
  6. page2
  7. [root@docker1 ~]#
  8. [root@docker1 test_volume]# docker run -d --rm --name nginx1 -v /webdir:/usr/share/nginx/html -p 81:80 nginx:latest
  9. 6b9920b4b7d3f666c486a1d372b45fa01b63cd64252fbdc629053aff0b953ce8
  10. [root@docker1 test_volume]# docker run -d --rm --name nginx2 -v /webdir:/usr/share/nginx/html -p 82:80 nginx:latest
  11. 9666d000921ee7d78edaf8fc0f91ab4127b68ca9195c70601fa3eaf628c79616
  12. [root@docker1 test_volume]# curl 127.0.0.1:81/page1.html
  13. page1
  14. [root@docker1 test_volume]# curl 127.0.0.1:82/page1.html
  15. page1
  16. [root@docker1 test_volume]# docker stop nginx1
  17. nginx1
  18. [root@docker1 test_volume]# docker stop nginx2
  19. nginx2
  20. [root@docker1 test_volume]#

使用local以外的volume driver:

使用vieux/sshfs:

安装插件:

  1. [root@docker1 test_volume]# docker plugin install --grant-all-permissions vieux/sshfs
  2. latest: Pulling from vieux/sshfs
  3. Digest: sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811
  4. 52d435ada6a4: Complete
  5. Installed plugin vieux/sshfs
  6. [root@docker1 test_volume]#
  7. [root@docker2 ~]# mkdir /sharedir
  8. [root@docker2 ~]# touch /sharedir/share.txt

创建卷:

  1. [root@docker1 test_volume]# docker volume create --driver vieux/sshfs -o sshcmd=root@192.168.99.129:/sharedir -o password=1 sshvolume
  2. sshvolume
  3. [root@docker1 test_volume]#
  4. [root@docker1 test_volume]# docker volume ls
  5. DRIVER VOLUME NAME
  6. local my-vol1
  7. vieux/sshfs:latest sshvolume
  8. [root@docker1 test_volume]#
  9. [root@docker1 test_volume]# docker run -it --rm -v sshvolume:/opt alpine sh
  10. / # ls /opt/
  11. share.txt
  12. / # exit
  13. [root@docker1 test_volume]#
  14. 官方参考如下:
  15. docker run -d \
  16. --name sshfs-container \
  17. --volume-driver vieux/sshfs \
  18. --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
  19. nginx:latest
  1. 使用基于nfs的卷:
  2. 官方参考如下:
  3. Nfsv3
  4. docker service create -d \
  5. --name nfs-service \
  6. --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,volume-opt=o=addr=10.0.0.10' \
  7. nginx:latest
  8. nfsv4
  9. docker service create -d \
  10. --name nfs-service \
  11. --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
  12. nginx:latest
  13. 配置nfs服务,自行解决防火墙和selinux:
  14. [root@docker2 ~]# mkdir /nfs1 /nfs2
  15. [root@docker2 ~]# chmod 777 /nfs1 /nfs2
  16. [root@docker2 ~]# vim /etc/exports
  17. [root@docker2 ~]# cat /etc/exports
  18. /nfs1 *(rw,no_root_squash)
  19. /nfs2 *(rw,no_root_squash)
  20. [root@docker2 ~]#
  21. [root@docker2 ~]# systemctl start nfs-server.service
  22. [root@docker1 test_volume]# yum -y install nfs-utils
  23. [root@docker1 test_volume]# showmount -e 192.168.99.129
  24. Export list for 192.168.99.129:
  25. /nfs2 *
  26. /nfs1 *
  27. [root@docker1 test_volume]#

手动创建卷:

  1. [root@docker1 test_volume]# docker volume create --driver local -o type=nfs -o device=:/nfs1 -o o=addr=192.168.99.129,rw,nfsvers=4 nfs1volume
  2. nfs1volume
  3. [root@docker1 test_volume]#
  4. [root@docker1 test_volume]# docker volume ls
  5. DRIVER VOLUME NAME
  6. local my-vol1
  7. local nfs1volume
  8. vieux/sshfs:latest sshvolume
  9. [root@docker1 test_volume]#
  10. 验证:
  11. [root@docker1 test_volume]# docker run -it --rm --mount 'type=volume,source=nfs1volume,target=/opt,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/nfs1,"volume-opt=o=addr=192.168.99.129,rw,nfsvers=4"' --privileged alpine sh
  12. / # touch /opt/1.txt
  13. / # exit
  14. [root@docker1 test_volume]#
  15. [root@docker2 ~]# ls /nfs1
  16. 1.txt
  17. [root@docker2 ~]#
  18. [root@docker1 test_volume]# docker run -it --rm --mount 'type=volume,source=nfs1volume,target=/opt' --privileged alpine sh
  19. / # ls /opt/
  20. 1.txt
  21. / # exit
  22. [root@docker1 test_volume]#

创建容器时自动创建nfs卷:

  1. [root@docker1 ~]# docker volume ls
  2. DRIVER VOLUME NAME
  3. local my-vol1
  4. local nfs1volume
  5. vieux/sshfs:latest sshvolume
  6. [root@docker1 ~]#
  7. [root@docker1 test_volume]# docker run -it --rm --mount 'type=volume,source=nfs2volume,target=/opt,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/nfs2,"volume-opt=o=addr=192.168.99.129,rw,nfsvers=4"' --privileged alpine sh
  8. / # touch /opt/2.txt
  9. / # exit
  10. [root@docker1 test_volume]#
  11. [root@docker1 test_volume]# docker volume ls
  12. DRIVER VOLUME NAME
  13. local my-vol1
  14. local nfs1volume
  15. local nfs2volume
  16. vieux/sshfs:latest sshvolume
  17. [root@docker1 test_volume]#
  18. [root@docker2 ~]# ls /nfs2
  19. 2.txt
  20. [root@docker2 ~]#

练习:使用samba共享提供持久存储

官方参考:

docker volume create \

--driver local \

--opt type=cifs \

--opt device=//uxxxxx.your-server.de/backup \

--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \

--name cif-volume

其他数据卷内容参考:Volumes | Docker DocsLearn how to create, manage, and use volumes instead of bind mounts for persisting data generated and used by Docker.icon-default.png?t=N7T8https://docs.docker.com/storage/volumes/

USER 指定当前用户:

格式:USER <用户名>[:<用户组>]

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

  1. [root@docker1 test_volume]# vim Dockerfile
  2. [root@docker1 test_volume]# cat Dockerfile
  3. from centos
  4. RUN id > /user.txt && chmod 777 /user.txt
  5. RUN useradd test
  6. USER test
  7. RUN id >> /user.txt
  8. CMD cat /user.txt
  9. [root@docker1 test_volume]#
  10. [root@docker1 test_volume]# docker build -t test-user:v1 .
  11. [root@docker1 test_volume]# docker run -it --rm test-user:v1
  12. uid=0(root) gid=0(root) groups=0(root)
  13. uid=1000(test) gid=1000(test) groups=1000(test)
  14. [root@docker1 test_volume]#

HEALTHCHECK 健康检查:

格式:

 HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令

 HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。

  1. [root@docker1 ~]# mkdir /test-health
  2. [root@docker1 ~]# cd /test-health
  3. [root@docker1 test-health]# vim Dockerfile
  4. [root@docker1 test-health]# cat Dockerfile
  5. FROM nginx
  6. RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
  7. HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1
  8. [root@docker1 test-health]# docker build -t myhealth:v1 .
  9. 另起一个终端,每秒刷新一次docker ps -a的输出:
  10. [root@docker1 ~]# watch -n 1 docker ps -a
  11. [root@docker1 test-health]# docker run -d --rm --name myh myhealth:v1
  12. a1fffb3d0193408d81a1db9484576a3e2df214b12d9fa19ae78da6ff875d7704
  13. [root@docker1 test-health]#
  14. [root@docker1 ~]# docker ps -a
  15. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  16. a1fffb3d0193 myhealth:v1 "/docker-entrypoint.…" 28 seconds ago Up 27 seconds (healthy) 80/tcp myh
  17. [root@docker1 ~]# 速度快,可以看到从starting到healthy的过程
  18. 为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看。
  19. [root@docker1 test-health]# docker inspect --format '{{json .State.Health}}' myh | python3 -m json.tool

模拟故障:

再容器中删除index.html,因为健康检查指令curl -fs http://localhost/ || exit 1查看的时首页,此时删除首页则访问报错,但是不能使用nginx -s stop停服务,因为nginx进程是容器的主体进程,停服务则容器退出:

  1. [root@docker1 test-health]# docker exec -it myh sh
  2. # ls /usr/share/nginx/html/index.html
  3. /usr/share/nginx/html/index.html
  4. # rm -rf /usr/share/nginx/html/index.html
  5. # exit
  6. [root@docker1 test-health]#
  7. 等待一段时间可以看到unhealthy:
  8. [root@docker1 ~]# docker ps -a
  9. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  10. cf26f8e926d2 myhealth:v1 "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (unhealthy) 80/tcp myh
  11. [root@docker1 ~]#
  12. 自行创建index.html,测试恢复为healthy的过程

  1. [root@docker1 test-health]# vim Dockerfile
  2. [root@docker1 test-health]# cat Dockerfile
  3. FROM alpine
  4. LABEL custom alpine
  5. [root@docker1 test-health]# docker build -t mylabel:v1 .
  6. [root@docker1 test-health]# docker image ls -f LABEL=custom
  7. REPOSITORY TAG IMAGE ID CREATED SIZE
  8. mylabel v1 bcefe279deed 3 months ago 7.38MB
  9. [root@docker1 test-health]#

练习

从centos基础镜像创建一个容器,安装nginx软件包,配置健康检查,如果/usr/share/nginx/html/test.html存在,则检查正常,不存在则unhealthy,验证效果

  1. [root@docker1 ~]# mkdir /test-h2
  2. [root@docker1 ~]# cd /test-h2
  3. [root@docker1 test-h2]# vim Dockerfile
  4. [root@docker1 test-h2]# docker build -t myh2 .
  5. [root@docker1 test-h2]# cat Dockerfile
  6. FROM centos
  7. RUN rm -rf /etc/yum.repos.d/* \
  8. && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
  9. && yum -y install nginx \
  10. && yum clean all \
  11. && echo test > /usr/share/nginx/html/test.html
  12. EXPOSE 80
  13. HEALTHCHECK --interval=5s --timeout=3s \
  14. CMD [ -f "/usr/share/nginx/html/test.html" ] || exit 1
  15. [root@docker1 test-h2]#
  16. 注: 此时运行容器,没有启动nginx服务,无法使用curl判定,所以使用[ -f “xxxx” ]

练习2

使用samba共享提供卷

  1. [root@docker2 ~]# mkdir /sambashare
  2. [root@docker2 ~]# yum -y install samba samba-client
  3. [root@docker2 ~]# vim /etc/samba/smb.conf
  4. [root@docker2 ~]# tail -5 /etc/samba/smb.conf
  5. [smbshare]
  6. path = /sambashare/
  7. read only = No
  8. hosts allow = 192.168.99.
  9. valid users = testuser
  10. [root@docker2 ~]#
  11. [root@docker2 ~]# chmod 777 /sambashare/
  12. [root@docker2 ~]# useradd -s /sbin/nologin testuser
  13. [root@docker2 ~]# pdbedit -a testuser
  14. new password: (redhat)
  15. retype new password:(redhat)
  16. ……
  17. [root@docker2 ~]# pdbedit -L
  18. testuser:1001:
  19. [root@docker2 ~]#
  20. [root@docker2 ~]# systemctl restart smb.service nmb.service
  21. [root@docker1 test-h2]# yum -y install samba-client
  22. 使用testuser用户和redhat密码查看192.168.99.129服务器的共享:
  23. [root@docker1 ~]# smbclient -L 192.168.99.129 -U testuser%redhat
  24. Sharename Type Comment
  25. --------- ---- -------
  26. print$ Disk Printer Drivers
  27. smbshare Disk
  28. IPC$ IPC IPC Service (Samba 4.19.4)
  29. testuser Disk Home Directories
  30. SMB1 disabled -- no workgroup available
  31. [root@docker1 ~]#
  32. [root@docker1 ~]# smbclient -L 192.168.99.129 (直接回车,使用匿名用户查看)
  33. Password for [SAMBA\root]:
  34. Anonymous login successful
  35. Sharename Type Comment
  36. --------- ---- -------
  37. print$ Disk Printer Drivers
  38. smbshare Disk
  39. IPC$ IPC IPC Service (Samba 4.19.4)
  40. SMB1 disabled -- no workgroup available
  41. [root@docker1 ~]#
  42. [root@docker1 ~]# yum -y install cifs-utils
  43. [root@docker1 ~]# mount -o username=testuser,password=redhat //192.168.99.129/smbshare /opt
  44. [root@docker1 ~]# df -h /opt
  45. Filesystem Size Used Avail Use% Mounted on
  46. //192.168.99.129/smbshare 70G 13G 58G 19% /opt
  47. [root@docker1 ~]#
  48. [root@docker1 ~]# umount /opt
  49. 创建samba共享的卷:
  50. [root@docker1 ~]# docker volume create \
  51. > --driver local \
  52. > --opt type=cifs \
  53. > --opt device=//192.168.99.129/smbshare \
  54. > --opt o=addr=192.168.99.129,username=testuser,password=redhat,file_mode=0777,dir_mode=0777 \
  55. > --name cifs-volume
  56. cifs-volume
  57. [root@docker1 ~]#
  58. [root@docker1 ~]# docker run -it --rm -v cifs-volume:/opt alpine sh
  59. / # touch /opt/cifs.txt
  60. / # exit
  61. [root@docker1 ~]#
  62. [root@docker1 ~]# docker volume ls
  63. DRIVER VOLUME NAME
  64. local cifs-volume
  65. local my-vol1
  66. [root@docker1 ~]#
  67. [root@docker2 ~]# ls /sambashare/
  68. cifs.txt
  69. [root@docker2 ~]#
  70. [root@docker1 ~]# docker volume rm cifs-volume
  71. cifs-volume
  72. [root@docker1 ~]#
  73. [root@docker2 ~]# systemctl stop smb nmb

 SHELL 指令:

  1. [root@docker1 test-shell]# cat Dockerfile
  2. from centos
  3. RUN rm -rf /etc/yum.repos.d/* \
  4. && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
  5. && yum -y install python3 \
  6. && yum clean all \
  7. && touch /result.txt
  8. COPY * /
  9. SHELL ["/usr/bin/python3"]
  10. RUN /python.py
  11. SHELL ["/bin/bash", "-c"]
  12. RUN /shell.sh
  13. CMD cat /result.txt
  14. [root@docker1 test-shell]#
  15. [root@docker1 test-shell]# cat shell.sh
  16. echo hello shell >> /result.txt
  17. [root@docker1 test-shell]# cat python.py
  18. import os
  19. with open('/result.txt', 'w') as f:
  20. f.write("hello python\n")
  21. [root@docker1 test-shell]#
  22. [root@docker1 test-shell]# docker build -t myshell:v1 .
  23. [root@docker1 test-shell]# docker run --rm myshell:v1
  24. hello python
  25. hello shell
  26. [root@docker1 test-shell]#

ONBUILD 为他人做嫁衣裳:

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。

  1. [root@docker1 ~]# mkdir /test-onbuild
  2. [root@docker1 ~]# cd /test-onbuild
  3. [root@docker1 test-onbuild]# cat start.sh
  4. #! /bin/bash
  5. shell_var=$(ls /*.sh)
  6. $shell_var
  7. [root@docker1 test-onbuild]# chmod +x start.sh
  8. [root@docker1 test-onbuild]# cat Dockerfile
  9. from centos
  10. RUN mkdir /app
  11. WORKDIR /app
  12. ONBUILD COPY *.txt /
  13. ONBUILD COPY *.sh /
  14. COPY start.sh /app
  15. CMD ["./start.sh"]
  16. [root@docker1 test-onbuild]#
  17. [root@docker1 test-onbuild]# docker build -t onbuild_base .
  18. 注:此时ONBUILD指令没有执行
  19. [root@docker1 ob1]# pwd
  20. /ob1
  21. [root@docker1 ob1]#
  22. [root@docker1 ob1]# cat shell.sh
  23. #! /bin/bash
  24. cat /1.txt > /12.txt
  25. cat /2.txt >> /12.txt
  26. cat /12.txt
  27. [root@docker1 ob1]#
  28. [root@docker1 ob1]# chmod +x shell.sh
  29. [root@docker1 ob1]# cat 1.txt
  30. 1
  31. [root@docker1 ob1]# cat 2.txt
  32. 2
  33. [root@docker1 ob1]# cat Dockerfile
  34. FROM onbuild_base:latest
  35. [root@docker1 ob1]#
  36. [root@docker1 ob1]# docker build -t ob_sub:v1 .
  37. [root@docker1 ob1]# docker run --rm ob_sub:v1
  38. 1
  39. 2
  40. [root@docker1 ob1]#
  41. [root@docker1 ob1]# mkdir /ob2
  42. [root@docker1 ob1]# cd /ob2
  43. [root@docker1 ob2]# vim jiaoben.sh
  44. [root@docker1 ob2]# cat jiaoben.sh
  45. #! /bin/bash
  46. cat /3.txt > /34.txt
  47. cat /4.txt >> /34.txt
  48. cat /34.txt
  49. [root@docker1 ob2]#
  50. [root@docker1 ob2]# chmod +x jiaoben.sh
  51. [root@docker1 ob2]# echo 3 > 3.txt
  52. [root@docker1 ob2]# echo 4 > 4.txt
  53. [root@docker1 ob2]#
  54. [root@docker1 ob2]# vim Dockerfile
  55. [root@docker1 ob2]# cat Dockerfile
  56. from onbuild_base:latest
  57. [root@docker1 ob2]#
  58. [root@docker1 ob2]# docker build -t ob_sub:v2 .
  59. [root@docker1 ob2]# docker run --rm ob_sub:v2
  60. 3
  61. 4
  62. [root@docker1 ob2]#

参考文档:

    1. Dockerfie 官方文档:https://docs.docker.com/engine/reference/builder/
    2. Dockerfile 最佳实践文档:

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

    1. Docker 官方镜像 Dockerfile:https://github.com/docker-library/docsicon-default.png?t=N7T8https://github.com/docker-library/docs

 练习:

  1. 在docker1安装httpd服务,共享页面index.html(内容为common-index)
  2. 制作基础镜像osbase:

以centos为基础,配置yum源,安装wget,拷贝脚本web.sh至/app

脚本内容:

   判断安装的web服务是什么:

       如果是httpd,则执行httpd -D FOREGROUND

       如果是nginx,则执行nginx -g “daemon off;”

在dockerfile中使用onbuild关键字,将docker1共享的index.html下载到/目录

  1. 在osbase的基础上构建镜像,安装httpd或nginx,将/index.html拷贝至网站根目录

镜像分别为os_httpd和os_nginx

在每个镜像中,有对应的ONBUILD指令,将页面文件拷贝至对应服务的网站根目录中

  1. 在os_httpd和os_nginx的基础上,构建镜像,拷贝页面至指定目录,测试访问

多阶段构建:

使用单个dockerfile可能遇到的问题:

将所有的构建过程编包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:

    镜像层次多,镜像体积较大,部署时间变长

源代码存在泄露的风险

使用一个dockerfile源码编译出hello.c的二进制文件并运行:

  1. [root@docker1 ~]# mkdir /multi-hello
  2. [root@docker1 ~]# cd /multi-hello
  3. [root@docker1 multi-hello]#
  4. [root@docker1 multi-hello]# vim hello.c
  5. [root@docker1 multi-hello]# cat hello.c
  6. #include<stdio.h>
  7. int main(void)
  8. {
  9. printf ("Hello world!\n");
  10. return 0;
  11. }
  12. [root@docker1 multi-hello]#
  13. [root@docker1 multi-hello]# cat Dockerfile
  14. FROM centos
  15. RUN rm -rf /etc/yum.repos.d/* \
  16. && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
  17. && yum -y install gcc gcc-c++ make \
  18. && yum clean all \
  19. && mkdir /app
  20. COPY hello.c /
  21. RUN gcc -o /hello /hello.c && mv /hello /app
  22. CMD ["/app/hello"]
  23. [root@docker1 multi-hello]#
  24. [root@docker1 multi-hello]# docker build -t multi-hello:v1 .
  25. [root@docker1 multi-hello]# docker run --rm multi-hello:v1
  26. Hello world!
  27. [root@docker1 multi-hello]#
  28. 此时镜像多了200M左右:
  29. [root@docker1 multi-hello]# docker image ls centos
  30. REPOSITORY TAG IMAGE ID CREATED SIZE
  31. centos latest 5d0da3dc9764 2 years ago 231MB
  32. [root@docker1 multi-hello]# docker image ls multi-hello:v1
  33. REPOSITORY TAG IMAGE ID CREATED SIZE
  34. multi-hello v1 42afade795ac 51 seconds ago 424MB
  35. [root@docker1 multi-hello]#
  36. 如果想要所需的效果,及运行二进制文件,编译环境不是必须的,所有可以分两次构建:
  37. [root@docker1 multi-hello]# ls
  38. Dockerfile hello.c
  39. [root@docker1 multi-hello]#
  40. 从容器复制文件到宿主机,只需容器存在即可,所有此处用了docker create
  41. (使用docker run也可以)
  42. [root@docker1 multi-hello]# docker create --name m1 multi-hello:v1
  43. 14285a08b091a714ae9182a61ab90d75df7437987cd2a702ce84d7cd315487da
  44. [root@docker1 multi-hello]# docker ps -a
  45. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  46. 14285a08b091 multi-hello:v1 "/app/hello" 4 seconds ago Created m1
  47. [root@docker1 multi-hello]#
  48. [root@docker1 multi-hello]# docker cp m1:/app/hello .
  49. Successfully copied 19.5kB to /multi-hello/.
  50. [root@docker1 multi-hello]# ls hello
  51. hello
  52. [root@docker1 multi-hello]#
  53. [root@docker1 multi-hello]# vim dockerfile2
  54. [root@docker1 multi-hello]# cat dockerfile2
  55. FROM centos
  56. RUN mkdir /app
  57. COPY hello /app
  58. CMD ["/app/hello"]
  59. [root@docker1 multi-hello]#
  60. [root@docker1 multi-hello]# docker build -f dockerfile2 -t multi-hello:v2 .
  61. [root@docker1 multi-hello]# docker run --rm multi-hello:v2
  62. Hello world!
  63. [root@docker1 multi-hello]#
  64. [root@docker1 multi-hello]# docker image ls multi-hello
  65. REPOSITORY TAG IMAGE ID CREATED SIZE
  66. multi-hello v2 99036d01a922 About a minute ago 231MB
  67. multi-hello v1 42afade795ac 10 minutes ago 424MB
  68. [root@docker1 multi-hello]# docker image ls centos
  69. REPOSITORY TAG IMAGE ID CREATED SIZE
  70. centos latest 5d0da3dc9764 2 years ago 231MB
  71. [root@docker1 multi-hello]#
  72. 此时multi-hello:v2实现了同样的效果,但是体积小了很多

多阶段构建即使用1个dockerfile实现上面的多次构建过程:

  1. [root@docker1 multi-hello]# rm -rf hello
  2. [root@docker1 multi-hello]# vim dockerfile3
  3. [root@docker1 multi-hello]# vim dockerfile3
  4. [root@docker1 multi-hello]# cat dockerfile3
  5. FROM centos as build1
  6. RUN rm -rf /etc/yum.repos.d/* \
  7. && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
  8. && yum -y install gcc gcc-c++ make \
  9. && yum clean all \
  10. COPY hello.c /
  11. RUN gcc -o /hello /hello.c
  12. FROM centos as build2
  13. WORKDIR /app
  14. COPY --from=build1 /hello .
  15. CMD ["/app/hello"]
  16. [root@docker1 multi-hello]#
  17. [root@docker1 multi-hello]# docker build -f dockerfile3 -t multi-hello:v3 .
  18. [root@docker1 multi-hello]# docker run --rm multi-hello:v3
  19. Hello world!
  20. [root@docker1 multi-hello]# docker image ls multi-hello
  21. REPOSITORY TAG IMAGE ID CREATED SIZE
  22. multi-hello v3 0163f8be5f45 18 seconds ago 231MB
  23. multi-hello v2 99036d01a922 17 minutes ago 231MB
  24. multi-hello v1 42afade795ac 26 minutes ago 424MB
  25. [root@docker1 multi-hello]#

练习:三阶段的构建

第一阶段构:

下载两个包glibc-static-2.28-251.el8.x86_64.rpm和libxcrypt-static-4.1.1-6.el8.x86_64.rpm

第二阶段:

从第一阶段拷贝两个包到根目录并安装,拷贝hello.c的源码到根目录

使用静态编译,如:gcc -o hello -static hello.c

第三阶段:基于空白镜像

获取第二阶段的hello二进制文件,复制到/app目录,并从cmd运行

  1. [root@docker1 ~]# docker image ls centos_stream8
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. centos_stream8 latest e502e2d948d7 18 hours ago 335MB
  4. [root@docker1 ~]#
  5. [root@docker1 ~]# mkdir /mbuild
  6. [root@docker1 ~]# cd /mbuild
  7. [root@docker1 mbuild]# vim Dockerfile
  8. [root@docker1 mbuild]# cat Dockerfile
  9. from centos_stream8 as build1
  10. RUN yum -y install wget \
  11. && wget http://rpmfind.net/linux/centos/8-stream/PowerTools/x86_64/os/Packages/glibc-static-2.28-251.el8.x86_64.rpm \
  12. && wget http://rpmfind.net/linux/centos/8-stream/PowerTools/x86_64/os/Packages/libxcrypt-static-4.1.1-6.el8.x86_64.rpm
  13. from centos_stream8 as build2
  14. COPY --from=build1 /*.rpm .
  15. COPY hello.c /
  16. RUN yum -y install gcc /glibc-static-2.28-251.el8.x86_64.rpm /libxcrypt-static-4.1.1-6.el8.x86_64.rpm \
  17. && gcc -o /hello -static /hello.c
  18. from scratch as build3
  19. WORKDIR /app
  20. COPY --from=build2 /hello /app
  21. CMD ["./hello"]
  22. [root@docker1 mbuild]#
  23. [root@docker1 mbuild]# vim hello.c
  24. [root@docker1 mbuild]# cat hello.c
  25. #include<stdio.h>
  26. int main(void)
  27. {
  28. printf ("Hello world!\n");
  29. return 0;
  30. }
  31. [root@docker1 mbuild]#
  32. [root@docker1 mbuild]# docker build -t mhello .
  33. [root@docker1 mbuild]# docker image ls mhello
  34. REPOSITORY TAG IMAGE ID CREATED SIZE
  35. mhello latest 17b68d3ec2d5 16 seconds ago 1.75MB
  36. [root@docker1 mbuild]# docker run --rm mhello
  37. Hello world!
  38. [root@docker1 mbuild]#
  39. 注:可以使用--target,构建其中某一个阶段的镜像
  40. 如:docker build --target build1 -t mhello-prepare .

练习:

在docker2部署私有仓库,并配置https

在docker1能够直接将镜像推送到docker2的仓库中即可

[root@docker2 ~]# cat /etc/docker/daemon.json

cat: /etc/docker/daemon.json: No such file or directory

[root@docker2 ~]#

[root@docker2 ~]# docker pull registry

[root@docker2 ~]# docker image ls registry

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE

registry     latest    d6b2c32a0f14   7 months ago   25.4MB

[root@docker2 ~]#

 

这里假设我们将要搭建的私有仓库地址为 docker.domain.com,下面我们介绍使用 openssl 自行签发 docker.domain.com 的站点 SSL 证书。

第一步创建 CA 私钥:

  1. [root@docker2 certs]# openssl genrsa -out "root-ca.key" 4096
  2. [root@docker2 certs]# ls root-ca.key
  3. root-ca.key
  4. [root@docker2 certs]#

 第二步利用私钥创建 CA 根证书请求文件:

  1. [root@docker2 certs]# openssl req \
  2. > -new -key "root-ca.key" \
  3. > -out "root-ca.csr" -sha256 \
  4. > -subj '/C=CN/ST=tj/L=tj/O=tj/CN=tj Docker Registry CA'
  5. [root@docker2 certs]# ls
  6. root-ca.csr root-ca.key
  7. [root@docker2 certs]#

第三步配置 CA 根证书,新建 root-ca.cnf:

  1. [root@docker2 certs]# vim root-ca.cnf
  2. [root@docker2 certs]# cat root-ca.cnf
  3. [root_ca]
  4. basicConstraints = critical,CA:TRUE,pathlen:1
  5. keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
  6. subjectKeyIdentifier=hash
  7. [root@docker2 certs]#

第四步签发根证书:

  1. [root@docker2 certs]# openssl x509 -req -days 3650 -in "root-ca.csr" \
  2. > -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
  3. > -extfile "root-ca.cnf" -extensions \
  4. > root_ca
  5. Signature ok
  6. subject=C = CN, ST = tj, L = tj, O = tj, CN = tj Docker Registry CA
  7. Getting Private key
  8. [root@docker2 certs]# ls
  9. root-ca.cnf root-ca.crt(根证书) root-ca.csr(签名请求) root-ca.key(私钥)
  10. [root@docker2 certs]#

第五步生成站点 SSL 私钥:

  1. [root@docker2 certs]# openssl genrsa -out "docker.domain.com.key" 4096
  2. Generating RSA private key, 4096 bit long modulus (2 primes)
  3. ...............................................++++
  4. ..................................................................++++
  5. e is 65537 (0x010001)
  6. [root@docker2 certs]#
  7. [root@docker2 certs]# ls
  8. docker.domain.com.key root-ca.cnf root-ca.crt root-ca.csr root-ca.key
  9. [root@docker2 certs]#

第六步使用私钥生成证书请求文件:

  1. [root@docker2 certs]# openssl req -new -key "docker.domain.com.key" -out "site.csr" -sha256 \
  2. > -subj '/C=CN/ST=tj/L=tj/O=tj/CN=docker.domain.com'
  3. [root@docker2 certs]# ls
  4. docker.domain.com.key root-ca.crt root-ca.key
  5. root-ca.cnf root-ca.csr site.csr
  6. [root@docker2 certs]#

第七步配置证书,新建 site.cnf 文件:

  1. [root@docker2 certs]# vim site.cnf
  2. [root@docker2 certs]# cat site.cnf
  3. [server]
  4. authorityKeyIdentifier=keyid,issuer
  5. basicConstraints = critical,CA:FALSE
  6. extendedKeyUsage=serverAuth
  7. keyUsage = critical, digitalSignature, keyEncipherment
  8. subjectAltName = DNS:docker.domain.com, IP:127.0.0.1
  9. subjectKeyIdentifier=hash
  10. [root@docker2 certs]#

第八步签署站点 SSL 证书:

  1. [root@docker2 certs]# openssl x509 -req -days 750 -in "site.csr" -sha256 \
  2. > -CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
  3. > -out "docker.domain.com.crt" -extfile "site.cnf" -extensions server
  4. Signature ok
  5. subject=C = CN, ST = tj, L = tj, O = tj, CN = docker.domain.com
  6. Getting CA Private Key
  7. [root@docker2 certs]#
  8. [root@docker2 certs]# mkdir /ssl
  9. [root@docker2 certs]# cp docker.domain.com.key docker.domain.com.crt root-ca.crt /ssl
  10. [root@docker2 certs]# ls /ssl/
  11. docker.domain.com.crt docker.domain.com.key root-ca.crt
  12. [root@docker2 certs]#
  13. [root@docker2 ~]# mkdir /registry
  14. [root@docker2 ~]# mv /ssl/ /registry/
  15. [root@docker2 ~]# cd /registry/
  16. [root@docker2 registry]# vim config.yml
  17. [root@docker2 registry]# cat config.yml
  18. version: 0.1
  19. log:
  20. accesslog:
  21. disabled: true
  22. level: debug
  23. formatter: text
  24. fields:
  25. service: registry
  26. environment: staging
  27. storage:
  28. delete:
  29. enabled: true
  30. cache:
  31. blobdescriptor: inmemory
  32. filesystem:
  33. rootdirectory: /var/lib/registry
  34. auth:
  35. htpasswd:
  36. realm: basic-realm
  37. path: /etc/docker/registry/auth/nginx.htpasswd
  38. http:
  39. addr: :443
  40. host: https://docker.domain.com
  41. headers:
  42. X-Content-Type-Options: [nosniff]
  43. http2:
  44. disabled: false
  45. tls:
  46. certificate: /etc/docker/registry/ssl/docker.domain.com.crt
  47. key: /etc/docker/registry/ssl/docker.domain.com.key
  48. health:
  49. storagedriver:
  50. enabled: true
  51. interval: 10s
  52. threshold: 3
  53. [root@docker2 registry]#
  54. [root@docker2 registry]# mkdir auth
  55. [root@docker2 registry]# yum -y install httpd-tools
  56. [root@docker2 registry]# htpasswd -Bbn testuser redhat > auth/nginx.htpasswd
  57. [root@docker2 registry]#
  58. [root@docker2 registry]# tree /registry/
  59. /registry/
  60. ├── auth
  61. │   └── nginx.htpasswd
  62. ├── config.yml
  63. └── ssl
  64. ├── docker.domain.com.crt
  65. ├── docker.domain.com.key
  66. └── root-ca.crt
  67. 2 directories, 5 files
  68. [root@docker2 registry]#

安装docker-compose编排工具:

  1. [root@docker2 ~]# DOCKER_CONFIG=/usr/local/lib/docker/cli-plugins
  2. [root@docker2 ~]# mkdir -p $DOCKER_CONFIG/cli-plugins
  3. [root@docker2 ~]# curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
  4. [root@docker2 ~]# chmod +x $DOCKER_CONFIG/cli-plugins
  5. [root@docker2 ~]# docker compose version
  6. Docker Compose version v2.27.0
  7. [root@docker2 ~]#
  8. [root@docker2 ~]# mkdir /dcompose
  9. [root@docker2 ~]# cd /dcompose
  10. [root@docker2 dcompose]# vim docker-compose.yml
  11. [root@docker2 dcompose]# cat docker-compose.yml
  12. version: '3'
  13. services:
  14. registry:
  15. image: registry
  16. ports:
  17. - "443:443"
  18. volumes:
  19. - /registry:/etc/docker/registry
  20. - registry-data:/var/lib/registry
  21. volumes:
  22. registry-data:
  23. [root@docker2 dcompose]#
  24. [root@docker2 dcompose]# docker volume ls
  25. DRIVER VOLUME NAME
  26. [root@docker2 dcompose]#
  27. [root@docker2 dcompose]# cat /etc/hosts
  28. 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 docker.domain.com
  29. ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
  30. [root@docker2 dcompose]#
  31. [root@docker2 dcompose]# pwd
  32. /dcompose
  33. [root@docker2 dcompose]# ls
  34. docker-compose.yml
  35. [root@docker2 dcompose]# docker compose up -d
  36. WARN[0000] /dcompose/docker-compose.yml: `version` is obsolete
  37. [+] Running 3/3
  38. ✔ Network dcompose_default Cr... 0.3s
  39. ✔ Volume "dcompose_registry-data" Created 0.0s
  40. ✔ Container dcompose-registry-1 Started 0.7s
  41. [root@docker2 dcompose]#
  42. [root@docker2 dcompose]# docker volume ls
  43. DRIVER VOLUME NAME
  44. local dcompose_registry-data
  45. [root@docker2 dcompose]#
  46. [root@docker2 dcompose]# docker ps
  47. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  48. 976fbe0456cc registry "/entrypoint.sh /etc…" 31 seconds ago Up 29 seconds 0.0.0.0:443->443/tcp, :::443->443/tcp, 5000/tcp dcompose-registry-1
  49. [root@docker2 dcompose]#
  50. 测试:
  51. 由于自行签发的 CA 根证书不被系统信任,所以我们需要将 CA 根证书 ssl/root-ca.crt 移入 /etc/docker/certs.d/docker.domain.com 文件夹中。
  52. [root@docker2 ~]# mkdir -p /etc/docker/certs.d/docker.domain.com
  53. [root@docker2 ~]# cp /registry/ssl/root-ca.crt /etc/docker/certs.d/docker.domain.com/ca.crt
  54. [root@docker2 ~]# ls /etc/docker/certs.d/docker.domain.com/ca.crt
  55. /etc/docker/certs.d/docker.domain.com/ca.crt
  56. [root@docker2 ~]#
  57. 登录:
  58. [root@docker2 ~]# docker login docker.domain.com
  59. Username: testuser
  60. Password:
  61. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  62. Configure a credential helper to remove this warning. See
  63. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  64. Login Succeeded
  65. [root@docker2 ~]#
  66. [root@docker2 ~]# docker tag hello-world:latest docker.domain.com/testuser/hello:v1
  67. [root@docker2 ~]# docker push docker.domain.com/testuser/hello:v1
  68. The push refers to repository [docker.domain.com/testuser/hello]
  69. ac28800ec8bb: Pushed
  70. v1: digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 size: 524
  71. [root@docker2 ~]#

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/630920
推荐阅读
相关标签
  

闽ICP备14008679号