Docker从入门到精通

系列文章目录

docker常见用法之镜像构建1


docker


一、镜像的分层结构

共享宿主机的内核(kernel)(容器的安全把宿主机安全管控好就好)

base镜像提供的是最小的linux发行版

同一docker主机支持运行多种linux发行版(因为linux内核一样,不一样的是文件系统)

采用分层结构的最大好处:共享资源(底层共享资源)

分层结构:降低了网络带宽和磁盘空间

(下载网上的镜像时候会判断你有该层没,你有相同层的话,你便不用下载了已经有的层。本机只要存储同样的镜像层一份,本机的镜像也可以共享)
Copy-on-Write(linux内核的写时复制技术)容器层可以写

容器层以下都不可以写(都是只读)

docker从上往下依次查找文件

容器层保存镜像变化的部分,并不会对镜像本身进行任何的修改

一个镜像最多127层(一般不会有那么大,因为优化就是减少镜像层)


二、容器的用法

容器常用用法:

-i交互式 -t打开一个tty终端
-d打入后台 -name给容器起个名字
ctrl +d 退出容器终端并且容器停掉 docker ps显示正在运行的容器
ctrl +pq 退出容器终端并且容器后台运行 docker ps +a 显示所有的容器
docker rm +容器名字 删掉已经停止的容器 容器正在running状态需要先stop,在rm
强制删除,不用停止容器直接删除rm-f + 容器名字 docker -p 宿主机端口:容器内的端口,用宿主机的端口号映射容器内的端口
docker start + 容器名字,开启容器 docker container attach +容器名字,进入该容器
docker images 查看容器已经有的镜像 docker history +容器名字,查看之前打包的历史记录
docker rmi +镜像名字,删除镜像 docker load 导入镜像
docker port + 容器名字,可以查看容器的端口映射 --restart=always随着docker引擎的开启该容器自动启动
docker inspect + 容器名字或者id,查看容器具体信息 docker inspect +镜像,查看镜像的具体信息
docker -v 宿主机路径:容器路径,数据持久化 docker exec -it 容器名字 sh 重新进入交互式容器中不能tab补齐
-- docker -v 将宿主机资源挂载到容器内
docker exec -it 容器名字 bash 重新进入交互式容器中能tab补齐
bash 复制代码
[root@docker1 docker]# docker container 
attach   diff     kill     port     rm       stop     wait     
commit   exec     logs     prune    run      top      
cp       export   ls       rename   start    unpause  
create   inspect  pause    restart  stats    update   

三、镜像的构建

镜像的名称是不能冲突的

3.1docker commit 构建新镜像三部曲

不推荐该方法

运行容器 docker run
修改容器
将容器保存为新的镜像
缺点:效率低、可重复性弱、容易出错
       使用者无法对镜像进行审计,存在安全隐患

3.1.1运行容器并且修改容器

bash 复制代码
[root@docker1 docker]# docker run -it --name test busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # touch file1
/ # touch file2
/ # touch file3
/ # ls
bin    etc    file2  home   root   tmp    var
dev    file1  file3  proc   sys    usr
ctrl +d
bash 复制代码
[root@docker1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
bash 复制代码
[root@docker1 docker]# docker start test 
test
[root@docker1 docker]# docker container attach test 
/ # 
ctrl +pq
bash 复制代码
[root@docker1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7d589bd8615e        busybox             "sh"                27 minutes ago      Up 5 minutes                            test

3.1.2提交容器

bash 复制代码
[root@docker1 docker]# docker commit --help
Usage:	docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
[root@docker1 docker]# docker commit -m "v1" test test:v1
sha256:dc00eef3c58e0c21318a3a8bc9f4586f75e18b460211cb4bed1f565134924cf4
bash 复制代码
[root@docker1 docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                v1                  dc00eef3c58e        55 seconds ago      1.24MB
busybox             latest              beae173ccac6        3 weeks ago         1.24MB

missing 表示在别人机器上打包的你看不到,v1创建了3个文件

只能看到sh,不知道用户在其中具体干了什么,不便于用户审计和重用,安全隐患。

bash 复制代码
[root@docker1 docker]# docker history test:v1 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
dc00eef3c58e        2 minutes ago       sh                                              166B                v1
beae173ccac6        3 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4...   1.24MB              
bash 复制代码
[root@docker1 docker]# docker history busybox:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
beae173ccac6        3 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4...   1.24MB              

分层结构的好处,共享资源。两个镜像都用了最后2层,但操作系统上面只用保存一份。彼此共享,镜像层是只读的

bash 复制代码
[root@docker1 docker]# docker run -it --name demo test:v1
/ # ls
bin    dev    etc    file1  file2  file3  home   proc   root   sys    tmp    usr    var

3.1.2删除docker镜像

删除原先docker三部曲创建的镜像

当前有容器占用镜像,所以删不了该镜像。删除镜像的时候,先保证没有容器占用该镜像

bash 复制代码
[root@docker1 docker]# docker rmi test:v1
Error response from daemon: conflict: unable to remove repository reference "test:v1" (must force) - container 1e534ccc1bb7 is using its referenced image dc00eef3c58e

docker ps-a 找到占用镜像的容器删掉,然后删除容器镜像

bash 复制代码
[root@docker1 docker]# docker rm -f demo 
demo
[root@docker1 docker]# docker rmi test:v1 
Untagged: test:v1
Deleted: sha256:dc00eef3c58e0c21318a3a8bc9f4586f75e18b460211cb4bed1f565134924cf4
Deleted: sha256:9e982fbda3a1bbb95e62de21d15b305daef87bab314f218a62afbfd3f9939c2e

3.2Dockerfile构建镜像

创建一个Dockerfile (必须在一个空目录中创建) 因为一开始会发送内容给Docker引擎,如果在很大/目录上面构建,会把整个/发送去构建

构建镜像

bash 复制代码
[root@docker1 docker]# cd 
[root@docker1 ~]# ls
[root@docker1 ~]# mkdir docker 
[root@docker1 ~]# cd docker/
[root@docker1 docker]# ls
[root@docker1 docker]# vim Dockerfile

FROM 从那个基础镜像开始构建,给予它一个环境(构建方式,通过基础镜像,运行一个容器,(后台)在里面执行指令)

RUN在容器里面运行什么指令

.是从当前目录读取

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1

里面有构建镜像的具体参数

bash 复制代码
[root@docker1 docker]# docker build --help

每一个RUN,一层。相当于,你每一次运行,执行了一次Docker commit

bash 复制代码
[root@docker1 docker]# docker build -t test:v1 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM busybox
 ---> beae173ccac6
Step 2/4 : RUN touch file1
 ---> Running in 0121d9c6c701
Removing intermediate container 0121d9c6c701
 ---> 884a1d2fcbd4
Step 3/4 : RUN mkdir dir1
 ---> Running in f45072d8860b
Removing intermediate container f45072d8860b
 ---> 3f7259a48bfc
Step 4/4 : RUN mv file1 dir1
 ---> Running in 612208e6db5b
Removing intermediate container 612208e6db5b
 ---> b6b7f570cc47
Successfully built b6b7f570cc47
Successfully tagged test:v1

便于审计并且便于重用,因为这个文件Dockerfile已经写下来了

在Dockerfile中写的每一行通过Docker commit提交成镜像层


END

系列文章目录

docker常用方法之dockerfile入门指令用法2


docker


一、 Dockerfile写法详解

看docker官方的网站学习docker具体指令

常用指令:

FROM 指定base镜像,如果本地不存在会从远程仓库下载 MAINTAINER 设置镜像的作者,比如用户邮箱等
COPY 把文件从build context 复制到镜像 支持两种形式:COPY src dest 和 COPY 【"src,""dest"】 src必须指定build context 中的文件或目录

1.1 copy指令用法

src必须指定build context 中的文件或目录 即当前目录

实验环境:

bash 复制代码
[root@docker1 docker]# vim index.html
[root@docker1 docker]# cat index.html 
www.yan.com

编写Dockerfile:

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /

前面镜像用的cache,因为之前编译过,Dockerfile没有改变都是用缓存来执行,加速构建过程

bash 复制代码
[root@docker1 docker]# docker build -t test:v2 .
Sending build context to Docker daemon  3.072kB
Step 1/5 : FROM busybox
 ---> beae173ccac6
Step 2/5 : RUN touch file1
 ---> Using cache
 ---> 884a1d2fcbd4
Step 3/5 : RUN mkdir dir1
 ---> Using cache
 ---> 3f7259a48bfc
Step 4/5 : RUN mv file1 dir1
 ---> Using cache
 ---> b6b7f570cc47
Step 5/5 : COPY index.html /
 ---> 317f587b99ce
Successfully built 317f587b99ce
Successfully tagged test:v2

拷贝文件到容器中

bash 复制代码
[root@docker1 docker]# docker history test:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
317f587b99ce        2 minutes ago       /bin/sh -c #(nop) COPY file:d88a99d823b18eab...   12B                 
b6b7f570cc47        34 minutes ago      /bin/sh -c mv file1 dir1                        0B                  
3f7259a48bfc        34 minutes ago      /bin/sh -c mkdir dir1                           0B                  
884a1d2fcbd4        34 minutes ago      /bin/sh -c touch file1                          0B                  
beae173ccac6        3 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4...   1.24MB              

执行的指令,ls /接在镜像的后面会覆盖掉镜像原有的操作指令。

--rm帮助运行完容器指令后自动删除该容器

bash 复制代码
[root@docker1 docker]# docker run --rm test:v2 ls /
bin
dev
dir1
etc
home
index.html
proc
root
sys
tmp
usr
var
[root@docker1 docker]# docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@docker1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

1.2 ADD指令用法

ADD用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:

实验环境:

bash 复制代码
[kiosk@foundation38 lamp]$ scp nginx-1.18.0.tar.gz root@172.25.254.1:/root/docker
[root@docker1 docker]# ls
Dockerfile  index.html  nginx-1.18.0.tar.gz

编写Dockefile:

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
bash 复制代码
[root@docker1 docker]# docker build -t test:v3 .
Sending build context to Docker daemon  1.043MB
Step 1/6 : FROM busybox
 ---> beae173ccac6
Step 2/6 : RUN touch file1
 ---> Using cache
 ---> 884a1d2fcbd4
Step 3/6 : RUN mkdir dir1
 ---> Using cache
 ---> 3f7259a48bfc
Step 4/6 : RUN mv file1 dir1
 ---> Using cache
 ---> b6b7f570cc47
Step 5/6 : COPY index.html /
 ---> Using cache
 ---> 317f587b99ce
Step 6/6 : ADD nginx-1.18.0.tar.gz  /
 ---> 88b81d3d9f28
Successfully built 88b81d3d9f28
Successfully tagged test:v3

解压后放入,基础镜像没有解压命令,所以在构建前用ADD构建。

bash 复制代码
[root@docker1 docker]# docker run --rm test:v3 ls /
bin
dev
dir1
etc
home
index.html
nginx-1.18.0
proc
root
sys
tmp
usr
var

1.3ENV指令用法

设置环境变量,变量可以被后续的指令使用:

变量名大写

Dockerfile写法:

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
ENV HOSTNAME docker1

1.4EXPOSE指令用法

用于应用容器,要发布一个服务的容器。

如果容器中运行应用服务,可以把服务端口暴露出去:

EXPOSE 80

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
EXPOSE 80

1.5VOLUME指令用法

应用容器的数据需要持久化

申明数据卷,通常指定的是应用的数据挂载点:

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
VOLUME ["/data"]

1.6WORKDIR指令用法

为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。即,容器内切换目录。

前面3个用法的运行结果:

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1

运行结果就不写在代码块了

bash 复制代码
[root@docker1 docker]# docker build -t test:v4 .

data是前面定义的数据卷

bash 复制代码
[root@docker1 docker]# docker run -it test:v4
/dir1 # cd /data/
/data # 

这个卷挂载你宿主机的上面

bash 复制代码
/data # mount |grep data
/dev/mapper/rhel-root on /data type xfs (rw,relatime,attr2,inode64,noquota)

docker里面看到的是宿主机的信息,磁盘、cpu、内存这些信息存在/proc,/proc是文件系统里面的不会被隔离。

bash 复制代码
/data # df
Filesystem           1K-blocks      Used Available Use% Mounted on
overlay               17811456   1594500  16216956   9% /
tmpfs                    65536         0     65536   0% /dev
tmpfs                  1023468         0   1023468   0% /sys/fs/cgroup
shm                      65536         0     65536   0% /dev/shm
/dev/mapper/rhel-root
                      17811456   1594500  16216956   9% /data
/dev/mapper/rhel-root
                      17811456   1594500  16216956   9% /etc/resolv.conf
/dev/mapper/rhel-root
                      17811456   1594500  16216956   9% /etc/hostname
/dev/mapper/rhel-root
                      17811456   1594500  16216956   9% /etc/hosts
tmpfs                  1023468         0   1023468   0% /proc/asound
tmpfs                  1023468         0   1023468   0% /proc/acpi
tmpfs                    65536         0     65536   0% /proc/kcore
tmpfs                    65536         0     65536   0% /proc/keys
tmpfs                    65536         0     65536   0% /proc/timer_list
tmpfs                    65536         0     65536   0% /proc/timer_stats
tmpfs                    65536         0     65536   0% /proc/sched_debug
tmpfs                  1023468         0   1023468   0% /proc/scsi
tmpfs                  1023468         0   1023468   0% /sys/firmware

docker运行的主机:

bash 复制代码
[root@docker1 ~]# df
Filesystem            1K-blocks    Used Available Use% Mounted on
/dev/mapper/rhel-root  17811456 1594500  16216956   9% /
devtmpfs                1011400       0   1011400   0% /dev
tmpfs                   1023468       0   1023468   0% /dev/shm
tmpfs                   1023468   17076   1006392   2% /run
tmpfs                   1023468       0   1023468   0% /sys/fs/cgroup
/dev/vda1               1038336  135172    903164  14% /boot
tmpfs                    204696       0    204696   0% /run/user/0
overlay                17811456 1594500  16216956   9% /var/lib/docker/overlay2/0d9fe361ffa5bec1667b38b2dc660e093a1dd319d69a23a6e498683163971fc5/merged

这个便是容器挂载在宿主机上面的卷

bash 复制代码
/dev/mapper/rhel-root  17811456 1594500  16216956   9% /

查看一下该容器的具体信息

docker inspect 后面可以加容器也可以镜像

bash 复制代码
[root@docker1 ~]# docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                            PORTS               NAMES
4c626bd8688f        test:v4             "sh"                14 seconds ago      Up 13 seconds                     80/tcp              romantic_bhabha
999fd34ca89f        test:v4             "sh"                4 hours ago         Exited (255) About a minute ago   80/tcp              peaceful_wing
[root@docker1 ~]# docker inspect 4c626bd8688f

inspect查询部分信息:

Gateway是宿主机上面的地址,docker 0的地址。所以容器会通过桥接的模式到达宿主机的网关

所有容器的数据会放在宿主机的/var/lib/docker,如果把这个删掉,所有的镜像容器全没了。

bash 复制代码
[root@docker1 docker]# ls
builder  buildkit  containers  image  network  overlay2  plugins  runtimes  swarm  tmp  trust  volumes

容器的卷的目录在/var/lib/docker/volumes

bash 复制代码
  "Gateway": "172.17.0.1"
  "IPAddress": "172.17.0.2",
       "Mounts": [
            {
                "Type": "volume",
                "Name": "a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171",
                "Source": "/var/lib/docker/volumes/a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]

这个路径就被挂载在容器的目录里面

bash 复制代码
"Source": "/var/lib/docker/volumes/a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171/_data",

容器里面:

bash 复制代码
/data # touch file1
/data # ls
file1

宿主机上:

bash 复制代码
[root@docker1 ~]# cd /var/lib/docker/volumes/a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171/_data
[root@docker1 _data]# ls
file1

宿主机docker0的地址:

bash 复制代码
[root@docker1 ~]# ip addr | grep 172.17.0.1
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

容器里面查询ip的结果:

bash 复制代码
/dir1 # ip addr 
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

1.7将数据存入宿主机原因

1.容器的文件系统性能比宿主机差

2.数据过大放在容器不合适,不小心删掉容器,数据就丢失了

同理存在宿主机上面:

宿主机删掉该数据,容器里面的数据就没有了

宿主机:

bash 复制代码
[root@docker1 ~]# cd /var/lib/docker/volumes/a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171/_data
[root@docker1 _data]# ls
file1
[root@docker1 _data]# rm -fr file1 

容器里面:

bash 复制代码
/data # ls
file1
/data # ls
/data # 

1.8RUN指令的用法

在容器中运行命令并创建新的镜像层,常用于安装软件包:

RUN yum install -y vim


1.9CMD与ENTRYPOINT指令的用法

这两个指令都是用于设置容器后执行的命令,但CMD会被docker run 后面的命令行覆盖(比如docker run -it /ls会覆盖掉),而ENTRYPOINT不会被忽略,一定会被执行

docker run 后面的参数可以传递给ENTRYPOINT指令当作参数

Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效

CMD当用户进入后自动执行的指令,像busybox这个镜像第二层,意思就是当用户进去后,自动执行sh

官方推荐CMD用exec格式写

bash 复制代码
[root@docker1 docker]# docker history test:v1
beae173ccac6        3 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B                  

1.10Shell 和exec格式的区别

Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而exec格式不会

而用exec格式写的话:["/bin/sh","-c","echo $变量名"]

Shell格式:

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1
CMD echo $HOSTNAME
bash 复制代码
[root@docker1 docker]# docker build -t test:v5 .
[root@docker1 docker]# docker run --rm test:v5
docker1

exec格式:

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1
CMD ["echo $HOSTNAME"]
bash 复制代码
[root@docker1 docker]# docker build -t test:v6 .
[root@docker1 docker]# docker run --rm test:v6
docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: exec: "echo $HOSTNAME": executable file not found in $PATH: unknown.
bash 复制代码
[root@docker1 docker]# docker rmi test:v6
[root@docker1 docker]# vim Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1
CMD ["/bin/echo","echo $HOSTNAME"]
bash 复制代码
[root@docker1 docker]# docker build -t test:v6 .
[root@docker1 docker]# docker run --rm test:v6
echo $HOSTNAME

用exec格式写:

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1
CMD ["/bin/echo","-c","echo $HOSTNAME"]
bash 复制代码
[root@docker1 docker]# docker build -t test:v7 .
[root@docker1 docker]# docker run --rm test:v7
docker1

Exec格式时,ENTRYPOINT可以通过CMD提供额外的参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。即ENTRYPOINT与CMD混合使用

1.11ENTRYPOINT与CMD混合使用

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM busybox
RUN touch file1
RUN mkdir dir1
RUN mv file1 dir1
COPY index.html /
ADD nginx-1.18.0.tar.gz  /
ENV HOSTNAME docker1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /dir1
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]
bash 复制代码
[root@docker1 docker]# docker build -t test:v8 .
[root@docker1 docker]# docker run --rm test:v8
hello world
[root@docker1 docker]# docker run --rm test:v8 linux
hello linux
[root@docker1 docker]# docker run --rm test:v8 yan
hello yan

END

系列文章目录

docker之封装镜像之nginx容器化3


docker


一、本文内容

学会如何自己封装一个完整的镜像,将nginx容器化并且优化该镜像

容器启动后,宿主机能上网,容器也能上网。


二、基础的镜像的选取,通过docker查找拉取

bash 复制代码
[root@docker1 yum.repos.d]# docker search rhel7

STARS是下载量
前面带有名字的都不是官方镜像,有可能有问题。

bash 复制代码
[root@docker1 yum.repos.d]# docker search centos

这个是官方镜像

为了选择自己想要的版本,去docker官方仓库查看

bash 复制代码
https://hub.docker.com/

三、nginx容器化

首先要清除前面测试的镜像

^以什么开头

bash 复制代码
[root@docker1 docker]# docker rmi `docker images | grep ^test | awk '{print $1":"$2}'`

在本地先下载一个系统的镜像

-i指定导入的系统镜像,加个bash进去交互。

bash 复制代码
[root@docker1 docker]# docker load -i rhel7.tar 
e1f5733f050b: Loading layer [==================================================>]  147.1MB/147.1MB
[root@docker1 docker]# docker run -it --name demo rhel7:latest bash

版本是7.0的

bash 复制代码
bash-4.2# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.0 (Maipo)

现在容器里面里面安装Nginx,寻找需要什么资源后,在宿主机Dockerfile里面写相关资源提交镜像后,Nginx便容器化了。

容器中:

修改yum仓库

bash 复制代码
bash-4.2# cd /etc/yum.repos.d/
bash-4.2# vi rhel7.repo            
bash-4.2# cat rhel7.repo 
[dvd]
name = rhel7
baseurl = http://172.25.138.250/westos
gpgcheck=0
enabled =1 
bash 复制代码
[root@docker1 docker]# ls
Dockerfile  index.html  nginx-1.18.0.tar.gz  rhel7.tar
[root@docker1 docker]# tar zxf nginx-1.18.0.tar.gz 
[root@docker1 docker]# docker container cp nginx-1.18.0 demo:/
[root@docker1 docker]# docker container attach demo 
bash-4.2# ls
bin   dev  home  lib64	mnt	      nginx-1.18.0.tar.gz  proc  run   srv  tmp  var
boot  etc  lib	 media	nginx-1.18.0  opt		   root  sbin  sys  usr

nginx编译需要的包

bash 复制代码
bash-4.2# yum install gcc pcre-devel openssl-devel
Error: libselinux conflicts with fakesystemd-1-14.el7.x86_64

openssl与centos依赖性冲突了,所以就不装openssl

7.0升级到7.6

Rpmdb损坏了,要升级索引数据库。

bash 复制代码
bash-4.2# yum install gcc pcre-devel -y
Rpmdb checksum is invalid: dCDPT(pkg checksums): glibc-devel.x86_64 0:2.17-260.el7 - u
bash 复制代码
bash-4.2# rpmdb --rebuilddb
bash 复制代码
bash-4.2# cd nginx-1.18.0/
bash-4.2# ls
CHANGES  CHANGES.ru  LICENSE  README  auto  conf  configure  contrib  html  man  src
bash-4.2# ./configure --prefix=/usr/local/nginx 

报错:缺少了zlib的库,这个库如果安装openssl便自动安装进去了

bash 复制代码
./configure: error: the HTTP gzip module requires the zlib library.
You can either disable the module by using --without-http_gzip_module
option, or install the zlib library into the system, or build the zlib library
statically from the source with nginx by using --with-zlib=<path> option.

编译成功

bash 复制代码
bash-4.2# ./configure --prefix=/usr/local/nginx

在宿主机里面:

/usr/local/nginx/html是nginx的默认发布目录

/usr/local/nginx/sbin/nginx运行nginx

查看一下nginx官方如何启动Nginx

bash 复制代码
[root@docker1 docker]# docker search nginx
nginx                             Official build of Nginx.                        16202               [OK]  

每次拉取都是镜像的最新版,详细看inspect,大概看history

bash 复制代码
[root@docker1 docker]# docker pull nginx
[root@docker1 docker]# docker inspect nginx:latest 

自己写必须绝对路径而不是Nginx就行

Dockerfile写法:

bash 复制代码
[root@docker1 docker]# vim Dockerfile 
[root@docker1 docker]# cat Dockerfile 
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel 
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
bash 复制代码
[root@docker1 docker]# docker build -t webserver:v1 .
Step 10/12 : RUN make
 ---> Running in 1871c9076c77
/bin/sh: make: command not found

所以需要修改一下Dockerfile
不要动上面好的部分,你在yum gcc那块添加的话,后面执行便不能用cache了,而且还可能改错。

bash 复制代码
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel 
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN yum install make -y
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

继续安装

bash 复制代码
[root@docker1 docker]# docker build -t webserver:v1 .
Successfully tagged webserver:v1
bash 复制代码
[root@docker1 docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
webserver           v1                  bdd2829a42e3        31 seconds ago      346MB

可以删掉之前做实验的容器了

bash 复制代码
[root@docker1 docker]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
1871c9076c77        644179a9b6e3        "/bin/sh -c make"   6 minutes ago       Exited (127) 6 minutes ago                        modest_buck
7aaa2d2b53da        rhel7:latest        "bash"              43 hours ago        Exited (130) 16 minutes ago                       demo
[root@docker1 docker]# docker rm 1871c9076c77 7aaa2d2b53da

启动nginx的镜像

bash 复制代码
[root@docker1 docker]# docker run -d --name nginx webserver:v1
[root@docker1 docker]# docker inspect nginx
                    "IPAddress": "172.17.0.2",
                "Source": "/var/lib/docker/volumes/70f0dede14b7c1978edb38eb49534509f1fcc205e750bb365254b75677b76005/_data",

发布失败,因为在inspect查到mount里面的宿主机挂载点覆盖点我们的卷了

bash 复制代码
[root@docker1 docker]# curl 172.17.0.2
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

重新测试:

bash 复制代码
[root@docker1 docker]# cd /var/lib/docker/volumes/70f0dede14b7c1978edb38eb49534509f1fcc205e750bb365254b75677b76005/_data
[root@docker1 _data]# vim index.html
[root@docker1 _data]# cat index.html 
www.yan.org
[root@docker1 _data]# curl 172.17.0.2
www.yan.org

Nginx容器化成功


END

系列文章目录

docker之nginx镜像优化4


docker


一、镜像优化的意义及方法

镜像的优化可以减少客户端下载时候的带宽

已经选择了精简的镜像,所以减少镜像的层数,可以把之前的RUN合并在一起。将WORKDIR切换成在RUN底下的cd

之前的Dockerfile:

bash 复制代码
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel 
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN yum install make -y
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

减少镜像层数后:

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel && cd /mnt/nginx-1.18.0 && ./configure --prefix=/usr/local/nginx && yum install make -y && make && make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

清理中间产物:/var/cache/yum yum的缓存路径,nginx安装包删掉,编译完了make gcc都可以删掉(安装make这些包时候会安装依赖性,但是删掉时候不删掉依赖性)

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && cd /mnt/nginx-1.18.0 && ./configure --prefix=/usr/local/nginx && make && make install  && rm -fr /mnt/nginx-1.18.0 /var/cache/yum 
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
bash 复制代码
[root@docker1 docker]# docker build -t webserver:v2 .

优化后镜像大小差距:

bash 复制代码
[root@docker1 docker]# docker images webserver
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
webserver           v2                  503439033877        24 seconds ago      258MB
webserver           v1                  bdd2829a42e3        36 minutes ago      346MB
bash 复制代码
[root@docker1 docker]# docker images rhel7
rhel7               latest              0a3eb3fde7fd        7 years ago         140MB

优化了:346-258,除去基础base镜像140,还是多了

可以看出多的主要在Yum里面111MB,该层主要安装包编译等

bash 复制代码
[root@docker1 docker]# docker history webserver:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
503439033877        6 minutes ago       /bin/sh -c #(nop)  CMD ["/usr/local/nginx/sb...   0B                  
c140026256fd        6 minutes ago       /bin/sh -c rpmdb --rebuilddb && yum install ...   111MB               
8b163bc5912e        7 minutes ago       /bin/sh -c #(nop) ADD file:a90dc1ecadbd423a5...   6.25MB              
b17ef4913f9c        48 minutes ago      /bin/sh -c #(nop) COPY file:fe5cdcb63a06bd4c...   67B                 
82ca7e5c38e6        49 minutes ago      /bin/sh -c #(nop)  VOLUME [/usr/local/nginx/...   0B                  
8aa3b0c110c7        49 minutes ago      /bin/sh -c #(nop)  EXPOSE 80                    0B                  
0a3eb3fde7fd        7 years ago                                                         140MB               Imported from -

可以看出v1没有优化的时候,光yum代码。

bash 复制代码
[root@docker1 docker]# docker history webserver:v1
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
bdd2829a42e3        44 minutes ago      /bin/sh -c #(nop)  CMD ["/usr/local/nginx/sb...   0B                           
9e03306cbffd        44 minutes ago      /bin/sh -c yum install make -y                  43.6MB                         
bf1e3007a03b        49 minutes ago      /bin/sh -c yum install -y gcc pcre-devel zli...   133MB               

源码编译后,真正只需要编译后的二进制代码
所以,我真正只需要/usr/local/nginx的二进制代码只有5M,其余的(中间产物)不需要,再把debug一关不到1M
可以只把操作系统编译好的源码(二进制代码)给其它操作系统直接使用


二、使用多阶段构建

分两个部分,先在一个容器编译好二进制代码再拷贝给第二个容器使用

将debug注释掉

bash 复制代码
[root@docker1 nginx-1.18.0]# vim auto/cc/gcc 
bash 复制代码
[root@docker1 nginx-1.18.0]# sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc 

全部替换完成

将该指令添加到Dockerfile中,并且多阶段构建(将上一个容器编译后的nginx的二进制编码拿来使用)

as build是给上面起名build

COPY --from=build /usr/local/nginx /usr/local/nginx 将上一个容器的二进制编码目录(/usr/local/nginx)放在下一个容器的/usr/local/nginx

暴露端口和卷都不是必须的所以删掉了,编一个最精简的Dockerfile

bash 复制代码
[root@docker1 docker]# cat Dockerfile 
FROM rhel7 as build
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && cd /mnt/nginx-1.18.0 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc  && ./configure --prefix=/usr/local/nginx && make && make install  && rm -fr /mnt/nginx-1.18.0 /var/cache/yum 

FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
bash 复制代码
[root@docker1 docker]# docker build -t webserver:v3 .

除去140MB的基础镜像base,一个nginx 1MB

bash 复制代码
[root@docker1 docker]# docker images webserver
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
webserver           v3                  5cd6dd1fdc7f        31 seconds ago      141MB
webserver           v2                  503439033877        35 minutes ago      258MB
webserver           v1                  bdd2829a42e3        About an hour ago   346MB

docker 能运行肯定nginx没问题,有问题CMD都报错了

bash 复制代码
[root@docker1 docker]# docker run -d --name nginx webserver:v3
[root@docker1 docker]# docker container inspect nginx | grep "IPAddress"
            "IPAddress": "172.17.0.2",
[root@docker1 docker]# curl 172.17.0.2
<h1>Welcome to nginx!</h1>

再优化都不可能比base镜像小

所以,在优化需要寻找更加精简的base,通过https://hub.docker.com/寻找或www.github.com或www.gitee.com上面寻找

nginx在运行时候,会调用系统的动态库文件

库文件必不缺的,缺了二进制文件就起不来了。

所以在拷贝二进制文件目录的时候把库文件也要考入,同时编译的nginx不同调用的库文件也不同,加了opensll还有lib-opensll库,所以如果换取更小的镜像的话,需要把库文件和二进制文件同时迁移。同时还要考虑这些库文件有无依赖性还要调用其他的库文件。

bash 复制代码
[root@docker1 docker]# docker run -it --rm webserver:v3 bash
bash-4.2# ldd /usr/local/nginx/sbin/nginx 
	linux-vdso.so.1 =>  (0x00007ffc06f6d000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f3560c8a000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3560a6e000)
	libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f3560837000)
	libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f35605d6000)
	libz.so.1 => /lib64/libz.so.1 (0x00007f35603c0000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f355ffff000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f3560e8e000)
	libfreebl3.so => /lib64/libfreebl3.so (0x00007f355fd80000)

在github上面搜索distroless,这个是谷歌的容器工具。

下载
我用的是debian10,导入镜像。

bash 复制代码
[root@docker1 docker]# docker load -i base-debian10.tar 

这个base镜像小

bash 复制代码
[root@docker1 docker]# docker images 
gcr.io/distroless/base-debian10   latest              d48fcdd54946        52 years ago        19.2MB

首先在github搜索distroless nginx,进去

然后查看别人写好的Dockerfile,可以看出用的是官方提供的最小镜像并且是多阶段构建,以及将系统的库文件考入。
编写Dockerfile2

bash 复制代码
[root@docker1 docker]# cat Dockerfile2
FROM nginx:1.18.0 as base

# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE

RUN mkdir -p /opt/var/cache/nginx && \
    cp -a --parents /usr/lib/nginx /opt && \
    cp -a --parents /usr/share/nginx /opt && \
    cp -a --parents /var/log/nginx /opt && \
    cp -aL --parents /var/run /opt && \
    cp -a --parents /etc/nginx /opt && \
    cp -a --parents /etc/passwd /opt && \
    cp -a --parents /etc/group /opt && \
    cp -a --parents /usr/sbin/nginx /opt && \
    cp -a --parents /usr/sbin/nginx-debug /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
    cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime

FROM gcr.io/distroless/base-debian10

COPY --from=base /opt /

EXPOSE 80 443

ENTRYPOINT ["nginx", "-g", "daemon off;"]

构建镜像,-f指定dockerfile2,要不然读取的是默认的Dockerfile

bash 复制代码
[root@docker1 docker]# docker build -t webserver:v4 -f Dockerfile2 .

效果

bash 复制代码
[root@docker1 docker]# docker images webserver
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
webserver           v4                  0fce27d5ac56        15 seconds ago      31.7MB

运行容器,运行成功。

bash 复制代码
[root@docker1 docker]# docker run -d --name nginx webserver:v4
[root@docker1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
79bc3e329d8f        webserver:v4        "nginx -g 'daemon of..."   23 seconds ago      Up 22 seconds       80/tcp, 443/tcp     nginx
bash 复制代码
[root@docker1 docker]# docker inspect nginx | grep IP
                    "IPAddress": "172.17.0.2",

访问成功

bash 复制代码
[root@docker1 docker]# curl 172.17.0.2
<h1>Welcome to nginx!</h1>

END

系列文章目录

docker之镜像加速器5


docker


配置docker镜像加速器

在拉取镜像的时候通过官网(国外)拉取慢

所以通过阿里云的镜像加速器修改docker默认仓库位置后拉取镜像速度就快了

访问阿里云官网:www.aliyun.com

点击控制台

搜索容器,选择容器镜像服务

复制上面的文档,然后镜像仓库位置变动了,拉取镜像速度变快

bash 复制代码
[root@server9 docker]# docker info 
Registry Mirrors:
  https://qwfrb104.mirror.aliyuncs.com/
 Live Restore Enabled: false

END

系列文章目录

docker之仓库原理6


docker


docker公有仓库

默认使用的是官方的仓库,官方仓库的网址:https://hub.docker.com

可以在docker官方的公共仓库上面注册自己的账号并且分享自己的封装好的镜像


docker私有仓库registry

从私有仓库拉取以及上传的原理

docker客户端通过Indx认证后,index给docker拉取仓库位置(仓库有很多个),以及token,docker访问仓库并给仓库token,仓库用docker客户端的token与index校验,校验成功后同意docker客户端拉取。

从私有仓库拉取以及上传的原理流程图

删除完镜像后,registry还要告诉indx要同步信息,在索引里面删掉该镜像。


END

系列文章目录

docker之搭建私有仓库registry7


docker


搭建私有仓库的意义

在生产环境中,你的服务器可能不能上网

在内网集群里面,布置容器大量应用的时候,成千上万的,体量很大,分布密度比传统的虚拟化大很多,分布在不同节点上面跑,从远端仓库拉取很消耗网络资源和时间,所以必须在内网里面布置一个私有仓库,让其部署效率变快。

官方文档网址:https://docs.docker.com/registry/deploying/

搭建私有仓库

在宿主机上面拉取registry镜像

bash 复制代码
[root@docker1 docker]# docker pull registry

重要信息

bash 复制代码
[root@docker1 docker]# docker history registry
<missing>           2 months ago        /bin/sh -c #(nop)  EXPOSE 5000                  0B                  
<missing>           2 months ago        /bin/sh -c #(nop)  VOLUME [/var/lib/registry]   0B                  

--restart=always开机自启动

bash 复制代码
[root@docker1 ~]#  docker run -d -p 5000:5000 --restart=always --name registry registry

向仓库上传自己的镜像,要先将镜像改名成仓库地址和端口加镜像名称,后面不加版本便为最新版

bash 复制代码
[root@docker1 ~]# docker tag webserver:v4 localhost:5000/webserver

上传

bash 复制代码
[root@docker1 ~]# docker push localhost:5000/webserver

删掉本地的镜像

bash 复制代码
[root@docker1 ~]# docker images 
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
webserver                         v4                  0fce27d5ac56        47 hours ago        31.7MB
localhost:5000/webserver          latest              0fce27d5ac56        47 hours ago        31.7MB
bash 复制代码
[root@docker1 ~]# docker rmi webserver:v4 
Untagged: webserver:v4
[root@docker1 ~]# docker rmi localhost:5000/webserver:latest 
Untagged: localhost:5000/webserver:latest
Untagged: localhost:5000/webserver@sha256:e1fcc49060c0bfcabaf933ce8ca297fc4df63b80113f5098d931f9fac65464fe
Deleted: sha256:0fce27d5ac5666a7fef70f3ad01b64177509acf11495c42ff85ef392b68e979f
Deleted: sha256:0bd5d2b3dad5cbee261f44fbe012ed0d0809990d75503463fb5d4ec17a582149
Deleted: sha256:5ee35935b3b95e4a02f7dde3541e235eb6d67421bd52157d29e13b2055dff9c2
Deleted: sha256:502cc226f58a8c7b0adf7a06b92a2d5156d08d7af7b21bc6e4d6a69

从仓库拉取镜像

bash 复制代码
[root@docker1 ~]# docker pull localhost:5000/webserver 
[root@docker1 ~]# docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
localhost:5000/webserver          latest              0fce27d5ac56        47 hours ago        31.7MB

搭建私有仓库的功能

实验环境的搭建:

开启另一个虚拟机docker2,安装上docker就行,并且启动

bash 复制代码
[root@docker2 yum.repos.d]# yum install -y docker-ce
[root@docker2 yum.repos.d]# systemctl enable docker

没有ip,所以修改内核参数,docker1修改过,把内核文件复制给docker2就可以了

bash 复制代码
[root@docker2 yum.repos.d]# docker info 
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
bash 复制代码
[root@docker1 sysctl.d]# scp docker.conf docker2:/etc/sysctl.d/
[root@docker2 yum.repos.d]# sysctl --system

无认证加密功能认证仓库的搭建

docker2 拉取docker1仓库的镜像,默认仓库是不支持非加密访问远端仓库。

bash 复制代码
[root@docker2 sysctl.d]# docker info 
Insecure Registries:
  127.0.0.0/8
bash 复制代码
[root@docker2 sysctl.d]# docker pull 172.25.254.1:5000/webserver
Using default tag: latest
Error response from daemon: Get https://172.25.254.1:5000/v2/: http: server gave HTTP response to HTTPS client

官方文档上面写的,使用一个非加密的仓库

bash 复制代码
[root@docker2 docker]# vim daemon.json
[root@docker2 docker]# cat daemon.json 
{
  "insecure-registries" : ["172.25.254.1:5000"]
}
[root@docker2 docker]# systemctl daemon-reload 
[root@docker2 docker]# systemctl restart docker

支持非安全的仓库,本地的localhost和docker1的5000端口

bash 复制代码
[root@docker2 docker]# docker info 
 Insecure Registries:
  172.25.254.1:5000
  127.0.0.0/8

拉取成功

bash 复制代码
[root@docker2 docker]# docker pull 172.25.254.1:5000/webserver
[root@docker2 docker]# docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
172.25.254.1:5000/webserver   latest              0fce27d5ac56        47 hours ago        31.7MB

搭建认证加密功能的仓库(生成证书并启动registry)

实验环境:

bash 复制代码
[root@docker1 sysctl.d]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
bcb7e7682a99        registry            "/entrypoint.sh /etc..."   53 minutes ago      Up 53 minutes       0.0.0.0:5000->5000/tcp   registry
[root@docker1 sysctl.d]# docker rm -f registry 
registry

容器删掉了,但是卷存储了容器的操作,对存储没有影响

bash 复制代码
[root@docker1 sysctl.d]# docker volume ls
DRIVER              VOLUME NAME
local               70f0dede14b7c1978edb38eb49534509f1fcc205e750bb365254b75677b76005
local               a780ebed1de6be544711f18a254682fc4f018ce2f7058b0a23f6f16a3eb73171
local               ab43717053b89c0a594289ab002bbc48ab9144075c88e5a230b78cb24250b305
local               b76dc83d8ac88ed49f725bd014ec89e97c4f7b3cc2b75a803e9c66af1b5c101e
local               f266d47b2c99eadd824c8d31ce921b03db558b0817b6bb20e36858e5000f8363

删掉本地没有被容器使用的卷

bash 复制代码
[root@docker1 sysctl.d]# docker volume prune 
bash 复制代码
[root@docker1 sysctl.d]# docker volume ls
DRIVER              VOLUME NAME

启动认证功能,首先开启其加密功能,保证认证的网络通信是加密的,不然alice截获,便成明文了,没有意义了。

读官方文档
要使用证书,所以我的证书是自签名的证书,在https://docs.docker.com/registry/insecure/有相关文档

在生产环境中的证书是从CA申请过来的,所以测试我用自签名证书
创建存放证书的目录,在linux中所以证书是通过openssl来运行的

bash 复制代码
[root@docker1 ~]# mkdir -p certs
[root@docker1 ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/yan.org.key -x509 -days 365 -out certs/yan.org.crt
bash 复制代码
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:shanxi
Locality Name (eg, city) [Default City]:xi'an
Organization Name (eg, company) [Default Company Ltd]:yan
Organizational Unit Name (eg, section) []:linux
Common Name (eg, your name or your server's hostname) []:reg.yan.org  仓库的域名      
Email Address []:

证书创建成功

bash 复制代码
[root@docker1 ~]# ls certs/
yan.org.crt  yan.org.key

-v手动挂接,将生成的/certs挂入容器的/certs

容器启动443端口加密
由于官方的,没有加入卷,到时候删掉仓库容器后,还得重新上传镜像,麻烦,所以我多加了一条指令

在宿主机/opt/registry路径(自动帮忙生成,如果有直接挂载)挂载到/var/lib/registry这个目录上面(在容器内是仓库存放镜像的位置)

bash 复制代码
-v /opt/registry:/var/lib/registry 
bash 复制代码
[root@docker1 ~]# docker run -d   --restart=always   --name registry   -v "$(pwd)"/certs:/certs -v /opt/registry:/var/lib/registry  -e REGISTRY_HTTP_ADDR=0.0.0.0:443   -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/yan.org.crt   -e REGISTRY_HTTP_TLS_KEY=/certs/yan.org.key  -p 443:443   registry

后面所有镜像保存在该位置,可以在宿主机里面做持久化

bash 复制代码
[root@docker1 ~]# ll -d /opt/registry/
drwxr-xr-x 2 root root 6 Feb  6 21:10 /opt/registry/
bash 复制代码
[root@docker1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                            NAMES
da3da9151ec0        registry            "/entrypoint.sh /etc..."   2 minutes ago       Up About a minute   0.0.0.0:443->443/tcp, 5000/tcp   registry
[root@docker1 ~]# docker port registry 
443/tcp -> 0.0.0.0:443

远程连接:

在docker2加入解析docker1的仓库

bash 复制代码
[root@docker2 docker]# sudo vim /etc/hosts

远程上传:

默认端口是443可以不用加

bash 复制代码
[root@docker2 docker]# docker tag nginx:latest reg.yan.org/nginx
[root@docker2 docker]# docker push reg.yan.org/nginx
The push refers to repository [reg.yan.org/nginx]
Get https://reg.yan.org/v2/: x509: certificate signed by unknown authority

缺少证书,需要添加证书,让docker引擎识别到证书

所有客户端都需要证书,一旦启动加密功能以后

后面端口不用加,默认是443,加个:443也可以

只要访问reg.yan.org这个仓库,它会自动去这个路经找证书,证书是docker1创建的

bash 复制代码
[root@docker2 docker]# mkdir /etc/docker/certs.d
[root@docker2 docker]# cd certs.d/
[root@docker2 certs.d]# mkdir reg.yan.org
/etc/docker/certs.d/reg.yan.org
bash 复制代码
[root@docker1 ~]# cd certs/
[root@docker1 certs]# ls
yan.org.crt  yan.org.key
[root@docker1 certs]# scp yan.org.crt docker2:/etc/docker/certs.d/reg.yan.org/ca.crt
bash 复制代码
[root@docker2 reg.yan.org]# ls
ca.crt

有了证书,远程上传成功

bash 复制代码
[root@docker2 reg.yan.org]# docker push reg.yan.org/nginx 

上传的镜像会保存到/opt/registry持久化了,实际是上传到容器内/var/lib/registry,但是你实际是把宿主机的目录挂在/var/lib/registry,所以会持久化

搭建registry的认证功能

在官方文档https://docs.docker.com/registry/deploying/

官方是通过运行httpd镜像容器,然后使用htpasswd加密生成用户加密文件,所以我们安装了http-tools,不需要运行容器来加密,麻烦。

调用了htpasswd工具生成用户名密码的认证文件,这是http中的工具

bash 复制代码
[root@docker1 ~]# mkdir auth
[root@docker1 ~]# cd auth/
[root@docker1 auth]# yum install -y httpd-tools
[root@docker1 auth]# htpasswd --help
-B -b -n 都有
 -B  Force bcrypt encryption of the password (very secure).
 -n  Don't update file; display results on stdout.
 -b  Use the password from the command line rather than prompting for it.
 -C  Set the computing time used for the bcrypt algorithm
 (higher is more secure but slower, default: 5, valid: 4 to 31).

第一次要加-c,第二次再使用就第一次的就被覆盖掉了

bash 复制代码
[root@docker1 auth]# cat htpasswd 
ywq:$2y$05$fKzYdI2UoQqofccJO0F.VutAC4Akv7z9LdPoH7G2I134KxLD1l4fy
zrx:$2y$05$c77YlrPXP1oz6M6LRwydyOrywlVnvT28GGQWGwniscZe58F21mF6C
bash 复制代码
[root@docker1 ~]# docker rm -f registry 

将认证目录挂载到容器内的/auth,告诉要启动htpasswd认证方式,读取该认证文件,修改仓库参数

--restart=always随着docker引擎的启动,该registry容器启动

bash 复制代码
[root@docker1 ~]# docker run -d   --restart=always   --name registry   -v "$(pwd)"/certs:/certs -v /opt/registry:/var/lib/registry   -v "$(pwd)"/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -e REGISTRY_HTTP_ADDR=0.0.0.0:443   -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/yan.org.crt   -e REGISTRY_HTTP_TLS_KEY=/certs/yan.org.key  -p 443:443   registry
832e2bdb222d16ac3c25521d1a8420d48c4e4d6ce71028217f47a142d7709d01

远程上传拉取(缺少认证):

bash 复制代码
[root@docker2 reg.yan.org]# docker push reg.yan.org/nginx 
no basic auth credentials
[root@docker2 reg.yan.org]# docker pull reg.yan.org/nginx 
Using default tag: latest
Error response from daemon: Get https://reg.yan.org/v2/nginx/manifests/latest: no basic auth credentials
bash 复制代码
[root@docker2 reg.yan.org]# docker login reg.yan.org
Username: ywq
Password: 
Login Succeeded

成功后会存储到这个文件

bash 复制代码
[root@docker2 ~]# cd .docker/
[root@docker2 .docker]# ls
config.json
[root@docker2 .docker]# cat config.json 
{
	"auths": {
		"reg.yan.org": {
			"auth": "eXdxOndlc3Rvcw=="
		}
	},
	"HttpHeaders": {
		"User-Agent": "Docker-Client/19.03.15 (linux)"
	}
}
bash 复制代码
[root@docker2 .docker]# docker logout reg.yan.org
Removing login credentials for reg.yan.org
[root@docker2 .docker]# cat config.json 
{
	"auths": {},
	"HttpHeaders": {
		"User-Agent": "Docker-Client/19.03.15 (linux)"
	}
}

所以只要就登陆一次就记录了,不需要重复登陆,除非你注销了。

认证后,远程上传成功

bash 复制代码
[root@docker2 .docker]# docker push reg.yan.org/nginx 

END

系列文章目录

docker之harbor仓库8


docker


一、harbor仓库(最小化安装)的搭建及用法

harbor仓库作为企业级仓库:提供了镜像扫描、病毒扫描、签名

harbor仓库每次启动时会开启许多容器,可以提供web操作页面
docker-compose负责单个节点控制多个容器

软件下载位置:https://github.com/goharbor/harbor/releases
解压后里面的压缩包是所有harbor仓库的镜像,其余的是配置文件

bash 复制代码
[root@docker1 /]# tar zxf harbor-offline-installer-v1.10.1.tgz
[root@docker1 /]# cd harbor/
[root@docker1 harbor]# ls
common.sh  harbor.v1.10.1.tar.gz  harbor.yml  install.sh  LICENSE  prepare

修改harbor配置文件

bash 复制代码
[root@docker1 harbor]# vim harbor.yml 

可以看见它默认的数据目录在/data

bash 复制代码
[root@docker1 harbor]# mkdir /data
[root@docker1 harbor]# cp -r /root/certs/ /data/
[root@docker1 harbor]# vim harbor.yml

默认会开启80和443去发布,但是80是默认端口,如果443开启了会重定向到443

主机名必须与仓库生成证书的主机名保持一致
reg.yan.org就是服务器docker1,添加域名方便访问

设置一个管理员登陆的密码

安装harbor,提醒缺少docker-compose依赖性

bash 复制代码
[root@docker1 harbor]# ./install.sh 
✖ Need to install docker-compose(1.18.0+) by yourself first and run this script again.
bash 复制代码
[root@docker1 /]# mv docker-compose-Linux-x86_64-1.27.0 /usr/local/bin/docker-compose
[root@docker1 /]# chmod +x /usr/local/bin/docker-compose 

查看一下安装的参数

bash 复制代码
[root@docker1 harbor]# ./install.sh --help
--with-notary 镜像签名,只有签名过的镜像能部署,如果没有签名,拉取镜像是失败的(镜像安全)
--with-clair  镜像扫描器,扫描镜像里面的漏洞与缺陷
--with-chartmuseum k8s中的软件包管理,可以存放镜像还可以存放k8s的软件包。k8s有个应用ham应用专门把软件打成软件包来进行维护

最小化安装

bash 复制代码
[root@docker1 harbor]# ./install.sh 

安装好以后,之后的管理都在/harbor(安装harbor的目录)交给docker-compose来管理

docker-compose会在/harbor读取.yml文件,它会通过脚本解析harbor.yml来生成docker-compose.yml

bash 复制代码
[root@docker1 harbor]# ls
docker-compose.yml harbor.yml

因为一共开启了9个容器,不好管理,也不知道容器之间的关系,所以用docker-compose来管理

bash 复制代码
[root@docker1 harbor]# docker ps 
CONTAINER ID        IMAGE                                                     COMMAND                  CREATED             STATUS                             PORTS                                         NAMES
56f638dce977        goharbor/nginx-photon:v1.10.1                             "nginx -g 'daemon of..."   19 seconds ago      Up 12 seconds (health: starting)   0.0.0.0:80->8080/tcp, 0.0.0.0:443->8443/tcp   nginx
8d7514279f86        goharbor/harbor-jobservice:v1.10.1                        "/harbor/harbor_jobs..."   19 seconds ago      Up 14 seconds (health: starting)                                                 harbor-jobservice
eba94647a312        goharbor/harbor-core:v1.10.1                              "/harbor/harbor_core"    21 seconds ago      Up 18 seconds (health: starting)                                                 harbor-core
85c0de195cd0        goharbor/harbor-db:v1.10.1                                "/docker-entrypoint...."   28 seconds ago      Up 25 seconds (health: starting)   5432/tcp                                      harbor-db
ca1121fe1d31        goharbor/registry-photon:v2.7.1-patch-2819-2553-v1.10.1   "/home/harbor/entryp..."   28 seconds ago      Up 20 seconds (health: starting)   5000/tcp                                      registry
89cf045cb2ea        goharbor/redis-photon:v1.10.1                             "redis-server /etc/r..."   28 seconds ago      Up 23 seconds (health: starting)   6379/tcp                                      redis
807ff92faad0        goharbor/harbor-registryctl:v1.10.1                       "/home/harbor/start...."   28 seconds ago      Up 22 seconds (health: starting)                                                 registryctl
1fb2951ae681        goharbor/harbor-portal:v1.10.1                            "nginx -g 'daemon of..."   28 seconds ago      Up 20 seconds (health: starting)   8080/tcp                                      harbor-portal
604de693ca95        goharbor/harbor-log:v1.10.1                               "/bin/sh -c /usr/loc..."   30 seconds ago      Up 28 seconds (health: starting)   127.0.0.1:1514->10514/tcp                     harbor-log
[root@docker1 harbor]# docker ps -aq
56f638dce977
8d7514279f86
eba94647a312
85c0de195cd0
ca1121fe1d31
89cf045cb2ea
807ff92faad0
1fb2951ae681
604de693ca95
[root@docker1 harbor]# docker ps -aq | wc -l
9

docker-compose管理

bash 复制代码
[root@docker1 harbor]# docker-compose ps
      Name                 Command              State               Ports        
---------------------------------------------------------------------------------
harbor-core         /harbor/harbor_core      Up (healthy)                        
harbor-db           /docker-entrypoint.sh    Up (healthy)   5432/tcp             
harbor-jobservice   /harbor/harbor_jobserv   Up (healthy)                        
                    ice  ...                                                     
harbor-log          /bin/sh -c               Up (healthy)   127.0.0.1:1514->10514
                    /usr/local/bin/ ...                     /tcp                 
harbor-portal       nginx -g daemon off;     Up (healthy)   8080/tcp             
nginx               nginx -g daemon off;     Up (healthy)   0.0.0.0:80->8080/tcp,
                                                            0.0.0.0:443->8443/tcp
redis               redis-server             Up (healthy)   6379/tcp             
                    /etc/redis.conf                                              
registry            /home/harbor/entrypoin   Up (healthy)   5000/tcp             
                    t.sh                                                         
registryctl         /home/harbor/start.sh    Up (healthy)                        

如果在启动的时候有容器没有启动起来

bash 复制代码
[root@docker1 harbor]# docker-compose start
Starting log         ... done
Starting registry    ... done
Starting registryctl ... done
Starting postgresql  ... done
Starting portal      ... done
Starting redis       ... done
Starting core        ... done
Starting jobservice  ... done
Starting proxy       ... done

使用web管理harbor
这个仓库,library是默认项目(仓库分类),可以匿名拉取的
给仓库上传镜像,先给解析

bash 复制代码
[root@docker1 harbor]# cat /etc/hosts
172.25.254.1   docker1 reg.yan.org

证书有问题给docker1添加一个证书

bash 复制代码
[root@docker1 harbor]# docker login reg.yan.org
Username: admin
Password: 
Error response from daemon: Get https://reg.yan.org/v2/: x509: certificate signed by unknown authority
bash 复制代码
[root@docker1 harbor]# cd /etc/docker/
[root@docker1 docker]# mkdir certs.d
[root@docker1 docker]# cd certs.d/
[root@docker1 certs.d]# mkdir reg.yan.org
[root@docker1 certs.d]# cd reg.yan.org/
[root@docker1 reg.yan.org]# cp /data/certs/yan.org.crt ca.crt

所有harbor仓库的数据都持久化到/data了,添加不同的模块这个目录就记录下来了,可以看出harbor用了registry官方镜像

bash 复制代码
[root@docker1 reg.yan.org]# cd /data/
[root@docker1 data]# ls
ca_download  certs  database  job_logs  psc  redis  registry  secret
bash 复制代码
[root@docker1 data]# docker login reg.yan.org
Username: admin
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

上传成功,上传的时候必须添加仓库的url+仓库的项目+镜像的名字+版本号

不加版本号的话,签名是不生效的,签名只针对你的标签(版本号)

bash 复制代码
[root@docker1 data]# docker tag busybox:latest reg.yan.org/library/busybox:latest
[root@docker1 data]# docker push reg.yan.org/library/busybox:latest 

便可以在日志查看到上传成功

新建一个私有的项目
向私有项目上传镜像

bash 复制代码
[root@docker1 data]# docker tag yakexi007/game2048:latest reg.yan.org/yan/game2048:latest
[root@docker1 data]# docker push reg.yan.org/yan/game2048:latest

远程用户拉取本地仓库

由于docker2的指向仓库不是reg.yan.org所以拉取必须要加仓库名字,并且给docker2加解析拉取变快

bash 复制代码
[root@docker2 ~]# docker info 
bash 复制代码
[root@docker2 ~]# docker pull reg.yan.org/library/busybox:latest

可以查看日志,匿名用户(docker2)拉取镜像了
太麻烦了,拉取镜像还得加仓库名字

修改docker2仓库定向(和阿里云加速器重定向修改一样,把阿里云加速器的地址换成自己的仓库的地址就行了)

bash 复制代码
[root@docker2 ~]# cd /etc/docker/
[root@docker2 docker]# vim daemon.json 
[root@docker2 docker]# cat daemon.json 
{
  "registry-mirrors": ["https://reg.yan.org"]
}
[root@docker2 docker]# systemctl daemon-reload 
[root@docker2 docker]# systemctl restart docker
[root@docker2 docker]# docker info 

重定向生效

直接到本地仓库的默认library拉取,默认情况都会找library项目

bash 复制代码
[root@docker2 docker]# docker pull busybox

需要认证,因为不是公开的,不支持匿名下载。

bash 复制代码
[root@docker2 docker]# docker pull yan/game2048:latest
Error response from daemon: pull access denied for yan/game2048, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

创建用户
将用户添加到yan(私有仓库里)
拉取成功,并且私有仓库不暴露对外,不加本地仓库名字这个时候是去docker官方仓库拉取

bash 复制代码
[root@docker2 docker]# docker login reg.yan.org
Username: ywq
Password: 
Login Succeeded
[root@docker2 docker]# docker pull yan/game2048:latest
[root@docker2 docker]# docker pull reg.yan.org/yan/game2048:latest
latest: Pulling from yan/game2048
534e72e7cedc: Pull complete 
f62e2f6dfeef: Pull complete 
fe7db6293242: Pull complete 
3f120f6a2bf8: Pull complete 
4ba4e6930ea5: Pull complete 
Digest: sha256:8a34fb9cb168c420604b6e5d32ca6d412cb0d533a826b313b190535c03fe9390
Status: Downloaded newer image for reg.yan.org/yan/game2048:latest
reg.yan.org/yan/game2048:latest
[root@docker2 docker]# docker pull yan/game2048:latest
Error response from daemon: pull access denied for yan/game2048, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

二、 harbor仓库添加功能模板(安全模块签名和扫描)

扫描配合是否阻止潜在漏洞镜像来使用

官方文档地址:https://goharbor.io/docs/1.10/working-with-projects/working-with-images/pulling-pushing-images/

先停掉所有容器,并且删掉

由于之前导入过镜像,我们只删掉容器了,没有删镜像,所有这次加载快,因为镜像都导入过了

bash 复制代码
[root@docker1 docker]# cd /harbor
[root@docker1 harbor]# docker-compose stop
[root@docker1 harbor]# docker-compose rm
Are you sure? [yN] y
[root@docker1 harbor]# ./install.sh --with-notary --with-clair --with-chartmuseum
[root@docker1 harbor]# docker ps -aq|wc -l
14

这一次容器更多了,添加功能了
扫描镜像

项目配置里面有自动扫描,但是最好不开
它是会自动扫描的,每扫描一次相当于在虚拟机里面做了变更,虚拟机是属于copy-on-write的机制

它的一个子镜像,每次在子镜像做一次扫描,它的数据是变更的,一旦变更后它会大量复制母镜像的数据,只要会导致你子镜像越来越大,很快就塞满磁盘了,我的虚拟机设置是20G,一旦到了20G这个子镜像就不能使用了。这个扫描功能是你服务重启的时候,比如你重启你的虚拟机,这个扫描就会重新扫描一遍

bash 复制代码
[kiosk@foundation38 Pictures]$ cd /var/lib/libvirt/images/
[kiosk@foundation38 images]$ qemu-img info docker3
image: docker3
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 52M
cluster_size: 65536
backing file: new.qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

Helm Charts在k8s,由于在k8s要写大量的配置文件,为了便于管理Helm Charts将配置文件打包管理,类似操作系统的yum
删除镜像时候要垃圾清理,不然实际不会删掉的

镜像的签名部署

部署根证书,在/etc/docker,docker引擎就能识别到

开启docker内容信任变量后,上传下载镜像都要认证

bash 复制代码
[root@docker1 ~]# cd .docker/
[root@docker1 .docker]# ls
config.json
[root@docker1 .docker]# mkdir -p tls/reg.yan.org:4443/
[root@docker1 .docker]# cd tls/
[root@docker1 tls]# cd reg.yan.org\:4443/
[root@docker1 reg.yan.org:4443]# cp /etc/docker/certs.d/reg.yan.org/ca.crt .
[root@docker1 reg.yan.org:4443]# export DOCKER_CONTENT_TRUST=1
[root@docker1 reg.yan.org:4443]# export DOCKER_CONTENT_TRUST_SERVER=https://reg.yan.org:4443

开启认证功能后,必须带标签,因为签名就看标签
两个密码,如果镜像名字变更了,root key变更,镜像名不变,版本号变更,根key就不需要输入

每次只是变更v1 v2版本标签,你只需要输入仓库密码就行

bash 复制代码
[root@docker1 reg.yan.org:4443]# docker push reg.yan.org/library/busybox:latest
Enter passphrase for new root key with ID c9c5ba5: 
Repeat passphrase for new root key with ID c9c5ba5: 
Enter passphrase for new repository key with ID 38e3345: 
Repeat passphrase for new repository key with ID 38e3345: 
Successfully signed reg.yan.org/library/busybox:latest

远程部署:没有签名不能部署

bash 复制代码
[root@docker2 reg.yan.org]# docker pull reg.yan.org/library/webserver:v3
Error response from daemon: unknown: The image is not signed in Notary.

签名

bash 复制代码
[root@docker1 reg.yan.org:4443]# docker push reg.yan.org/library/webserver:v3 
Enter passphrase for root key with ID c9c5ba5: 
Enter passphrase for new repository key with ID 8b13ceb: 
Repeat passphrase for new repository key with ID 8b13ceb: 
Finished initializing "reg.yan.org/library/webserver"
Successfully signed reg.yan.org/library/webserver:v3

部署成功

bash 复制代码
[root@docker2 reg.yan.org]# docker pull reg.yan.org/library/webserver:v3

删除签名

bash 复制代码
[root@docker1 reg.yan.org:4443]# docker trust revoke reg.yan.org/library/webserver:v3 
Enter passphrase for repository key with ID 8b13ceb: 
Successfully deleted signature for reg.yan.org/library/webserver:v3

重新安装harbor签名和认证功能不加了,加了消耗内存,只加chartmuseum为了以后的k8s实验

bash 复制代码
[root@docker1 reg.yan.org:4443]# cd /harbor/
[root@docker1 harbor]# docker-compose stop 
[root@docker1 harbor]# docker-compose rm
[root@docker1 harbor]# unset DOCKER_CONTENT_TRUST 取消内容信任
[root@docker1 harbor]# ./install.sh --with-chartmuseum

但是不是所有的东西都被删除了,认证还有

bash 复制代码
[root@docker1 ~]# cd /data/
[root@docker1 data]# ls
ca_download  chart_storage  job_logs  redis     secret
certs        database       psc       registry

如果要变更harbor的yml文件,在安装的时候要./prepare,重新生成docker-compose.yml文件

bash 复制代码
[root@docker1 data]# cd /harbor/
[root@docker1 harbor]# ls
docker-compose.yml harbor.yml
[root@docker1 harbor]# vim harbor.yml 
[root@docker1 harbor]# ./prepare 

END

系列文章目录

docker之网络(原生网络与自定义网络)9


docker


一、本文内容

本文章写的是单机的多容器之间网络通信 以及跨主机容器的网络通信


二、 docker原生网络

删掉没有使用的网络,prune这个参数是docker每个指令都有的。

bash 复制代码
[root@docker1 harbor]# docker network prune 
Are you sure you want to continue? [y/N] y

docker 原生网络 bridge host null ,默认情况用的是桥接

bash 复制代码
[root@docker1 harbor]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
8db80f123dd8        bridge              bridge              local
b51b022f8430        host                host                local
c386dbae12f0        none                null                local

2.1容器间如何通信

2.1.1桥接模式

docker0是当前这个主机所有容器的网关,容器地址在默认分配上是单调递增的,第一个是0.2,第二个是0.3...

当容器停掉后,它的ip资源就会被释放出来,然后分配给其它容器,ip地址在容器里面是会变的是动态的

首先安装一个工具,这个工具是来操作桥接口的,桥接网卡掉了后,可以通过这个工具加上去

bash 复制代码
[root@docker1 harbor]# yum install bridge-utils.x86_64 -y
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b9a15b22	no		

veth7c468c6是容器的虚拟网卡,容器桥接上去了,一头在容器内网络,一头在docker0

bash 复制代码
[root@docker1 harbor]# docker run -d --name nginx nginx
[root@docker1 harbor]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
f28a0d105547        nginx               "/docker-entrypoint...."   3 seconds ago       Up 2 seconds        80/tcp              nginx
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b9a15b22	no		veth7c468c6

虚拟网卡docker0上是39,容器里面可能就是40,一个网线的两端

veth7c468c6@if39:

bash 复制代码
[root@docker1 harbor]# ip addr show
40: veth7c468c6@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether aa:23:2b:fe:e9:94 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::a823:2bff:fefe:e994/64 scope link 
       valid_lft forever preferred_lft forever
bash 复制代码
[root@docker1 harbor]# docker run -d --name nginx2 nginx
f640de1d58fe3628540618fc03aa8f4fe4259c55fec6d22eb41b741b94b6ae24
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b9a15b22	no		veth5af9c0d
							veth7c468c6

ip是单调递增的

bash 复制代码
[root@docker1 harbor]# ip addr show docker0 
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

所以

bash 复制代码
[root@docker1 harbor]# curl 172.17.0.2
<title>Welcome to nginx!</title>
[root@docker1 harbor]# curl 172.17.0.3
<h1>Welcome to nginx!</h1>

容器通过nat可以访问外网,开启了地址伪装MASQUERADE

容器通过虚拟网络对桥接到docker0上面,docker0通过eth0(打开内核路由功能 ipv4=1)来发送外网

bash 复制代码
[root@docker1 harbor]# iptables -t nat -nL
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           

2.1.2host共享宿主机的网络

默认是桥接,所以要用--network参数

bash 复制代码
[root@docker1 harbor]# docker run -d --name demo --network host nginx

里面只有一个虚拟网卡,host不会生成虚拟网卡,直接使用宿主机的网络 就有公有ip了,外网可以访问容器,但是需要避免端口冲突,避免容器之间和容器与宿主机间的冲突

bash 复制代码
[root@docker1 harbor]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
1b9e64aaa49a        nginx               "/docker-entrypoint...."   About a minute ago   Up About a minute                       demo
f28a0d105547        nginx               "/docker-entrypoint...."   14 minutes ago       Up 14 minutes       80/tcp              nginx
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b9a15b22	no		veth7c468c6

host网络模式

bash 复制代码
[root@docker1 harbor]# curl 172.25.254.1
<title>Welcome to nginx!</title>

端口冲突,启动不了

bash 复制代码
[root@docker1 harbor]# docker run -d --name demo2 --network host nginx
[root@docker1 harbor]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
1b9e64aaa49a        nginx               "/docker-entrypoint...."   9 minutes ago       Up 9 minutes                            demo
f28a0d105547        nginx               "/docker-entrypoint...."   21 minutes ago      Up 21 minutes       80/tcp              nginx
[root@docker1 harbor]# docker logs demo2
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

host直连不需要nat,但是


2.1.3none模式

禁用网络模式,不给容器ip地址

bash 复制代码
[root@docker1 harbor]# docker run -d --name demo2  --network none nginx
[root@docker1 harbor]# docker run -it --rm --network none busybox
/ # ip addr 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever

有些容器保存比较机密的东西如密码散列,不需要网络


三、docker自定义网络

overlay是互联网常用,三大运营商常用macvlan(底层硬件方式去解决网络跨主机通信)

自定义bridge可以自己固定某个容器的ip,而bridge在容器使用时会自动分配一个ip如1,关闭后重启,可能就不是ip1变成ip2等等。

自定义bridge还可以自定义ip网段和子网地址等
创建自定义网桥,默认自定义网络是bridge

bash 复制代码
[root@docker1 harbor]# docker network --help
[root@docker1 harbor]# docker network create my_net1
[root@docker1 harbor]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
8db80f123dd8        bridge              bridge              local
b51b022f8430        host                host                local
18fb73b3c2f5        my_net1             bridge              local
c386dbae12f0        none                null                local

harbor也是自己创建的仓库,因为它可以自动DNS解析容器名称到IP,所以容器用bridge网桥的时候,建议使用自己创建的
不加网络参数默认会桥接到原生的bridge中

bash 复制代码
[root@docker1 harbor]# docker run -d --name web1 nginx
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
br-18fb73b3c2f5		8000.024231c9d512	no		
docker0		8000.0242b9a15b22	no		veth2e47b03
[root@docker1 harbor]# docker run -d --name web2 --network my_net1 nginx
[root@docker1 harbor]# brctl show
bridge name	bridge id		STP enabled	interfaces
br-18fb73b3c2f5		8000.024231c9d512	no		veth231ba38
docker0		8000.0242b9a15b22	no		veth2e47b03

这个容器默认是原生bridge,是不提供解析的

bash 复制代码
[root@docker1 harbor]# docker run -it --rm busybox
ping: bad address 'web1'
/ # ping 172.17.0.2
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.059 ms
/ # ping web2
ping: bad address 'web2'

自定义网桥功能

通过DNS解析来通信

bash 复制代码
[root@docker1 harbor]# docker run -it --rm --network my_net1 busybox
/ # ping web2
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.120 ms
/ # ping web1
ping: bad address 'web1'

ping 不同web1,因为自定义的网段和docker0网段不同

bash 复制代码
[root@docker1 harbor]# ip addr show
43: br-18fb73b3c2f5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:31:c9:d5:12 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-18fb73b3c2f5
       valid_lft forever preferred_lft forever
    inet6 fe80::42:31ff:fec9:d512/64 scope link 
       valid_lft forever preferred_lft forever
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

容器的ip是动态的,用ip通信不行,ip是动态变更的,用容器名字来通信

bash 复制代码
[root@docker1 harbor]# docker stop web2
[root@docker1 harbor]# docker run -d --name web3 --network my_net1 nginx
[root@docker1 harbor]# docker start web2 
[root@docker1 harbor]# docker run -it --rm --network my_net1 busybox
/ # ping web2
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.051 ms
bash 复制代码
[root@docker1 harbor]# docker network create --help
[root@docker1 harbor]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 my_net2
3043c2a41e35d3a32a7a649fcaa3b4b0b2d3700121751b9a63415b6d31308bae
[root@docker1 harbor]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
8db80f123dd8        bridge              bridge              local
b51b022f8430        host                host                local
18fb73b3c2f5        my_net1             bridge              local
3043c2a41e35        my_net2             bridge              local
c386dbae12f0        none                null                local
[root@docker1 harbor]# ip addr show  生成桥接口了
58: br-3043c2a41e35: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:4f:90:95:90 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/24 brd 172.20.0.255 scope global br-3043c2a41e35
       valid_lft forever preferred_lft forever
bash 复制代码
[root@docker1 harbor]# docker run -d --name web4 --network my_net2 --ip 172.20.0.100 nginx
[root@docker1 harbor]# docker inspect web4
bash 复制代码
[root@docker1 harbor]# docker stop web4
[root@docker1 harbor]# docker start web4 
[root@docker1 harbor]# docker inspect web4


必须是自定义的网段上面才能--ip
my_net1没有自定义网段

bash 复制代码
[root@docker1 harbor]# docker run -d --name web5 --network my_net1 --ip 172.18.0.100 nginx
docker: Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.

docker为了安全,所以隔离不同的network,查看它的策略都是DROP丢弃的

不同网桥的容器通信不要调整它的策略这样会破坏它的隔离性

bash 复制代码
[root@docker1 ~]# iptables -L
Chain DOCKER-ISOLATION-STAGE-2 (3 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

web3 my_net1 web4 my_net2,让其互通

给web3添加一块my_net1的网卡

bash 复制代码
[root@docker1 ~]# docker network connect my_net1 web4
[root@docker1 ~]# docker inspect web3



四、Docker容器通信

Joined容器:

共享一个容器的网络,两个不同容器可以通过localhost高速通信

比如lamp架构,nginx mysql php可以不同容器部署运行,但是通过localhost访问,只是通过不同的端口访问,比如mysql3306,php9000,nginx80。

web3是my_net1

bash 复制代码
[root@docker1 ~]# docker inspect web3
                    "Gateway": "172.18.0.1",

共享web3的ip地址

bash 复制代码
[root@docker1 ~]# docker pull radial/busyboxplus
[root@docker1 ~]# docker tag radial/busyboxplus:latest busyboxplus:latest 
[root@docker1 ~]# docker run -it --rm --network container:web3 busyboxplus
/ # ip addr
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
   / # curl localhost
<title>Welcome to nginx!</title>


默认网络没有解析,给默认网路添加DNS解析 ,当容器重启后,ip变更,它的解析也自动变更。

主机名:别名,可以通信ping主机名也可以通信别名

这种不如直接用自定义的briege里面的DNS

bash 复制代码
[root@docker1 ~]# docker run -it --rm --link web3:nginx --network my_net1 busyboxplus
/ # ip addr
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth0
/ # ping web3
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.057 ms
bash 复制代码
/ # env
HOSTNAME=ca85afe9651d
SHLVL=1
HOME=/
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

web1桥接的是docker0,env它将变量和解析加进去了

bash 复制代码
[root@docker1 ~]# docker inspect web1
                    "IPAddress": "172.17.0.2",
[root@docker1 ~]# docker run -it --rm --link web1:nginx  busyboxplus
/ # ping web1
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.060 ms
/ # env
HOSTNAME=01ba3b877905
SHLVL=1
HOME=/
NGINX_ENV_PKG_RELEASE=1~bullseye
NGINX_PORT_80_TCP=tcp://172.17.0.2:80
NGINX_ENV_NGINX_VERSION=1.21.5
NGINX_ENV_NJS_VERSION=0.7.1
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_PORT=tcp://172.17.0.2:80
NGINX_NAME=/sad_benz/nginx
PWD=/
NGINX_PORT_80_TCP_ADDR=172.17.0.2
NGINX_PORT_80_TCP_PORT=80
NGINX_PORT_80_TCP_PROTO=tcp
/ # ping nginx
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.052 ms
/ # cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	nginx 2fc55fe8c1fd web1
172.17.0.3	01ba3b877905
加解析了

所以--link不能用于自定义网络,只能用于默认网络。

默认网络没有解析

bash 复制代码
/ # ping web1
ping: bad address 'web1'

并且它的解析会随着容器ip地址的变更而变更,但是它写入的变量env不会变更

将web1关闭启动变更它的ip,它的解析也变更了

bash 复制代码
/ # cat /etc/hosts
172.17.0.2	nginx 2fc55fe8c1fd web1
/ # cat /etc/hosts
172.17.0.4	nginx 2fc55fe8c1fd web1

数据如何进来以及如何出去

每加一个,开启一个虚拟伪装

bash 复制代码
[root@docker1 ~]# iptables -t nat -nL
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.20.0.0/24        0.0.0.0/0           

docker0与真实网卡,通过Linux内核实现数据包的路由
双冗余,一个通过iptable火墙转发,一种通过进程代理来实现,两种存在一个都可以生效(外网访问容器)

docker prox不能完全替代iptable DNAT因为转发还要用iptable
清空容器

bash 复制代码
[root@docker1 ~]# docker ps -aq
81cd079f1e08
f7d480524524
e305ecfdc237
7b5f010de330
ddcac54b82da
2fc55fe8c1fd
[root@docker1 ~]# docker rm -f `docker ps -aq` 

当访问本机的80会重定向到容器的80端口

bash 复制代码
[root@docker1 ~]# docker run -d --name demo -p 80:80 nginx
[root@docker1 ~]# iptables -t nat -nL
Chain DOCKER (2 references)
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80
bash 复制代码
[root@docker1 ~]# curl 172.25.254.1
<title>Welcome to nginx!</title>

专门的进程,监听80端口,双冗余

bash 复制代码
[root@docker1 ~]# netstat -antlp
 tcp6       0      0 :::80                   :::*                    LISTEN      7569/docker-proxy   

证明外部访问容器是双冗余

宿主机直接走的网关docker0 ping通

bash 复制代码
[root@docker1 ~]# iptables -t nat -F
[root@docker1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain DOCKER (0 references)
target     prot opt source               destination    

因为都在一个网桥不需要火墙和prox进程

bash 复制代码
/ # ping 172.17.0.2
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.079 ms
[root@docker1 ~]# ps ax
 7569 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -contai
[root@docker1 ~]# kill 7569
/ # ping 172.17.0.2
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.065 ms

外部就不通了

没有火墙和proxy关了,外部进不来了

bash 复制代码
[kiosk@foundation38 Desktop]$ curl 172.25.254.1
curl: (7) Failed to connect to 172.25.254.1 port 80: Connection refused

关闭火墙外部数据还是能进入容器,通过docker proxy

bash 复制代码
[root@docker1 ~]# systemctl restart docker
[root@docker1 ~]# iptables -t nat -nL
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.20.0.0/24        0.0.0.0/0           
[root@docker1 ~]# docker start demo 
[root@docker1 ~]# iptables -t nat -nL
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.20.0.0/24        0.0.0.0/0           
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80
[kiosk@foundation38 Desktop]$ curl 172.25.254.1
<title>Welcome to nginx!</title>
[root@docker1 ~]# ps ax | grep proxy
8496 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
 8572 pts/1    S+     0:00 grep --color=auto proxy
[root@docker1 ~]# iptables -t nat -F
[root@docker1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain DOCKER (0 references)
target     prot opt source               destination         
[kiosk@foundation38 Desktop]$ curl 172.25.254.1
<title>Welcome to nginx!</title>

关闭进程,留着火墙

bash 复制代码
[root@docker1 ~]# systemctl restart docker
[root@docker1 ~]# docker start demo 
[root@docker1 ~]# ps ax | grep proxy
 8896 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
 8971 pts/1    R+     0:00 grep --color=auto proxy
[root@docker1 ~]# kill 8896
[kiosk@foundation38 Desktop]$ curl 172.25.254.1
<title>Welcome to nginx!</title>

所以外部访问容器是双冗余机制


五、 跨主机容器网络

清理环境

bash 复制代码
[root@docker1 ~]# docker network prune 
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
my_net1
my_net2
[root@docker1 ~]# docker rm -f demo
[root@docker1 ~]# docker volume prune 
Are you sure you want to continue? [y/N] y
[root@docker1 ~]# docker image prune 
删掉只有名字,id是none,用不了的镜像,其实是镜像的缓存

实验环境

bash 复制代码
[root@docker1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3811ae4f8bf9        bridge              bridge              local
b51b022f8430        host                host                local
c386dbae12f0        none                null                local
[root@docker2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
568aa16db709        bridge              bridge              local
20d505b4b669        host                host                local
09ed8d8227c2        none                null                local

overlay是docker swarm 使用,这次先用macvlan

第三方是k8s使用

docker官方给你网络库和模型了,你根据自己需要的网络自己开发
Endpoint相当于虚拟网卡
macvlan是底层解决,硬件来解决
给docker1和docker2各添加一个桥接在eth0的网卡

激活新加入网卡的混杂模式

bash 复制代码
[root@docker1 ~]# ip addr
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
46: enp7s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
[root@docker1 ~]# ip link set enp7s0 promisc on
[root@docker1 ~]# ip addr
46: enp7s0: <BROADCAST,MULTICAST,PROMISC> mtu 1500 qdisc noop state DOWN group default qlen 1000
[root@docker1 ~]# ip link set up enp7s0
[root@docker1 ~]# ip addr
46: enp7s0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
[root@docker2 ~]# ip link set enp7s0 promisc on
[root@docker2 ~]# ip link set up enp7s0
[root@docker2 ~]# ip addr 
4: enp7s0: <NO-CARRIER,BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000

不能让两个ip冲突,两个网卡可以分配ip都为0.1,但是,因为是在一个vlan中,ip不要冲突。

bash 复制代码
[root@docker1 ~]# docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.1 -o parent=enp7s0 mynet1
[root@docker1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3811ae4f8bf9        bridge              bridge              local
b51b022f8430        host                host                local
9e1d71bae46c        mynet1              macvlan             local
c386dbae12f0        none                null                local
[root@docker1 ~]# docker run -it --rm --network mynet1 --ip 10.0.0.10 busyboxplus
/ # ip addr 
    inet 10.0.0.10/24 brd 10.0.0.255 scope global eth0
[root@docker2 ~]# docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.1 -o parent=enp7s0 mynet1
[root@docker2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
568aa16db709        bridge              bridge              local
20d505b4b669        host                host                local
dd46171171cb        mynet1              macvlan             local
09ed8d8227c2        none                null                local
[root@docker2 ~]# docker run -it --rm --network mynet1 --ip 10.0.0.11 busybox
/ # ip addr
    inet 10.0.0.11/24 brd 10.0.0.255 scope global eth0
/ # ping 10.0.0.10
64 bytes from 10.0.0.10: seq=0 ttl=64 time=0.814 ms
/ # ping 10.0.0.11
64 bytes from 10.0.0.11: seq=0 ttl=64 time=0.284 ms

通过底层的硬件去解决跨主机通信,由于容器是成千上万,可能需要很多网段需要大量的网卡,硬件可以插多少网卡呢?
没有新建linux bridge和虚拟网卡

bash 复制代码
[root@docker1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242c27a3cac	no		
[root@docker1 ~]# ip addr
46: enp7s0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
bash 复制代码
[root@docker1 ~]# ip link set enp7s0 down 
/ # ping 10.0.0.10
不通
[root@docker1 ~]# ip link set enp7s0 up
64 bytes from 10.0.0.10: seq=29 ttl=64 time=1002.343 ms

无需NAT和端口映射,所有这种macvlan只要把底层的物理链路通了,剩下的不用管了,docker不管

bash 复制代码
[root@docker2 ~]# docker run -d --name demo --network mynet1 --ip 10.0.0.11 webserver:v3 
/ # curl 10.0.0.11
<title>Welcome to nginx!</title>
[root@docker2 ~]# netstat -antlp
[root@docker2 ~]# iptables -nL -t nat
没有DNAT,没有端口映射

由于不能接无限个网卡,所以可以创建子接口(.1 .2.3.4...)依此类推

二层

bash 复制代码
[root@docker2 ~]# docker network create -d macvlan --subnet 20.0.0.0/24 --gateway 20.0.0.1 -o parent=enp7s0.1 mynet2
[root@docker1 ~]# docker network create -d macvlan --subnet 20.0.0.0/24 --gateway 20.0.0.1 -o parent=enp7s0.1 mynet2
[root@docker1 ~]# docker run -d --network mynet2 nginx
[root@docker1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
e91e508fdd2b        nginx               "/docker-entrypoint...."   28 seconds ago      Up 26 seconds                           practical_chandrasekhar
[root@docker1 ~]# docker inspect e91e508fdd2b
                    "IPAddress": "20.0.0.2",
[root@docker1 ~]# docker network create -d macvlan --subnet 30.0.0.0/24 --gateway 30.0.0.1 -o parent=enp7s0.2 mynet3

要使得二层通信,可以在三层做路由网关,将macvlan网络联通起来
inspect查看具体信息无论网络、卷、容器、镜像这些参数相通用的

bash 复制代码
[root@docker1 ~]# docker network inspect mynet2
[root@docker1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3811ae4f8bf9        bridge              bridge              local
b51b022f8430        host                host                local
9e1d71bae46c        mynet1              macvlan             local
7450c8721d84        mynet2              macvlan             local
2642e999f12a        mynet3              macvlan             local
c386dbae12f0        none                null                local

END

系列文章目录

docker卷


docker卷

bind mount

:以前宿主机路径,:以后容器路径

如果存在自动挂载,如果不存在默认会创建
对于镜像来说存储是一种需求,也可以通过这样的方式(挂载)修改容器的配置

/usr/share/nginx/html是Nginx默认的程序发布目录(数据挂载上)

bash 复制代码
[root@docker1 /]# mkdir /webdata
[root@docker1 /]# docker run -d --name demo -v /webdata:/usr/share/nginx/html nginx
[root@docker1 /]# cd /webdata/
[root@docker1 webdata]# vim index.html
[root@docker1 webdata]# cat index.html 
www.yan.org
[root@docker1 webdata]# curl 172.17.0.2
www.yan.org
bash 复制代码
[root@docker1 webdata]# docker inspect demo 
[root@docker1 webdata]# docker exec -it demo bash
root@a1f6892bc233:/# cd /usr/share/nginx/html/
root@a1f6892bc233:/usr/share/nginx/html# ls
index.html
root@a1f6892bc233:/usr/share/nginx/html# cat index.html 
www.yan.org

/etc/nginx是nginx的配置文件(配置文件挂载)

bash 复制代码
[root@docker1 webdata]# docker rm -f demo

需要配置文件

bash 复制代码
[root@docker1 webdata]# mkdir conf
[root@docker1 webdata]# mkdir html
[root@docker1 webdata]# mv index.html html/
[root@docker1 webdata]# cd conf/

进去容器看看配置文件

bash 复制代码
[root@docker1 conf]# docker run -it --rm nginx bash
root@d775f75c01df:/# cd /etc/nginx/
root@d775f75c01df:/etc/nginx# ls 
conf.d		mime.types  nginx.conf	 uwsgi_params
fastcgi_params	modules     scgi_params
root@d775f75c01df:/etc/nginx# cat nginx.conf 

发现里面只有全局的http

bash 复制代码
root@d775f75c01df:/etc/nginx# cd conf.d/
root@d775f75c01df:/etc/nginx/conf.d# ls
default.conf
root@d775f75c01df:/etc/nginx/conf.d# cat default.conf 

bash 复制代码
[root@docker1 conf]# vim www.conf
[root@docker1 conf]# cat www.conf 
server {
         listen 80;
         server_name www.yan.org;
         location / {
             root /html;虚拟主机的发布目录(容器)
             index index.html;
 }
}
[root@docker1 conf]# cd ..
[root@docker1 webdata]# cd html/
[root@docker1 html]# ls
index.html
bash 复制代码
[root@docker1 ~]# docker run -d --name demo -v /webdata/html:/html -v /webdata/conf/www.conf:/etc/nginx/conf.d/www.conf:ro -p 80:80 nginx
[root@docker1 ~]# vim /etc/hosts
172.25.254.1   docker1 reg.yan.org www.yan.org

访问域名www.yan.org,容器占用宿主机的80端口,所以请求会重定向到容器内。

bash 复制代码
[root@docker1 ~]# curl www.yan.org
www.yan.org

访问宿主机的80会重定向到容器里面

bash 复制代码
[root@docker1 ~]# ps ax
[root@docker1 ~]# iptables -t nat -nL
Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80
bash 复制代码
[root@docker1 ~]# cd /webdata/
[root@docker1 webdata]# ls
conf  html
[root@docker1 webdata]# cd html/
[root@docker1 html]# vim index.html 
[root@docker1 html]# cat index.html 
www.yan.org
123456789
[root@docker1 html]# curl www.yan.org
www.yan.org
123456789

docker managed volume

nginx默认没有定义卷的挂载

bash 复制代码
[root@docker1 volumes]# docker history nginx:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
605c77e624dd        6 weeks ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon...   0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop)  EXPOSE 80                    0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr...   0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop) COPY file:09a214a3e07c919a...   4.61kB              
<missing>           6 weeks ago         /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7...   1.04kB              
<missing>           6 weeks ago         /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0...   1.96kB              
<missing>           6 weeks ago         /bin/sh -c #(nop) COPY file:65504f71f5855ca0...   1.2kB               
<missing>           6 weeks ago         /bin/sh -c set -x     && addgroup --system -...   61.1MB              
<missing>           6 weeks ago         /bin/sh -c #(nop)  ENV PKG_RELEASE=1~bullseye   0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop)  ENV NJS_VERSION=0.7.1        0B                  
<missing>           6 weeks ago         /bin/sh -c #(nop)  ENV NGINX_VERSION=1.21.5     0B                  
<missing>           7 weeks ago         /bin/sh -c #(nop)  LABEL maintainer=NGINX Do...   0B                  
<missing>           7 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           7 weeks ago         /bin/sh -c #(nop) ADD file:09675d11695f65c55...   80.4MB              

registry定义了

bash 复制代码
[root@docker1 volumes]# docker history registry:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
               
<missing>           3 months ago        /bin/sh -c #(nop)  VOLUME [/var/lib/registry]   0B                  

_data就会被挂接到容器内

bash 复制代码
[root@docker1 docker]# cd /var/lib/docker/volumes/
[root@docker1 volumes]# ls
metadata.db
[root@docker1 volumes]# docker volume ls
DRIVER              VOLUME NAME
local               489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9
[root@docker1 volumes]# ls
489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9  metadata.db
root@docker1 volumes]# cd 489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9/
[root@docker1 489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9]# ls
_data
[root@docker1 489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9]# cd _data/
[root@docker1 _data]# ls

由于自动生成的卷名字很长,而且看不出对应关系

删掉容器卷还保留着

bash 复制代码
[root@docker1 _data]# docker rm -f registry 
registry
[root@docker1 _data]# docker volume ls
DRIVER              VOLUME NAME
local               489ec21e4aa78de9ca13565361142459a460b1beb7f64124714299d4d4b964e9
[root@docker1 _data]# docker volume prune 
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
bash 复制代码
[root@docker1 volumes]# cd /var/lib/docker/volumes/
[root@docker1 volumes]# ls
metadata.db
[root@docker1 volumes]# docker volume create registry
[root@docker1 _data]# docker volume ls
DRIVER              VOLUME NAME
local               registry
[root@docker1 volumes]# ls
metadata.db  registry
[root@docker1 volumes]# docker run -d --name registry -v registry:/var/lib/registry registry
[root@docker1 volumes]# docker inspect registry

特点:

-v不是docker manager 的话(bind mount )是用宿主机内的数据覆盖掉容器内的,docker manager卷的话会把容器的挂载点里原有的文件考入物理节点上,持久化

bash 复制代码
[root@docker1 volumes]# docker volume create vol1
[root@docker1 volumes]# ls
metadata.db  vol1
[root@docker1 volumes]# cd vol1/
[root@docker1 vol1]# ls
_data
[root@docker1 vol1]# cd _data/
[root@docker1 _data]# ls
bash 复制代码
[root@docker1 _data]# docker run -d --name nginx -v vol1:/usr/share/nginx/html nginx
[root@docker1 _data]# ls
50x.html  index.html

mind mount是覆盖的(没有该目录自动创建),不会考入原有容器挂载点内的数据

bash 复制代码
[root@docker1 mnt]# cd /yan
-bash: cd: /yan: No such file or directory
[root@docker1 mnt]# docker run -d --name nginx2 -v /yan:/usr/share/nginx/html nginx
[root@docker1 ~]# docker run -d --name nginx4  nginx:latest 
[root@docker1 ~]# docker exec -it nginx4 bash
root@f1177ba608b8:/# cd /usr/share/nginx/html/
root@f1177ba608b8:/usr/share/nginx/html# ls
50x.html  index.html
[root@docker1 mnt]# cd /yan
[root@docker1 yan]# ls
[root@docker1 yan]# docker exec -it nginx2 bash
root@be477783aa8a:/# cd /usr/share/nginx/html/
root@be477783aa8a:/usr/share/nginx/html# ls
root@be477783aa8a:/usr/share/nginx/html# 

bind mount 与 docker manager

host是主机

只能是目录,所以更改文件必须加-v重新写个

卷插件

可以实现跨主机共享
客户端把请求给docker引擎,引擎再连接插件(存储),插件再连接底层的nfs.
插件就相当于一个接口,引擎不能直接连接Nfs。

Daemon docker引擎

/etc/docker/plugins/这个路径就是docker引擎缺省的扫描路径

convoy卷插件

直接使用nfs(网络文件共享系统),-v挂接也也可以,但是你需要写路径,不同主机路径不一样,不好操作,所以直接用插件便用使用

跨主机共享

将/mnt/nfs输出出去

底层文件nfs共享系统搭建

bash 复制代码
[root@docker1 ~]# mkdir /mnt/nfs
[root@docker1 ~]# vim /etc/exports 
[root@docker1 ~]# cat /etc/exports 
/mnt/nfs *(rw,sync)
[root@docker1 ~]# chmod 777 /mnt/nfs/
[root@docker1 ~]# ll -d /mnt/nfs/
drwxrwxrwx 2 root root 6 Feb 14 21:45 /mnt/nfs/
[root@docker1 ~]# yum install nfs-utils
[root@docker1 ~]# systemctl start nfs
[root@docker1 ~]# showmount -e
Export list for docker1:
/mnt/nfs *
bash 复制代码
[root@docker2 ~]# mkdir /mnt/nfs
[root@docker2 ~]# yum install nfs-utils -y 
[root@docker2 ~]# mount 172.25.254.1:/mnt/nfs/ /mnt/nfs/
[root@docker2 ~]# cd /mnt/nfs/
[root@docker2 nfs]# ls
[root@docker2 nfs]# touch file
[root@docker2 nfs]# ls
file
[root@docker1 ~]# cd /mnt/nfs/
[root@docker1 nfs]# ls
file
[root@docker1 nfs]# rm -f file 
[root@docker1 nfs]# ls
[root@docker2 nfs]# ls

安装插件

解压后里面就两个二进制程序,将它移动到/usr/local/bin/底下调用就行了

/etc/docker/plugins/这个路径就是docker引擎缺省的扫描路径(docker引擎会自动扫描这个路径上面的插件)

bash 复制代码
[root@docker1 ~]# ls
auth  certs  convoy.tar.gz  docker
[root@docker1 ~]# tar zxf convoy.tar.gz 
[root@docker1 convoy]# ls
convoy  convoy-pdata_tools  SHA1SUMS
[root@docker1 convoy]# mkdir -p /etc/docker/plugins/

启动插件服务

bash 复制代码
[root@docker1 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@docker1 convoy]# ps ax
11173 pts/0    Sl     0:00 convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs
这个进程在后端

插件sock文件路径,只有程序启动后,sock才出现

bash 复制代码
[root@docker1 convoy]# cd /var/run/
[root@docker1 run]# cd convoy/
[root@docker1 convoy]# ls
convoy.sock

把sock路径写入docker缺省路径里面

bash 复制代码
[root@docker1 convoy]# echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec
[root@docker1 convoy]# cat /etc/docker/plugins/convoy.spec
unix:///var/run/convoy/convoy.sock

给服务器2添加该插件

bash 复制代码
[root@docker2 ~]# ls
convoy.tar.gz
[root@docker2 ~]# tar zxf convoy.tar.gz 
[root@docker2 convoy]# mv convoy* /usr/local/bin/
[root@docker2 convoy]# mkdir -p /etc/docker/plugins/
[root@docker2 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@docker2 convoy]# cd /var/run/convoy/
[root@docker2 convoy]# ls
convoy.sock
[root@docker2 convoy]# echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec

插件使用

bash 复制代码
[root@docker1 ~]# convoy --help
[root@docker1 ~]# convoy create vol1
[root@docker1 ~]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:15:16 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:15:16 +0800 2022",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}

提示权限错误了

bash 复制代码
[root@docker2 convoy]# convoy list
{}

no_root_squash 超级用户挂载的时候不要去变更权限,要不然就变成nfs nobody

bash 复制代码
[root@docker1 ~]# vim /etc/exports
[root@docker1 ~]# cat /etc/exports
/mnt/nfs *(rw,no_root_squash)
[root@docker1 ~]# showmount -e
Export list for docker1:
/mnt/nfs *
[root@docker1 ~]# exportfs -rv 刷新
exporting *:/mnt/nfs
bash 复制代码
[root@docker2 config]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:15:16 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:15:16 +0800 2022",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}

docker卷可以自动识别到

bash 复制代码
[root@docker2 config]# docker volume ls
DEBU[0707] Handle plugin activate: POST /Plugin.Activate  pkg=daemon
DEBU[0707] Response:  {
	"Implements": [
		"VolumeDriver"
	]
}  pkg=daemon
DEBU[0707] Handle plugin list volume: POST /VolumeDriver.List  pkg=daemon
DEBU[0707]                                               event=mountpoint object=volume pkg=daemon reason=prepare volume=vol1
DEBU[0707]                                               event=mountpoint mountpoint= object=volume pkg=daemon reason=complete volume=vol1
DEBU[0707] Successfully got volume list for docker.      pkg=daemon
DEBU[0707] Response:  {
	"Volumes": [
		{
			"Name": "vol1"
		}
	]
}  pkg=daemon
ERRO[0707] Handler not found: POST /VolumeDriver.Capabilities  pkg=daemon
DRIVER              VOLUME NAME
convoy              vol1
bash 复制代码
[root@docker2 config]# convoy create vol2
[root@docker1 ~]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:15:16 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:15:16 +0800 2022",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	},
	"vol2": {
		"Name": "vol2",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:25:28 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol2",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:25:28 +0800 2022",
			"VolumeName": "vol2"
		},
		"Snapshots": {}
	}
}

用convoy和docker volume都能操作

bash 复制代码
[root@docker1 ~]# docker volume rm -f vol2
[root@docker1 ~]# docker volume ls
DEBU[1386] Handle plugin list volume: POST /VolumeDriver.List  pkg=daemon
DEBU[1386]                                               event=mountpoint object=volume pkg=daemon reason=prepare volume=vol1
DEBU[1386]                                               event=mountpoint mountpoint= object=volume pkg=daemon reason=complete volume=vol1
DEBU[1386] Successfully got volume list for docker.      pkg=daemon
DEBU[1386] Response:  {
	"Volumes": [
		{
			"Name": "vol1"
		}
	]
}  pkg=daemon
ERRO[1386] Handler not found: POST /VolumeDriver.Capabilities  pkg=daemon
DRIVER              VOLUME NAME
convoy              vol1
[root@docker1 ~]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:15:16 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:15:16 +0800 2022",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}

插件搭建成功

容器跨主机迁移以及数据跨主机迁移

docker 管理卷可以考出容器内数据

bash 复制代码
[root@docker1 ~]# docker run -d --name demo -v vol1:/usr/share/nginx/html nginx
[root@docker1 ~]# cd /mnt/nfs/vol1/
[root@docker1 vol1]# ls
50x.html  index.html
[root@docker1 vol1]# vim test.html
[root@docker1 vol1]# cat test.html 
www.yan.com
yan wei qiu

由于没有做端口映射

bash 复制代码
[root@docker1 vol1]# curl 172.17.0.2
<title>Welcome to nginx!</title>
[root@docker1 vol1]# curl 172.17.0.2/test.html
www.yan.com
yan wei qiu

正常情况下容器是自动迁移的,集群

bash 复制代码
[root@docker1 vol1]# docker rm -f demo

现在是手动迁移,容器跨主机迁移,数据也跨主机迁移

bash 复制代码
[root@docker2 config]# docker run -d --name demo -v vol1:/usr/share/nginx/html nginx
[root@docker2 config]# curl 172.17.0.2/test.html
www.yan.com
yan wei qiu

卸载该插件

bash 复制代码
[root@docker2 config]# fg
convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs	(wd: ~/convoy)
^CCaught signal interrupt: shutting down.
[root@docker2 config]# cd /etc/docker/plugins/
[root@docker2 plugins]# ls
convoy.spec
[root@docker2 plugins]# rm -fr convoy.spec 
[root@docker2 plugins]# systemctl stop docker
[root@docker2 plugins]# systemctl daemon-reload 
[root@docker2 plugins]# systemctl start docker

不卸载的话,docker重启会慢

bash 复制代码
[root@docker1 vol1]# convoy list
{}
[root@docker1 vol1]# convoy create vol1
[root@docker1 vol1]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Mon Feb 14 22:47:43 +0800 2022",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Mon Feb 14 22:47:43 +0800 2022",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}
[root@docker1 plugins]# systemctl stop docker
[root@docker1 plugins]# systemctl daemon-reload 
[root@docker1 plugins]# systemctl start docker

启动会变慢

卷也看不到,因为docker引擎没有识别

bash 复制代码
[root@docker1 plugins]# docker volume ls
DRIVER              VOLUME NAME

慢是因为有缓存信息

解决

docker所有数据在这里

重启恢复了(之前所有卷的数据也丢失了),所以卷的缓存信息都在元数据里面

bash 复制代码
[root@docker1 plugins]# cd /var/lib/docker
[root@docker1 docker]# cd volumes/
[root@docker1 volumes]# ls
metadata.db
[root@docker1 volumes]# mv metadata.db /mnt/
[root@docker1 volumes]# ls
[root@docker1 volumes]# systemctl restart docker

可以看出元数据缓存之前的卷,还可以重新将该服务写入docker缺省路径,按照正常的方式关闭

bash 复制代码
[root@docker1 volumes]# cd /mnt/
[root@docker1 mnt]# ls
metadata.db  nfs
[root@docker1 mnt]# cat metadata.db 
��
   �
        �������>[��
                     �
                          �z3Ff�l
nvolumes:vol1{"Name":"","Driver":"convoy","Labels":null,"Options":null}


volumes	

END

相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
追风林4 小时前
mac 本地docker-mysql主从复制部署
mysql·macos·docker
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~5 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust