赞
踩
在这里我们来整理一下docker容器、dockerfile、docker镜像的关系:
dockerfile是面向开发的,发布项目做镜像的时候就要编写dockerfile文件。
dockerfile:构建文件,定义了一切的步骤,源代码。
dockerImanges:通过dockerfile构建生成的镜像,最终发布和运行的产品。
docker容器:容器就是镜像运行起来提供服务的
- Dockerfile 指令选项:
-
- FROM #基础镜像 。 (centos)
- MAINTAINER #镜像的作者和邮箱。(已被弃用,结尾介绍代替词)
- RUN #镜像构建的时候需要执行的命令。
- CMD #类似于 RUN 指令,用于运行程序(只有最后一个会生效,可被替代)
- EXPOSE #对外开放的端口。
- ENV #设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
- ADD # 步骤:tomcat镜像,这个tomcat压缩包。添加内容。
- COPY #复制指令,将文件拷贝到镜像中。
- VOLUME #设置卷,挂载的主机目录。
- USER #用于指定执行后续命令的用户和用户组,
- 这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
- WORKDIR #工作目录(类似CD命令)。
- ENTRYPOINT #类似于 CMD 指令,但其不会被 docker run
- 的命令行参数指定的指令所覆盖,会追加命令。
- ONBUILD #当构建一个被继承Dokcerfile,就会运行ONBUILD的指令。出发执行。
-
-
- 注意:CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
- 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
- CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
- 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
-
- LABEL(MAINTALNER已经被弃用了,目前是使用LABEL代替)
- LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
- LABEL <key>=<value> <key>=<value> <key>=<value> ...
- 比如我们可以添加镜像的作者:
- LABEL org.opencontainers.image.authors="runoob"
-
格式有两种:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
格式:ARG <参数名>[=<默认值>]
构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。
格式为 EXPOSE <端口1> [<端口2>...]。
EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
格式为 WORKDIR <工作目录路径>。
使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录
- [root@docker1 ~]# mkdir /test-multi
- [root@docker1 ~]# cd /test-multi
- [root@docker1 test-multi]# vim Dockerfile
- [root@docker1 test-multi]# cat Dockerfile
- FROM centos
- ENV aa=1 bb=2 cc=3 envdir=/a/b/c
- ARG dd=4 ee=5 ff=6 argdir=/a/b/c
- WORKDIR $argdir
- COPY test.sh $envdir
- RUN echo $aa $bb $cc $dd $dd $ff > /var.txt
- CMD ["./test.sh"]
- [root@docker1 test-multi]#
- [root@docker1 test-multi]# vim test.sh
- [root@docker1 test-multi]# cat test.sh
- #! /bin/bash
- echo output env vars:
- echo $aa $bb $cc
- echo output arg vars:
- echo $dd $ee $ff
- echo current work directory:
- pwd
- [root@docker1 test-multi]#
- [root@docker1 test-multi]# chmod +x test.sh
-
-
-
- [root@docker1 test-multi]# docker build -t mymulti:v1 .
- ……
- => [2/4] WORKDIR /a/b/c 0.1s
- => [3/4] COPY test.sh /a/b/c 0.0s
- => [4/4] RUN echo 1 2 3 4 4 6 > /var.txt
- ……
-
- 验证:
- [root@docker1 test-multi]# docker run --rm mymulti:v1
- output env vars:
- 1 2 3
- output arg vars:
-
- current work directory:
- /a/b/c
- [root@docker1 test-multi]#
-
格式为:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
- [root@docker1 ~]# mkdir /test_volume
- [root@docker1 ~]# cd /test_volume
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# cat Dockerfile
- from alpine
- RUN mkdir /test && touch /test/test.txt
- [root@docker1 test_volume]# docker build -t myvolume:v1 .
- [root@docker1 test_volume]# docker run -it myvolume:v1 sh
- / # cat /test/test.txt
- / # echo 123 > /test/test.txt
- / # cat /test/test.txt
- 123
- / # exit
- [root@docker1 test_volume]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- c2de419ef2d3 myvolume:v1 "sh" 36 seconds ago Exited (0) 3 seconds ago zealous_lumiere
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker start zealous_lumiere
- zealous_lumiere
- [root@docker1 test_volume]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- c2de419ef2d3 myvolume:v1 "sh" About a minute ago Up 7 seconds zealous_lumiere
- [root@docker1 test_volume]# docker exec -it zealous_lumiere sh
- / # cat /test/test.txt
- 123
- / # exit
- [root@docker1 test_volume]# docker stop zealous_lumiere
- zealous_lumiere
- [root@docker1 test_volume]# docker rm zealous_lumiere
- zealous_lumiere
- [root@docker1 test_volume]#注:容器没删除,则数据存在
-
- 重新创建的容器没有之前的数据,数据是非持久化的:
- [root@docker1 test_volume]# docker run -it --name mv1 myvolume:v1 sh
- / # cat /test/test.txt
- / # exit
- [root@docker1 test_volume]# docker rm mv1
- mv1
- [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 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:
挂载主机目录 (Bind mounts)
- [root@docker1 test_volume]# docker volume ls
- DRIVER VOLUME NAME
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker volume create my-vol1
- my-vol1
- [root@docker1 test_volume]# docker volume ls
- DRIVER VOLUME NAME
- local my-vol1
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker inspect my-vol1
- [
- {
- "CreatedAt": "2024-05-21T09:32:49+08:00",
- "Driver": "local",
- "Labels": null,
- "Mountpoint": "/var/lib/docker/volumes/my-vol1/_data",
- "Name": "my-vol1",
- "Options": null,
- "Scope": "local"
- }
- ]
- [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 inspect myvolume:v2| grep -i -A 2 volumes
- "Volumes": {
- "/test": {}
- },
- [root@docker1 test_volume]#
-
- [root@docker1 test_volume]# docker run -it --rm -v my-vol1:/test myvolume:v2 sh
- / # cat /test/test.txt
- / # echo 123 > /test/test.txt
- / # echo 456 > /test/test2.txt
- / # exit
- [root@docker1 test_volume]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- [root@docker1 test_volume]# docker run -it --rm -v my-vol1:/test myvolume:v2 sh
- / # cat /test/test.txt
- 123
- / # cat /test/test2.txt
- 456
- / # exit
- [root@docker1 test_volume]#
- [root@docker1 ~]# ls /var/lib/docker/volumes/my-vol1/_data
- test2.txt test.txt
- [root@docker1 ~]#
- [root@docker1 test_volume]# docker run -it --rm --mount source=my-vol1,target=/test myvolume:v2 sh
- / # cat /test/test2.txt
- 456
- / # exit
- [root@docker1 test_volume]#
- Linux目录挂载:加bind选项
- [root@docker1 ~]# mkdir /a /b
- [root@docker1 ~]# touch /b/b.txt
- [root@docker1 ~]# mount /a /b
- mount: /b: /a is not a block device.
- [root@docker1 ~]# mount -o bind /a /b
- [root@docker1 ~]# ls /b
- [root@docker1 ~]# umount /b
- [root@docker1 ~]# ls /b
- b.txt
- [root@docker1 ~]#
- [root@docker1 test_volume]# mkdir /testmount
- [root@docker1 test_volume]# echo 3 > /testmount/3.txt
- [root@docker1 test_volume]# docker run -it --rm --mount type=bind,source=/testmount,target=/test myvolume:v2 sh
- / # ls /test
- 3.txt
- / # echo 33 > /test/3.txt
- / # exit
- [root@docker1 test_volume]# docker run -it --rm --mount type=bind,source=/testmount,target=/test,readonly myvolume:v2 sh
- / # cat /test/3.txt
- 33
- / # echo 333 > /test/3.txt
- sh: can't create /test/3.txt: Read-only file system
- / # exit
- [root@docker1 test_volume]#
- [root@docker1 ~]# ls /webdir/
- Dockerfile page1.html page2.html
- [root@docker1 ~]# cat /webdir/page1.html
- page1
- [root@docker1 ~]# cat /webdir/page2.html
- page2
- [root@docker1 ~]#
- [root@docker1 test_volume]# docker run -d --rm --name nginx1 -v /webdir:/usr/share/nginx/html -p 81:80 nginx:latest
- 6b9920b4b7d3f666c486a1d372b45fa01b63cd64252fbdc629053aff0b953ce8
- [root@docker1 test_volume]# docker run -d --rm --name nginx2 -v /webdir:/usr/share/nginx/html -p 82:80 nginx:latest
- 9666d000921ee7d78edaf8fc0f91ab4127b68ca9195c70601fa3eaf628c79616
- [root@docker1 test_volume]# curl 127.0.0.1:81/page1.html
- page1
- [root@docker1 test_volume]# curl 127.0.0.1:82/page1.html
- page1
- [root@docker1 test_volume]# docker stop nginx1
- nginx1
- [root@docker1 test_volume]# docker stop nginx2
- nginx2
- [root@docker1 test_volume]#
使用local以外的volume driver:
使用vieux/sshfs:
安装插件:
- [root@docker1 test_volume]# docker plugin install --grant-all-permissions vieux/sshfs
- latest: Pulling from vieux/sshfs
- Digest: sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811
- 52d435ada6a4: Complete
- Installed plugin vieux/sshfs
- [root@docker1 test_volume]#
-
- [root@docker2 ~]# mkdir /sharedir
- [root@docker2 ~]# touch /sharedir/share.txt
- [root@docker1 test_volume]# docker volume create --driver vieux/sshfs -o sshcmd=root@192.168.99.129:/sharedir -o password=1 sshvolume
- sshvolume
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker volume ls
- DRIVER VOLUME NAME
- local my-vol1
- vieux/sshfs:latest sshvolume
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker run -it --rm -v sshvolume:/opt alpine sh
- / # ls /opt/
- share.txt
- / # exit
- [root@docker1 test_volume]#
- (
- 官方参考如下:
- docker run -d \
- --name sshfs-container \
- --volume-driver vieux/sshfs \
- --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
- nginx:latest
- )
- 使用基于nfs的卷:
- (
- 官方参考如下:
- Nfsv3:
- docker service create -d \
- --name nfs-service \
- --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' \
- nginx:latest
-
- nfsv4:
- docker service create -d \
- --name nfs-service \
- --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"' \
- nginx:latest
- )
- 配置nfs服务,自行解决防火墙和selinux:
- [root@docker2 ~]# mkdir /nfs1 /nfs2
- [root@docker2 ~]# chmod 777 /nfs1 /nfs2
- [root@docker2 ~]# vim /etc/exports
- [root@docker2 ~]# cat /etc/exports
- /nfs1 *(rw,no_root_squash)
- /nfs2 *(rw,no_root_squash)
- [root@docker2 ~]#
- [root@docker2 ~]# systemctl start nfs-server.service
-
- [root@docker1 test_volume]# yum -y install nfs-utils
- [root@docker1 test_volume]# showmount -e 192.168.99.129
- Export list for 192.168.99.129:
- /nfs2 *
- /nfs1 *
- [root@docker1 test_volume]#
- [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
- nfs1volume
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker volume ls
- DRIVER VOLUME NAME
- local my-vol1
- local nfs1volume
- vieux/sshfs:latest sshvolume
- [root@docker1 test_volume]#
- 验证:
- [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
- / # touch /opt/1.txt
- / # exit
- [root@docker1 test_volume]#
- [root@docker2 ~]# ls /nfs1
- 1.txt
- [root@docker2 ~]#
- [root@docker1 test_volume]# docker run -it --rm --mount 'type=volume,source=nfs1volume,target=/opt' --privileged alpine sh
- / # ls /opt/
- 1.txt
- / # exit
- [root@docker1 test_volume]#
- [root@docker1 ~]# docker volume ls
- DRIVER VOLUME NAME
- local my-vol1
- local nfs1volume
- vieux/sshfs:latest sshvolume
- [root@docker1 ~]#
- [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
- / # touch /opt/2.txt
- / # exit
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker volume ls
- DRIVER VOLUME NAME
- local my-vol1
- local nfs1volume
- local nfs2volume
- vieux/sshfs:latest sshvolume
- [root@docker1 test_volume]#
- [root@docker2 ~]# ls /nfs2
- 2.txt
- [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
格式:USER <用户名>[:<用户组>]
USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。
USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
- [root@docker1 test_volume]# vim Dockerfile
- [root@docker1 test_volume]# cat Dockerfile
- from centos
- RUN id > /user.txt && chmod 777 /user.txt
- RUN useradd test
- USER test
- RUN id >> /user.txt
- CMD cat /user.txt
- [root@docker1 test_volume]#
- [root@docker1 test_volume]# docker build -t test-user:v1 .
- [root@docker1 test_volume]# docker run -it --rm test-user:v1
- uid=0(root) gid=0(root) groups=0(root)
- uid=1000(test) gid=1000(test) groups=1000(test)
- [root@docker1 test_volume]#
格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。
- [root@docker1 ~]# mkdir /test-health
- [root@docker1 ~]# cd /test-health
- [root@docker1 test-health]# vim Dockerfile
- [root@docker1 test-health]# cat Dockerfile
- FROM nginx
- RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
- HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1
- [root@docker1 test-health]# docker build -t myhealth:v1 .
-
- 另起一个终端,每秒刷新一次docker ps -a的输出:
- [root@docker1 ~]# watch -n 1 docker ps -a
-
- [root@docker1 test-health]# docker run -d --rm --name myh myhealth:v1
- a1fffb3d0193408d81a1db9484576a3e2df214b12d9fa19ae78da6ff875d7704
- [root@docker1 test-health]#
- [root@docker1 ~]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- a1fffb3d0193 myhealth:v1 "/docker-entrypoint.…" 28 seconds ago Up 27 seconds (healthy) 80/tcp myh
- [root@docker1 ~]# 速度快,可以看到从starting到healthy的过程
-
- 为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看。
- [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进程是容器的主体进程,停服务则容器退出:
- [root@docker1 test-health]# docker exec -it myh sh
- # ls /usr/share/nginx/html/index.html
- /usr/share/nginx/html/index.html
- # rm -rf /usr/share/nginx/html/index.html
- # exit
- [root@docker1 test-health]#
- 等待一段时间可以看到unhealthy:
- [root@docker1 ~]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- cf26f8e926d2 myhealth:v1 "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (unhealthy) 80/tcp myh
- [root@docker1 ~]#
- 自行创建index.html,测试恢复为healthy的过程
- [root@docker1 test-health]# vim Dockerfile
- [root@docker1 test-health]# cat Dockerfile
- FROM alpine
- LABEL custom alpine
-
- [root@docker1 test-health]# docker build -t mylabel:v1 .
- [root@docker1 test-health]# docker image ls -f LABEL=custom
- REPOSITORY TAG IMAGE ID CREATED SIZE
- mylabel v1 bcefe279deed 3 months ago 7.38MB
- [root@docker1 test-health]#
从centos基础镜像创建一个容器,安装nginx软件包,配置健康检查,如果/usr/share/nginx/html/test.html存在,则检查正常,不存在则unhealthy,验证效果
- [root@docker1 ~]# mkdir /test-h2
- [root@docker1 ~]# cd /test-h2
- [root@docker1 test-h2]# vim Dockerfile
- [root@docker1 test-h2]# docker build -t myh2 .
- [root@docker1 test-h2]# cat Dockerfile
- FROM centos
- RUN rm -rf /etc/yum.repos.d/* \
- && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
- && yum -y install nginx \
- && yum clean all \
- && echo test > /usr/share/nginx/html/test.html
- EXPOSE 80
- HEALTHCHECK --interval=5s --timeout=3s \
- CMD [ -f "/usr/share/nginx/html/test.html" ] || exit 1
- [root@docker1 test-h2]#
- 注: 此时运行容器,没有启动nginx服务,无法使用curl判定,所以使用[ -f “xxxx” ]
使用samba共享提供卷
- [root@docker2 ~]# mkdir /sambashare
- [root@docker2 ~]# yum -y install samba samba-client
- [root@docker2 ~]# vim /etc/samba/smb.conf
- [root@docker2 ~]# tail -5 /etc/samba/smb.conf
- [smbshare]
- path = /sambashare/
- read only = No
- hosts allow = 192.168.99.
- valid users = testuser
- [root@docker2 ~]#
- [root@docker2 ~]# chmod 777 /sambashare/
- [root@docker2 ~]# useradd -s /sbin/nologin testuser
- [root@docker2 ~]# pdbedit -a testuser
- new password: (redhat)
- retype new password:(redhat)
- ……
- [root@docker2 ~]# pdbedit -L
- testuser:1001:
- [root@docker2 ~]#
- [root@docker2 ~]# systemctl restart smb.service nmb.service
- [root@docker1 test-h2]# yum -y install samba-client
- 使用testuser用户和redhat密码查看192.168.99.129服务器的共享:
- [root@docker1 ~]# smbclient -L 192.168.99.129 -U testuser%redhat
-
- Sharename Type Comment
- --------- ---- -------
- print$ Disk Printer Drivers
- smbshare Disk
- IPC$ IPC IPC Service (Samba 4.19.4)
- testuser Disk Home Directories
- SMB1 disabled -- no workgroup available
- [root@docker1 ~]#
- [root@docker1 ~]# smbclient -L 192.168.99.129 (直接回车,使用匿名用户查看)
- Password for [SAMBA\root]:
- Anonymous login successful
-
- Sharename Type Comment
- --------- ---- -------
- print$ Disk Printer Drivers
- smbshare Disk
- IPC$ IPC IPC Service (Samba 4.19.4)
- SMB1 disabled -- no workgroup available
- [root@docker1 ~]#
- [root@docker1 ~]# yum -y install cifs-utils
- [root@docker1 ~]# mount -o username=testuser,password=redhat //192.168.99.129/smbshare /opt
- [root@docker1 ~]# df -h /opt
- Filesystem Size Used Avail Use% Mounted on
- //192.168.99.129/smbshare 70G 13G 58G 19% /opt
- [root@docker1 ~]#
- [root@docker1 ~]# umount /opt
-
-
- 创建samba共享的卷:
- [root@docker1 ~]# docker volume create \
- > --driver local \
- > --opt type=cifs \
- > --opt device=//192.168.99.129/smbshare \
- > --opt o=addr=192.168.99.129,username=testuser,password=redhat,file_mode=0777,dir_mode=0777 \
- > --name cifs-volume
- cifs-volume
- [root@docker1 ~]#
-
- [root@docker1 ~]# docker run -it --rm -v cifs-volume:/opt alpine sh
- / # touch /opt/cifs.txt
- / # exit
- [root@docker1 ~]#
- [root@docker1 ~]# docker volume ls
- DRIVER VOLUME NAME
- local cifs-volume
- local my-vol1
- [root@docker1 ~]#
- [root@docker2 ~]# ls /sambashare/
- cifs.txt
- [root@docker2 ~]#
- [root@docker1 ~]# docker volume rm cifs-volume
- cifs-volume
- [root@docker1 ~]#
- [root@docker2 ~]# systemctl stop smb nmb
- [root@docker1 test-shell]# cat Dockerfile
- from centos
- RUN rm -rf /etc/yum.repos.d/* \
- && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
- && yum -y install python3 \
- && yum clean all \
- && touch /result.txt
- COPY * /
- SHELL ["/usr/bin/python3"]
- RUN /python.py
- SHELL ["/bin/bash", "-c"]
- RUN /shell.sh
- CMD cat /result.txt
- [root@docker1 test-shell]#
-
- [root@docker1 test-shell]# cat shell.sh
- echo hello shell >> /result.txt
- [root@docker1 test-shell]# cat python.py
- import os
- with open('/result.txt', 'w') as f:
- f.write("hello python\n")
-
- [root@docker1 test-shell]#
-
- [root@docker1 test-shell]# docker build -t myshell:v1 .
- [root@docker1 test-shell]# docker run --rm myshell:v1
- hello python
- hello shell
- [root@docker1 test-shell]#
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。
- [root@docker1 ~]# mkdir /test-onbuild
- [root@docker1 ~]# cd /test-onbuild
- [root@docker1 test-onbuild]# cat start.sh
- #! /bin/bash
- shell_var=$(ls /*.sh)
- $shell_var
- [root@docker1 test-onbuild]# chmod +x start.sh
- [root@docker1 test-onbuild]# cat Dockerfile
- from centos
- RUN mkdir /app
- WORKDIR /app
- ONBUILD COPY *.txt /
- ONBUILD COPY *.sh /
- COPY start.sh /app
- CMD ["./start.sh"]
- [root@docker1 test-onbuild]#
- [root@docker1 test-onbuild]# docker build -t onbuild_base .
- 注:此时ONBUILD指令没有执行
-
- [root@docker1 ob1]# pwd
- /ob1
- [root@docker1 ob1]#
- [root@docker1 ob1]# cat shell.sh
- #! /bin/bash
- cat /1.txt > /12.txt
- cat /2.txt >> /12.txt
- cat /12.txt
- [root@docker1 ob1]#
- [root@docker1 ob1]# chmod +x shell.sh
- [root@docker1 ob1]# cat 1.txt
- 1
- [root@docker1 ob1]# cat 2.txt
- 2
- [root@docker1 ob1]# cat Dockerfile
- FROM onbuild_base:latest
- [root@docker1 ob1]#
- [root@docker1 ob1]# docker build -t ob_sub:v1 .
- [root@docker1 ob1]# docker run --rm ob_sub:v1
- 1
- 2
- [root@docker1 ob1]#
-
-
-
- [root@docker1 ob1]# mkdir /ob2
- [root@docker1 ob1]# cd /ob2
- [root@docker1 ob2]# vim jiaoben.sh
- [root@docker1 ob2]# cat jiaoben.sh
- #! /bin/bash
- cat /3.txt > /34.txt
- cat /4.txt >> /34.txt
- cat /34.txt
- [root@docker1 ob2]#
- [root@docker1 ob2]# chmod +x jiaoben.sh
- [root@docker1 ob2]# echo 3 > 3.txt
- [root@docker1 ob2]# echo 4 > 4.txt
- [root@docker1 ob2]#
- [root@docker1 ob2]# vim Dockerfile
- [root@docker1 ob2]# cat Dockerfile
- from onbuild_base:latest
- [root@docker1 ob2]#
- [root@docker1 ob2]# docker build -t ob_sub:v2 .
- [root@docker1 ob2]# docker run --rm ob_sub:v2
- 3
- 4
- [root@docker1 ob2]#
参考文档:
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
以centos为基础,配置yum源,安装wget,拷贝脚本web.sh至/app
脚本内容:
判断安装的web服务是什么:
如果是httpd,则执行httpd -D FOREGROUND
如果是nginx,则执行nginx -g “daemon off;”
在dockerfile中使用onbuild关键字,将docker1共享的index.html下载到/目录
镜像分别为os_httpd和os_nginx
在每个镜像中,有对应的ONBUILD指令,将页面文件拷贝至对应服务的网站根目录中
使用单个dockerfile可能遇到的问题:
将所有的构建过程编包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:
镜像层次多,镜像体积较大,部署时间变长
源代码存在泄露的风险
使用一个dockerfile源码编译出hello.c的二进制文件并运行:
- [root@docker1 ~]# mkdir /multi-hello
- [root@docker1 ~]# cd /multi-hello
- [root@docker1 multi-hello]#
- [root@docker1 multi-hello]# vim hello.c
- [root@docker1 multi-hello]# cat hello.c
- #include<stdio.h>
- int main(void)
- {
- printf ("Hello world!\n");
- return 0;
- }
- [root@docker1 multi-hello]#
-
- [root@docker1 multi-hello]# cat Dockerfile
- FROM centos
- RUN rm -rf /etc/yum.repos.d/* \
- && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
- && yum -y install gcc gcc-c++ make \
- && yum clean all \
- && mkdir /app
- COPY hello.c /
- RUN gcc -o /hello /hello.c && mv /hello /app
- CMD ["/app/hello"]
- [root@docker1 multi-hello]#
- [root@docker1 multi-hello]# docker build -t multi-hello:v1 .
- [root@docker1 multi-hello]# docker run --rm multi-hello:v1
- Hello world!
- [root@docker1 multi-hello]#
-
- 此时镜像多了200M左右:
- [root@docker1 multi-hello]# docker image ls centos
- REPOSITORY TAG IMAGE ID CREATED SIZE
- centos latest 5d0da3dc9764 2 years ago 231MB
- [root@docker1 multi-hello]# docker image ls multi-hello:v1
- REPOSITORY TAG IMAGE ID CREATED SIZE
- multi-hello v1 42afade795ac 51 seconds ago 424MB
- [root@docker1 multi-hello]#
-
-
- 如果想要所需的效果,及运行二进制文件,编译环境不是必须的,所有可以分两次构建:
- [root@docker1 multi-hello]# ls
- Dockerfile hello.c
- [root@docker1 multi-hello]#
-
- 从容器复制文件到宿主机,只需容器存在即可,所有此处用了docker create
- (使用docker run也可以)
- [root@docker1 multi-hello]# docker create --name m1 multi-hello:v1
- 14285a08b091a714ae9182a61ab90d75df7437987cd2a702ce84d7cd315487da
- [root@docker1 multi-hello]# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 14285a08b091 multi-hello:v1 "/app/hello" 4 seconds ago Created m1
- [root@docker1 multi-hello]#
-
- [root@docker1 multi-hello]# docker cp m1:/app/hello .
- Successfully copied 19.5kB to /multi-hello/.
- [root@docker1 multi-hello]# ls hello
- hello
- [root@docker1 multi-hello]#
- [root@docker1 multi-hello]# vim dockerfile2
- [root@docker1 multi-hello]# cat dockerfile2
- FROM centos
- RUN mkdir /app
- COPY hello /app
- CMD ["/app/hello"]
- [root@docker1 multi-hello]#
- [root@docker1 multi-hello]# docker build -f dockerfile2 -t multi-hello:v2 .
- [root@docker1 multi-hello]# docker run --rm multi-hello:v2
- Hello world!
- [root@docker1 multi-hello]#
-
- [root@docker1 multi-hello]# docker image ls multi-hello
- REPOSITORY TAG IMAGE ID CREATED SIZE
- multi-hello v2 99036d01a922 About a minute ago 231MB
- multi-hello v1 42afade795ac 10 minutes ago 424MB
- [root@docker1 multi-hello]# docker image ls centos
- REPOSITORY TAG IMAGE ID CREATED SIZE
- centos latest 5d0da3dc9764 2 years ago 231MB
- [root@docker1 multi-hello]#
- 此时multi-hello:v2实现了同样的效果,但是体积小了很多
多阶段构建即使用1个dockerfile实现上面的多次构建过程:
- [root@docker1 multi-hello]# rm -rf hello
- [root@docker1 multi-hello]# vim dockerfile3
- [root@docker1 multi-hello]# vim dockerfile3
- [root@docker1 multi-hello]# cat dockerfile3
- FROM centos as build1
- RUN rm -rf /etc/yum.repos.d/* \
- && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
- && yum -y install gcc gcc-c++ make \
- && yum clean all \
- COPY hello.c /
- RUN gcc -o /hello /hello.c
-
- FROM centos as build2
- WORKDIR /app
- COPY --from=build1 /hello .
- CMD ["/app/hello"]
- [root@docker1 multi-hello]#
- [root@docker1 multi-hello]# docker build -f dockerfile3 -t multi-hello:v3 .
- [root@docker1 multi-hello]# docker run --rm multi-hello:v3
- Hello world!
- [root@docker1 multi-hello]# docker image ls multi-hello
- REPOSITORY TAG IMAGE ID CREATED SIZE
- multi-hello v3 0163f8be5f45 18 seconds ago 231MB
- multi-hello v2 99036d01a922 17 minutes ago 231MB
- multi-hello v1 42afade795ac 26 minutes ago 424MB
- [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运行
- [root@docker1 ~]# docker image ls centos_stream8
- REPOSITORY TAG IMAGE ID CREATED SIZE
- centos_stream8 latest e502e2d948d7 18 hours ago 335MB
- [root@docker1 ~]#
-
- [root@docker1 ~]# mkdir /mbuild
- [root@docker1 ~]# cd /mbuild
- [root@docker1 mbuild]# vim Dockerfile
- [root@docker1 mbuild]# cat Dockerfile
- from centos_stream8 as build1
- RUN yum -y install wget \
- && wget http://rpmfind.net/linux/centos/8-stream/PowerTools/x86_64/os/Packages/glibc-static-2.28-251.el8.x86_64.rpm \
- && wget http://rpmfind.net/linux/centos/8-stream/PowerTools/x86_64/os/Packages/libxcrypt-static-4.1.1-6.el8.x86_64.rpm
-
- from centos_stream8 as build2
- COPY --from=build1 /*.rpm .
- COPY hello.c /
- RUN yum -y install gcc /glibc-static-2.28-251.el8.x86_64.rpm /libxcrypt-static-4.1.1-6.el8.x86_64.rpm \
- && gcc -o /hello -static /hello.c
-
- from scratch as build3
- WORKDIR /app
- COPY --from=build2 /hello /app
- CMD ["./hello"]
-
- [root@docker1 mbuild]#
- [root@docker1 mbuild]# vim hello.c
- [root@docker1 mbuild]# cat hello.c
- #include<stdio.h>
- int main(void)
- {
- printf ("Hello world!\n");
- return 0;
- }
- [root@docker1 mbuild]#
-
- [root@docker1 mbuild]# docker build -t mhello .
- [root@docker1 mbuild]# docker image ls mhello
- REPOSITORY TAG IMAGE ID CREATED SIZE
- mhello latest 17b68d3ec2d5 16 seconds ago 1.75MB
- [root@docker1 mbuild]# docker run --rm mhello
- Hello world!
- [root@docker1 mbuild]#
-
- 注:可以使用--target,构建其中某一个阶段的镜像
- 如: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 私钥:
- [root@docker2 certs]# openssl genrsa -out "root-ca.key" 4096
- [root@docker2 certs]# ls root-ca.key
- root-ca.key
- [root@docker2 certs]#
第二步利用私钥创建 CA 根证书请求文件:
- [root@docker2 certs]# openssl req \
- > -new -key "root-ca.key" \
- > -out "root-ca.csr" -sha256 \
- > -subj '/C=CN/ST=tj/L=tj/O=tj/CN=tj Docker Registry CA'
- [root@docker2 certs]# ls
- root-ca.csr root-ca.key
- [root@docker2 certs]#
第三步配置 CA 根证书,新建 root-ca.cnf:
- [root@docker2 certs]# vim root-ca.cnf
- [root@docker2 certs]# cat root-ca.cnf
- [root_ca]
- basicConstraints = critical,CA:TRUE,pathlen:1
- keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
- subjectKeyIdentifier=hash
- [root@docker2 certs]#
第四步签发根证书:
- [root@docker2 certs]# openssl x509 -req -days 3650 -in "root-ca.csr" \
- > -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
- > -extfile "root-ca.cnf" -extensions \
- > root_ca
- Signature ok
- subject=C = CN, ST = tj, L = tj, O = tj, CN = tj Docker Registry CA
- Getting Private key
- [root@docker2 certs]# ls
- root-ca.cnf root-ca.crt(根证书) root-ca.csr(签名请求) root-ca.key(私钥)
- [root@docker2 certs]#
第五步生成站点 SSL 私钥:
- [root@docker2 certs]# openssl genrsa -out "docker.domain.com.key" 4096
- Generating RSA private key, 4096 bit long modulus (2 primes)
- ...............................................++++
- ..................................................................++++
- e is 65537 (0x010001)
- [root@docker2 certs]#
- [root@docker2 certs]# ls
- docker.domain.com.key root-ca.cnf root-ca.crt root-ca.csr root-ca.key
- [root@docker2 certs]#
第六步使用私钥生成证书请求文件:
- [root@docker2 certs]# openssl req -new -key "docker.domain.com.key" -out "site.csr" -sha256 \
- > -subj '/C=CN/ST=tj/L=tj/O=tj/CN=docker.domain.com'
- [root@docker2 certs]# ls
- docker.domain.com.key root-ca.crt root-ca.key
- root-ca.cnf root-ca.csr site.csr
- [root@docker2 certs]#
第七步配置证书,新建 site.cnf 文件:
- [root@docker2 certs]# vim site.cnf
- [root@docker2 certs]# cat site.cnf
- [server]
- authorityKeyIdentifier=keyid,issuer
- basicConstraints = critical,CA:FALSE
- extendedKeyUsage=serverAuth
- keyUsage = critical, digitalSignature, keyEncipherment
- subjectAltName = DNS:docker.domain.com, IP:127.0.0.1
- subjectKeyIdentifier=hash
- [root@docker2 certs]#
第八步签署站点 SSL 证书:
- [root@docker2 certs]# openssl x509 -req -days 750 -in "site.csr" -sha256 \
- > -CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
- > -out "docker.domain.com.crt" -extfile "site.cnf" -extensions server
- Signature ok
- subject=C = CN, ST = tj, L = tj, O = tj, CN = docker.domain.com
- Getting CA Private Key
- [root@docker2 certs]#
-
- [root@docker2 certs]# mkdir /ssl
- [root@docker2 certs]# cp docker.domain.com.key docker.domain.com.crt root-ca.crt /ssl
- [root@docker2 certs]# ls /ssl/
- docker.domain.com.crt docker.domain.com.key root-ca.crt
- [root@docker2 certs]#
-
- [root@docker2 ~]# mkdir /registry
- [root@docker2 ~]# mv /ssl/ /registry/
- [root@docker2 ~]# cd /registry/
- [root@docker2 registry]# vim config.yml
- [root@docker2 registry]# cat config.yml
- version: 0.1
- log:
- accesslog:
- disabled: true
- level: debug
- formatter: text
- fields:
- service: registry
- environment: staging
- storage:
- delete:
- enabled: true
- cache:
- blobdescriptor: inmemory
- filesystem:
- rootdirectory: /var/lib/registry
- auth:
- htpasswd:
- realm: basic-realm
- path: /etc/docker/registry/auth/nginx.htpasswd
- http:
- addr: :443
- host: https://docker.domain.com
- headers:
- X-Content-Type-Options: [nosniff]
- http2:
- disabled: false
- tls:
- certificate: /etc/docker/registry/ssl/docker.domain.com.crt
- key: /etc/docker/registry/ssl/docker.domain.com.key
- health:
- storagedriver:
- enabled: true
- interval: 10s
- threshold: 3
-
- [root@docker2 registry]#
-
-
- [root@docker2 registry]# mkdir auth
- [root@docker2 registry]# yum -y install httpd-tools
- [root@docker2 registry]# htpasswd -Bbn testuser redhat > auth/nginx.htpasswd
- [root@docker2 registry]#
- [root@docker2 registry]# tree /registry/
- /registry/
- ├── auth
- │ └── nginx.htpasswd
- ├── config.yml
- └── ssl
- ├── docker.domain.com.crt
- ├── docker.domain.com.key
- └── root-ca.crt
-
- 2 directories, 5 files
- [root@docker2 registry]#
- [root@docker2 ~]# DOCKER_CONFIG=/usr/local/lib/docker/cli-plugins
- [root@docker2 ~]# mkdir -p $DOCKER_CONFIG/cli-plugins
- [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
- [root@docker2 ~]# chmod +x $DOCKER_CONFIG/cli-plugins
- [root@docker2 ~]# docker compose version
- Docker Compose version v2.27.0
- [root@docker2 ~]#
-
-
- [root@docker2 ~]# mkdir /dcompose
- [root@docker2 ~]# cd /dcompose
- [root@docker2 dcompose]# vim docker-compose.yml
- [root@docker2 dcompose]# cat docker-compose.yml
- version: '3'
-
- services:
- registry:
- image: registry
- ports:
- - "443:443"
- volumes:
- - /registry:/etc/docker/registry
- - registry-data:/var/lib/registry
-
- volumes:
- registry-data:
-
- [root@docker2 dcompose]#
-
- [root@docker2 dcompose]# docker volume ls
- DRIVER VOLUME NAME
- [root@docker2 dcompose]#
-
- [root@docker2 dcompose]# cat /etc/hosts
- 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 docker.domain.com
- ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
- [root@docker2 dcompose]#
-
- [root@docker2 dcompose]# pwd
- /dcompose
- [root@docker2 dcompose]# ls
- docker-compose.yml
- [root@docker2 dcompose]# docker compose up -d
- WARN[0000] /dcompose/docker-compose.yml: `version` is obsolete
- [+] Running 3/3
- ✔ Network dcompose_default Cr... 0.3s
- ✔ Volume "dcompose_registry-data" Created 0.0s
- ✔ Container dcompose-registry-1 Started 0.7s
- [root@docker2 dcompose]#
-
- [root@docker2 dcompose]# docker volume ls
- DRIVER VOLUME NAME
- local dcompose_registry-data
- [root@docker2 dcompose]#
-
- [root@docker2 dcompose]# docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 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
- [root@docker2 dcompose]#
-
- 测试:
- 由于自行签发的 CA 根证书不被系统信任,所以我们需要将 CA 根证书 ssl/root-ca.crt 移入 /etc/docker/certs.d/docker.domain.com 文件夹中。
- [root@docker2 ~]# mkdir -p /etc/docker/certs.d/docker.domain.com
- [root@docker2 ~]# cp /registry/ssl/root-ca.crt /etc/docker/certs.d/docker.domain.com/ca.crt
- [root@docker2 ~]# ls /etc/docker/certs.d/docker.domain.com/ca.crt
- /etc/docker/certs.d/docker.domain.com/ca.crt
- [root@docker2 ~]#
-
- 登录:
- [root@docker2 ~]# docker login docker.domain.com
- Username: testuser
- Password:
- 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@docker2 ~]#
-
- [root@docker2 ~]# docker tag hello-world:latest docker.domain.com/testuser/hello:v1
- [root@docker2 ~]# docker push docker.domain.com/testuser/hello:v1
- The push refers to repository [docker.domain.com/testuser/hello]
- ac28800ec8bb: Pushed
- v1: digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 size: 524
- [root@docker2 ~]#
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。