当前位置: 首页 > news >正文

Docker 进阶构建:镜像、网络与仓库管理

目录

三. docker镜像构建

1. docker镜像结构

2. 镜像运行的基本原理

3. 镜像获得方式

4. 镜像构建

5. Dockerfile实例

6. 镜像优化方案

6.1. 镜像优化策略

6.2. 镜像优化示例:缩减镜像层

6.3. 镜像优化示例:多阶段构建

6.4. 镜像优化示例:使用最精简镜像

四. docker 镜像仓库的管理

1. 什么是docker仓库

2. docker hub

3. docker hub的使用方法

3. docker仓库的工作原理

4. pull原理

5. push原理

6. 搭建docker的私有仓库

6.1. 为什么搭建私有仓库

6.2. 搭建简单的Registry仓库

6.3. 为Registry提加密传输

6.4. 为仓库建立登陆认证

7. 构建企业级私有仓库

7.1. 部署harbor

7.2. 管理仓库

五. Docker 网络

1. docker原生bridge网路

2. docker原生网络host

3. docker 原生网络none

4. docker的自定义网络

4.1. 自定义桥接网络

4.2. 为什么要自定义桥接

4.3. 如何让不同的自定义网络互通?

4.4. joined容器网络

4.5. joined网络示例演示

5. 容器内外网的访问

5.1 容器访问外网

5.2 外网访问docker容器

6. docker跨主机网络

6.1 CNM (Container Network Model)

6.2 macvlan网络方式实现跨主机通信


三. docker镜像构建

1. docker镜像结构
  • 共享宿主机的kernel

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

  • 同一docker主机支持运行多种Linux发行版

  • 采用分层结构的最大好处是:共享资源

2. 镜像运行的基本原理
  • Copy-on-Write 可写容器层

  • 容器层以下所有镜像层都是只读的

  • docker从上往下依次查找文件

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

3. 镜像获得方式
  • 基本镜像通常由软件官方提供

  • 企业镜像可以用官方镜像+Dockerfile来生成

  • 系统关于镜像的获取动作有两种:

  • docker pull 镜像地址

  • docker load –i 本地镜像包

4. 镜像构建
#FROM COPY 和MAINTAINER
[root@Docker-node1 ~]# mkdir docker/
[root@Docker-node1 ~]# cd docker/
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile   #基础镜像
[root@Docker-node1 docker]# docker build -t busybox:v1 . #构建镜像
[root@Docker-node1 docker]# docker images history busybox:v1
[root@Docker-node1 docker]#docker run -it --rm --name test1 busybox:v1[root@Docker-node1 docker]# mv Dockerfile timinglee
[root@Docker-node1 docker]# docker build -f /root/docker/timinglee -t example:v2 .    #-f指定名字
[root@Docker-node1 docker]# docker images[root@Docker-node1 docker]# mv timinglee Dockerfile
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org    #rhel版本不一样,指令不同 #指定邮箱信息
[root@Docker-node1 docker]# docker build -t busybox:v2 .
[root@Docker-node1 docker]#docker images history busybox:v2cp /etc/passwd
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd  #复制当前目录文件到容器指定位置,passwd必须在当前目录中
[root@Docker-node1 docker]#docker build -t busybox:v3 .
[root@Docker-node1 docker]#docker images history busybox:v3
[root@Docker-node1 docker]#docker run -it --rm --name test busybox:v3 #启动进入文件,看对应目录有没有文件
#如果已存在可以,删掉docker rm -f test[root@Docker-node1 docker]# tar zcf zhuzhuxia.tar.gz Dockerfile passwd
[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
[root@Docker-node1 docker]# docker build -t busybox:v4 .
[root@Docker-node1 docker]# docker run -it --rm --name tes busybox:v4[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
RUN mkdir /lee
[root@Docker-node1 docker]# docker build -t busybox:v5 .
[root@Docker-node1 docker]# docker images history busybox:v5
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v5[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
RUN mkdir /lee
CMD ["/bin/sh", "-c", "echo hello lee"]   #CMD的不同写法
#CMD echo joker
[root@Docker-node1 docker]# docker build -t busybox:v6 .
[root@Docker-node1 docker]# docker images history busybox:v6
[root@Docker-node1 docker]# docker run -it --name test busybox:v6[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
RUN mkdir /lee
ENV name=timinglee
ENTRYPOINT ["/bin/sh", "-c", "echo xiaofeifei"]   #不可替代
CMD ["/bin/sh", "-c", "echo $NAME"]   #CMD被替代
[root@Docker-node1 docker]# docker build -t busybox:v6 .
[root@Docker-node1 docker]# docker images history busybox:v6
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v6  #有内容;CMD
[root@Docker-node1 docker]# docker rm test
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v6 sh  #无内容;CMD
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v6 sh  #有内容;测试ENTRYPOINT[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
RUN mkdir /lee
EXPOSE 80 443   #暴露端口
ENV name=timinglee
ENTRYPOINT ["/bin/sh", "-c", "sleep 10000000"]   #不可替代
CMD ["/bin/sh", "-c", "echo $NAME"]   #CMD被替代
[root@Docker-node1 docker]# docker build -t busybox:v6 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v6  
[root@Docker-node1 docker]# docker run -d --rm --name test busybox:v6 
[root@Docker-node1 docker]# docker ps #看端口
[root@Docker-node1 docker]# docker stop test[root@Docker-node1 docker]# vim Dockerfile
FROM busybox
RUN touch /leefile 
LABEL Mail=lee@timinglee.org
COPY passwd /passwd
ADD zhuzhuxia.tar.gz /mnt
RUN mkdir /lee
EXPOSE 80 443
WORKDIR /mnt   #工作目录
VOLUME /lee   #目录挂载
[root@Docker-node1 docker]# docker build -t busybox:v6 .
[root@Docker-node1 docker]# docker run -it --rm --name test busybox:v6  
[root@Docker-node1 docker]# docker inspect test  #看"Mounts"的下面有没有目录/lee
5. Dockerfile实例
#清理容器
[root@node9 ~]# docker images
[root@node9 ~]# docker rmi <IMAGE ID> 
[root@node9 ~]# docker rmi `docker images | awk '/none/{print $1}'`
[root@node9 ~]# docker rmi busybox:v{1..7}#可以先拖入企业7镜像centos和nginx1.26软件包,提前下载。
[root@node9 ~]# docker load -i /mnt/centos-7#建立构建目录,编写构建文件
[root@node9 ~]# mdkir docker
[root@node9 ~]# cd docker/
[root@node9 docker]# mv /nginx-1.26.1.tar.gz . #移动文件到当前。
[root@node9 docker]# vim Dockerfile
FROM centos:7
LABEL Mail=lee@timinglee.org
ADD /nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]#通过dockerfile生成镜像
[root@node9 docker]# docker build -t nginx:v1 #出现仓库报错,添加一个rhel7.9镜像虚拟机。
#添加一个端口
[root@node9 docker]# yum install httpd -y
[root@node9 docker]# vim /etc/httpd/conf/httpd.conf
...
listen 8888
...
[root@node9 docker]# systemctl start httpd#挂载端口
[root@node9 docker]# mkdir /var/www/html/rhel7.9
[root@node9 docker]# mount /dev/sr1 /var/www/html/rhel7.9#查看ip
[root@node9 docker]# docker inspect centos:7
[root@node9 docker]# ping 172.17.0.2#进入容器
[root@node9 docker]# docker run -it --name centos centos:7
cd /etc/yum.repos.d/
rm -fr *
vim centos7.repo
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0#将一个名为 “centos” 的容器创建一个新的镜像,并为新镜像添加注释信息 “add repo”,新镜像命名为 “centos:repo”
[root@node9 docker]# docker commit -m "add repo" centos centos:repo
[root@node9 docker]# docker rm centos#修改配置文件
[root@node9 docker]# vim Dockerfile
FROM centos:repo
LABEL Mail=lee@timinglee.org
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]#再一次生成镜像
[root@node9 docker]# docker build -t nginx:v1 #查看容器
[root@server1 docker]# docker images
6. 镜像优化方案
6.1. 镜像优化策略
  • 选择最精简的基础镜像

  • 减少镜像的层数

  • 清理镜像构建的中间产物

  • 选择最精简的基础镜像

  • 减少镜像的层数

  • 清理镜像构建的中间产物

6.2. 镜像优化示例:缩减镜像层
[root@node9 docker]# vim Dockerfile
FROM centos:repo
LABEL Mail=lee@timinglee.org
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module -- with-http_stub_status_module && make && make install && rm -fr nginx-
1.26.1 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]   #CMD 是 Dockerfile 中的一个指令,用于定义容器启动时默认执行的命令。
["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]:这是一个命令列表。其中,/usr/local/nginx/sbin/nginx 是启动 Nginx 服务器的命令路径。-g 是 Nginx 的全局配置指令参数,daemon off 表示以非守护进程模式运行 Nginx,即让 Nginx 在前台运行,这样容器就不会在启动 Nginx 后立即退出,而是保持运行状态直到容器被停止或者出现错误。[root@node9 docker]# docker build -t nginx:v2 .
[root@node9 docker]# docker images nginx
[root@node9 docker]# vim Dockerfile
FROM centos:repo
LABEL Mail=lee@timinglee.org
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module -- with-http_stub_status_module && make && make install && rm -fr nginx-
1.26.1 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]   #CMD 是 Dockerfile 中的一个指令,用于定义容器启动时默认执行的命令。
["/usr/local/nginx/sbin/nginx", "-g", "daemon off"]:这是一个命令列表。其中,/usr/local/nginx/sbin/nginx 是启动 Nginx 服务器的命令路径。-g 是 Nginx 的全局配置指令参数,daemon off 表示以非守护进程模式运行 Nginx,即让 Nginx 在前台运行,这样容器就不会在启动 Nginx 后立即退出,而是保持运行状态直到容器被停止或者出现错误。[root@node9 docker]# docker build -t nginx:v2 .
[root@node9 docker]# docker images nginx
6.3. 镜像优化示例:多阶段构建
[root@node9 docker]# vim Dockerfile
FROM centos:repo AS build
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install -y gcc make pcre-devel openssl-devel && ./configure --prefix=/usr/local/nginx --with-http_ssl_module -- with-http_stub_status_module && make && make install && rm -fr nginx-
1.26.1 && yum clean allFROM centos:repo
LABEL Mail=lee@timinglee.org
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@node9 docker]# docker build -t nginx:v3 .
[root@node9 docker]# docker images nginx
6.4. 镜像优化示例:使用最精简镜像

使用google提供的最精简镜像

#下载地址:
https://github.com/GoogleContainerTools/distroless#下载镜像:
docker pull gcr.io/distroless/base
#提前下载,直接拖入即可。#利用最精简镜像构建
[root@node9 docker]# vim Dockerfile
FROM nginx:1.23 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 /usr/lib/x86_64-linux-gnu/libpcre* /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-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
[root@node9 ~]# docker build -t nginx:v4 .
[root@node9 ~]# docker images nginx
测试:
[root@node9 ~]# docker run --rm -d --name wevserver nginx:v4
[root@node9 ~]# docker ps

四. docker 镜像仓库的管理

1. 什么是docker仓库

Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。 它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉 取所需的镜像。 Docker 仓库可以分为公共仓库和私有仓库: 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。 例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。 比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中, 以保证安全性和控制访问权限。 通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。

2. docker hub

官网:https://hub.docker.com/ Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。 它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。 以下是 Docker Hub 的一些关键特点和优势:

  1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、Web 服务器等众多应用 的镜像。 例如,您可以轻松找到 Ubuntu、CentOS 等操作系统的镜像,以及 MySQL、Redis 等数据库 的镜像。

  2. 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。

  3. 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。

  4. 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。

  5. 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。

3. docker hub的使用方法
#登陆官方仓库
[root@docker ~]# docker login
Log in with your Docker ID or email address to push and pull images from Docker
Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to
create one.
You can log in with your password or a Personal Access Token (PAT). Using a
limited-scope PAT grants better security and is required for organizations using
SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: timinglee
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/#credential-stores
Login Succeeded#登陆信息保存位置
[root@docker ~]# cd .docker/
[root@docker .docker]# ls
config.json
[root@docker .docker]# cat config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dGltaW5nbGVlOjY3NTE1MTVtaW5nemxu"}}
}[root@docker ~]# docker tag nginx:v3 timinglee/nginx:v3   #修改名字,类似索引[root@docker ~]# docker push timinglee/nginx:v3
3. docker仓库的工作原理

仓库中的三个角色

  • index docker索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。

  • registry docker仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过Index Auth service的Token的方式进行认证

  • Registry Client Docker充当registry客户端来维护推送和拉取,以及客户端的授权。

4. pull原理

镜像拉取分为以下几步: 1.docker客户端向index发送镜像拉去请求并完成与index的认证 2.index发送认证token和镜像位置给dockerclient 3.dockerclient携带token和根据index指引的镜像位置取连接registry 4.Registry会根据client持有的token跟index核实身份合法性 5.index确认此token合法性 6.Registry会根据client的请求传递镜像到客户端

5. push原理

镜像上传的步骤: 1.client向index发送上传请求并完成用户认证 2.index会发方token给client来证明client的合法性 3.client携带index提供的token连接Registry 4.Registry向index合适token的合法性 5.index证实token的合法性 6.Registry开始接收客户端上传过来的镜像

6. 搭建docker的私有仓库
6.1. 为什么搭建私有仓库

docker hub虽然方便,但是还是有限制

  • 需要internet连接,速度慢

  • 所有人都可以访问

  • 由于安全原因企业不允许将镜像放到外网

好消息是docker公司已经将registry开源,我们可以快速构建企业私有仓库 地址: https://docs.docker.com/registry/deploying/

6.2. 搭建简单的Registry仓库
#下载Registry镜像
[root@node9 ~]#  docker pull registry
#我是提前下载了,所以直接拖入。
[root@node9 ~]# docker load -i registry.tag.gz 
ce7f800efff9: Loading layer  7.644MB/7.644MB
30609d4f10dd: Loading layer  792.6kB/792.6kB
3b6a51496c9d: Loading layer  17.55MB/17.55MB
e704e9e3e9dc: Loading layer  3.584kB/3.584kB
f019f591461d: Loading layer  2.048kB/2.048kB
Loaded image: registry:latest#开启Registry
[root@node9 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry
338896d1cc20d7e06ef39a0a3351b71b2a91b81dcfb12cae1818efd646fd05b4
[root@node9 ~]# docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED              STATUS              PORTS                                       NAMES
338896d1cc20   registry                 "/entrypoint.sh /etc…"   About a minute ago   Up About a minute   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   registry
d571fb7d7d7c   timinglee/mario:latest   "python3 -m http.ser…"   14 hours ago         Up 14 hours         0.0.0.0:80->8080/tcp, :::80->8080/tcp       game2#上传镜像到仓库中
#给要上传的镜像大标签
[root@node9 ~]# docker tag nginx:latest 172.25.254.100:5000/nginx:latest#docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@node9 ~]# docker push 172.25.254.100:5000/nginx:latest
The push refers to repository [172.25.254.100:5000/nginx]
Get "https://172.25.254.100:5000/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)#配置非加密端口
[root@node9 ~]# cat /etc/docker/daemon.json 
{"insecure-registries":["http://172.25.254.100:5000"]
}
[root@node9 ~]# systemctl restart docker#上传镜像
[root@node9 ~]# docker push 172.25.254.100:5000/nginx:latest
The push refers to repository [172.25.254.100:5000/nginx]
5f0272c6e96d: Pushed 
f4f00eaedec7: Pushed 
55e54df86207: Pushed 
ec1a2ca4ac87: Pushed 
8b87c0c66524: Pushed 
72db5db515fd: Pushed 
9853575bc4f9: Pushed 
latest: digest: sha256:127262f8c4c716652d0e7863bba3b8c45bc9214a57d13786c854272102f7c945 size: 1778#查看镜像上传
[root@node9 ~]# curl 172.25.254.100:5000/v2/_catalog
{"repositories":["nginx"]}
6.3. 为Registry提加密传输
#走加密端口
[root@node9 ~]# cat /etc/docker/daemon.json  #内容清掉。
[root@node9 ~]# systemctl restart docker#本地解析
vim /etc/hosts
172.25.254.100  node9.timinglee.org#生成认证key和证书
[root@node9 ~]# mkdir -p certs
[root@node9 ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout certs/timinglee.org.key \
-addext "subjectAltName = DNS:reg.timinglee.org" \ #指定备用名称
-x509 -days 365 -out certs/timinglee.org.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:timinglee
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org#启动registry仓库
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
> --name registry -v /opt/registry:/var/lib/registry \
> -v /root/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry
[root@node9 ~]# docker rm -f registry
registry
[root@node9 ~]# docker ps测试:
docker tag busybox:latest reg.timinglee.org/busybox:latest
[root@docker docker]# docker push reg.timinglee.org/busybox:latest #docker客户端没有key和证书
Error response from daemon: Get "https://reg.timinglee.org/v2/": tls: failed toverify certificate: x509: certificate signed by unknown authority#为客户端建立证书
[root@docker docker]# mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
[root@docker docker]# cp /root/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@docker docker]# systemctl restart docker
[root@node9 ~]# docker push reg.timinglee.org/busybox:latest
The push refers to repository [reg.timinglee.org/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
[root@docker docker]# curl -k https://reg.timinglee.org/v2/_catalog
{"repositories":["busybox"]}
6.4. 为仓库建立登陆认证
#安装建立认证文件的工具包
[root@docker docker]# dnf install httpd-tools -y#建立认证文件
[root@docker ~]# mkdir auth
[root@docker ~]# htpasswd -Bc auth/htpasswd lee #-B 强制使用最安全加密方式,默认用md5加密
New password:
Re-type new password:
Adding password for user timinglee#添加认证到registry容器中
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
> --name registry -v /opt/registry:/var/lib/registry \
> -v /root/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key \
> -v /root/auth:/auth \
> -e "REGISTRY_AUTH=htpasswd" \
> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
> registry#允许 curl 连接到使用自签名证书的服务器(-k 表示忽略 SSL 证书验证)。-u lee:123 用于提供用户名 lee 和密码 123 进行基本身份验证。从指定的 URL 获取数据,并以 JSON 格式返回了一个包含 repositories 数组的响应,数组中包含了 busybox 和 nginx
[root@docker ~]# curl -k https://node9.timinglee.org/v2/_catalog -u lee:123
{"repositories":["busybox","nginx"]}#当仓库开启认证后必须登陆仓库才能进行镜像上传
#未登陆情况下上传镜像
[root@node9 ~]# docker push reg.timinglee.org/nginx
Using default tag: latest
The push refers to repository [reg.timinglee.org/nginx]
5f0272c6e96d: Preparing 
f4f00eaedec7: Preparing 
55e54df86207: Preparing 
ec1a2ca4ac87: Preparing 
8b87c0c66524: Preparing 
72db5db515fd: Preparing 
9853575bc4f9: Preparing 
no basic auth credentials#未登陆请款下也不能下载
[root@node9 ~]# docker tag nginx:latest reg.timinglee.org/nginx
[root@node9 ~]# docker push reg.timinglee.org/nginx
[root@node9 ~]# docker pull reg.timinglee.org/nginx
Using default tag: latest
Error response from daemon: Head "https://reg.timinglee.org/v2/nginx/manifests/latest": no basic auth credentials#登陆测试
[root@docker ~]# docker login reg.timinglee.org
Username: lee
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/#credential-stores
Login Succeeded#退出登录
docker logout reg.timinglee.org
7. 构建企业级私有仓库

下载软件包地址 Releases · goharbor/harbor · GitHub Harbor 是由vmware公司开源的企业级 Docker Registry 项目。 它提供了以下主要功能和特点:

  1. 基于角色的访问控制(RBAC):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理 的灵活性。

  2. 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。

  3. 图形化用户界面(UI):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。

  4. 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。

  5. 垃圾回收:可以清理不再使用的镜像,节省存储空间。

7.1. 部署harbor
#提前下载,直接解压。
[root@docker ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@docker ~]# ls
anaconda-ks.cfg certs harbor-offline-installer-v2.5.4.tgz
auth harbor
cp -r /root/certs/ /data/
[root@docker ~]# cd harbor/
[root@docker harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml
hostname: reg.timinglee.org
certificate: /data/certs/timinglee.org.crt
private_key: /data/certs/timinglee.org.key
harbor_admin_password: 123
[root@docker harbor]# ./install.sh --help
Please set --with-notary #证书签名
Please set --with-trivy #安全扫描
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor
[root@docker harbor]# ./install.sh --with-chartmuseum#管理harbor的容器
[root@docker harbor]# docker compose stop   #停止
[root@docker harbor]# docker compose up -d   #重新加载
7.2. 管理仓库
#Windows本地解析
172.25.254.100  reg.timinglee.org#在浏览器上访问172.25.254.100
1.登陆;账号:admin 密码:123
2.建立仓库项目 项目名字:xiaozhuhzu,#在后面拉取镜像时需要加上这个标签#上传镜像
[root@docker harbor]# docker login reg.timinglee.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/#credential-stores
Login Succeeded
[root@node9 ~]# docker tag busybox:latest reg.timinglee.org/xiaozhuzhu/busybox:v1
[root@node9 ~]# docker push reg.timinglee.org/xiaozhuzhu/busybox:v1
The push refers to repository [reg.timinglee.org/xiaozhuzhu/busybox]
d51af96cf93e: Pushed 
v1: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
测试:
在浏览器上查看上传的镜像

五. Docker 网络

docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分 docker安装后会自动创建3种网络:bridge、host、none

#切换模式iptables
grubby --update-kernel ALL --args iptables=true#查看network
[root@node9 ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
0f5f6bc4bbf6   bridge                      bridge    local
ea9a34a2492b   harbor_harbor               bridge    local
1b13291bf8c7   harbor_harbor-chartmuseum   bridge    local
1b469e272a9a   host                        host      local
ce6ef696809d   none                        null      local#清理一些不用的网络
cd harbor/
docker compose down
1. docker原生bridge网路

docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口

[root@node9 ~]# ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default link/ether 02:42:e0:53:92:60 brd ff:ff:ff:ff:ff:ff
12: br-1b13291bf8c7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:7a:e8:5f:36 brd ff:ff:ff:ff:ff:ff
13: br-ea9a34a2492b: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:d1:58:69:b4 brd ff:ff:ff:ff:ff:ff

bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。 容器通过宿主机的NAT规则后可以访问外网

[root@docker mnt]# docker run -d --name web -p 80:80 nginx:1.23
defeba839af1b95bac2a200fd1e06a45e55416be19c7e9ce7e0c8daafa7dd470
[root@docker mnt]# ifconfig
....
veth7f320e9: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet6 fe80::986b:99ff:fe19:f8d9  prefixlen 64  scopeid 0x20<link>ether 9a:6b:99:19:f8:d9  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 21  bytes 2556 (2.4 KiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0veth7f320e9 为容器使用的网卡
#软件包bridge-utils-1.5-9.el7.x86_64
[root@docker mnt]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02425fe2346c no veth022a7c9
2. docker原生网络host

host网络模式需要在容器创建时指定 --network=host host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。

[root@docker ~]# docker run -it --name test --network host busybox
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:E0:53:92:60  inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0inet6 addr: fe80::42:e0ff:fe53:9260/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:8335 errors:0 dropped:0 overruns:0 frame:0TX packets:10143 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:4402060 (4.1 MiB)  TX bytes:71967675 (68.6 MiB)eth0      Link encap:Ethernet  HWaddr 00:0C:29:70:64:35  inet addr:172.25.254.100  Bcast:172.25.254.255  Mask:255.255.255.0inet6 addr: fe80::f21f:eb6:d618:77cb/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:538105 errors:0 dropped:0 overruns:0 frame:0TX packets:42952 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:773168166 (737.3 MiB)  TX bytes:13541075 (12.9 MiB)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:11834 errors:0 dropped:0 overruns:0 frame:0TX packets:11834 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:1045343 (1020.8 KiB)  TX bytes:1045343 (1020.8 KiB)veth7f320e9 Link encap:Ethernet  HWaddr 9A:6B:99:19:F8:D9  inet6 addr: fe80::986b:99ff:fe19:f8d9/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:23 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:0 (0.0 B)  TX bytes:2696 (2.6 KiB)如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败
3. docker 原生网络none

none模式是指禁用网络功能,只有lo接口,在容器创建时使用 --network=none指定。

[root@docker ~]# docker run -it --name test --rm --network none busybox 
/ # ifconfig
lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
4. docker的自定义网络

自定义网络模式,docker提供了三种自定义网络驱动:

bridge overlay macvlan bridge驱动类似默认的bridge网络模式,但增加了一些新的功能, overlay和macvlan是用于创建跨主机网络 建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。

4.1. 自定义桥接网络
#在建立自定以网络时,默认使用桥接模式
[root@node9 ~]# docker network create my_net1
3c765727244e0bf1e19ee4c6539232e51eea30a115b36ce5ae908ea4833d9c1d
[root@node9 ~]# docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
0f5f6bc4bbf6   bridge                      bridge    local
1b469e272a9a   host                        host      local
3c765727244e   my_net1                     bridge    local
ce6ef696809d   none                        null      local#桥接默认是单调递增
[root@docker ~]# ifconfig
br-1b13291bf8c7: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255inet6 fe80::42:7aff:fee8:5f36  prefixlen 64  scopeid 0x20<link>ether 02:42:7a:e8:5f:36  txqueuelen 0  (Ethernet)RX packets 8335  bytes 4402060 (4.1 MiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 10143  bytes 71967675 (68.6 MiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255inet6 fe80::42:e0ff:fe53:9260  prefixlen 64  scopeid 0x20<link>ether 02:42:e0:53:92:60  txqueuelen 0  (Ethernet)RX packets 8335  bytes 4402060 (4.1 MiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 10143  bytes 71967675 (68.6 MiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0#桥接也支持自定义子网和网关
[root@node9 ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway 192.168.0.100
2d17ab32024ae8d4272650c7ac0fe9aada6e7acb93409e35a29ff30b8a610382
[root@node9 ~]# docker network inspect my_net2
[{"Name": "my_net2","Id": "2d17ab32024ae8d4272650c7ac0fe9aada6e7acb93409e35a29ff30b8a610382","Created": "2024-08-28T16:28:22.122754722+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "192.168.0.0/24","Gateway": "192.168.0.100"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]
4.2. 为什么要自定义桥接
[root@docker ~]# docker run -d --name web1 nginx
d5da7eaa913fa6cdd2aa9a50561042084eca078c114424cb118c57eeac473424
[root@docker ~]# docker run -d --name web2 nginx
0457a156b02256915d4b42f6cc52ea71b18cf9074ce550c886f206fef60dfae5
[root@docker ~]# docker inspect web1
"Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:02","DriverOpts": null,"NetworkID": "7abac7f53cd3e9f8c9ec6cca5d736f390f4ccd326852a3b61e8c42f8953b94ac","EndpointID": "65d7c1a72a48499e4b5c361305bcb8e7054b37626ec5d5de70d7395ba6f5baa7","Gateway": "172.17.0.1","IPAddress": "172.17.0.2",      #注意ip信息"IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DNSNames": null[root@docker ~]# docker inspect web1"Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:03","DriverOpts": null,"NetworkID": "7abac7f53cd3e9f8c9ec6cca5d736f390f4ccd326852a3b61e8c42f8953b94ac","EndpointID": "26a3af63c8c7d97ea722a6bc25220d5ad73157dcf58f9e7df8a1b7639ae0ed8e","Gateway": "172.17.0.1","IPAddress": "172.17.0.3",   #注意ip信息"IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DNSNames": null#关闭容器后重启容器,启动顺序调换
[root@docker ~]# docker stop web1 web2
web1
web2
[root@docker ~]# docker start web2
web2
[root@docker ~]# docker start web1
web1
#我们会发容器ip颠倒docker引擎在分配ip时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的
多容器互访用ip很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定
docker原生网络是不支持dns解析的,自定义网络中内嵌了dns[root@docker ~]# docker run -d --network my_net1 --name web3 nginx
d9ed01850f7aae35eb1ca3e2c73ff2f83d13c255d4f68416a39949ebb8ec699f
[root@docker ~]# docker run -it --network my_net1 --name test busybox
/ # ping web3
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.197 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.096 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.087 ms注意:不同的自定义网络是不能通讯的
#在rhel7中使用的是iptables进行网络隔离,在rhel9中使用nftpables
[root@docker ~]# nft list ruleset可以看到网络隔离策略
4.3. 如何让不同的自定义网络互通?
[root@node9 ~]# docker network create mynet1 -d bridge
b7251c3df5a0094a5a6e46ed0b95b28c340f3fc07c582bd21b1466828b58a55c
[root@node9 ~]# docker network create mynet2 -d bridge
9feb3fab05a8dca230e76d49722a8d819c0134c473b2d01935ce3a5b482e6499
[root@node9 ~]# docker run -it --name testone --network mynet1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:32 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:4597 (4.4 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)#又开一个会话。
[root@node9 ~]# docker run -it --name testtwo --network mynet2 busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:13:00:02  inet addr:172.19.0.2  Bcast:172.19.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:36 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:5244 (5.1 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)/ # ping testone
ping: bad address 'testone'   #没有执行指令ping不通
/ # ifconfig                    #执行指令多一个网卡,可以ping
eth0      Link encap:Ethernet  HWaddr 02:42:AC:13:00:02  inet addr:172.19.0.2  Bcast:172.19.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:45 errors:0 dropped:0 overruns:0 frame:0TX packets:6 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:6154 (6.0 KiB)  TX bytes:380 (380.0 B)eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:03  inet addr:172.18.0.3  Bcast:172.18.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:15 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:2016 (1.9 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:8 errors:0 dropped:0 overruns:0 frame:0TX packets:8 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:794 (794.0 B)  TX bytes:794 (794.0 B)/ # ping testone
PING testone (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.145 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.146 ms
^C
--- testone ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.145/0.145/0.146 ms#在上面test容器中加入网络eth1
[root@node9 ~]# docker network connect mynet1 testtwo
4.4. joined容器网络

Joined容器一种较为特别的网络模式,•在容器创建时使用--network=container:vm1指定。(vm1指定的是运行的容器名) 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。

[root@node9 ~]# docker rm testone
testone
[root@node9 ~]# docker rm testtwo
testtwo
[root@node9 ~]# docker run -it --name testone --network mynet1 busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:15 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:2007 (1.9 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)[root@node9 ~]# docker run -it --name testtwo --network container:testone  busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0  #注意看ip信息UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:19 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:2416 (2.3 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)#重新删掉,为了效果,重新配。
[root@node9 ~]# docker rm testone
testone
[root@node9 ~]# docker rm testtwo
testtwo[root@node9 ~]# docker run -d --name testone --network mynet1 nginx
[root@node9 ~]# docker run -it --name testtwo --network container:testone centos:7
[root@b526153da4e6 /]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
4.5. joined网络示例演示

利用容器部署phpmyadmin管理mysql

#提前下载mysql包
[root@node9 ~]# docker load -i phpmyadmin-latest.tar.gz 
[root@node9 ~]# docker load -i mysql-5.7.tar.gz #运行phpmysqladmin
[root@docker ~]# docker run -d --name mysqladmin --network mynet1 \
-e PMA_ARBITRARY=1 \     #在web页面中可以手动输入数据库地址和端口
-p 80:80 phpmyadmin:latest#运行数据库
[root@docker ~]# docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD='123' \ #设定数据库密码
--network container:mysqladmin \ #把数据库容器添加到phpmyadmin容器中
mysql:5.7测试:
在浏览器访问172.25.254.100。在hphmyadmin界面新建mysql。#登录docker的mysql
docker exec -it mysql bash
mysql -uroot -p123
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| peihua316          |
| performance_schema |
| sys                |
| yangcun            |
| zhuzhuxia          |
+--------------------+
7 rows in set (0.00 sec)
mysql> SHOW TABLES FROM peihua316;
+---------------------+
| Tables_in_peihua316 |
+---------------------+
| 316                 |
+---------------------+
1 row in set (0.00 sec)
mysql> select * from peihua316.316;
+------+-------+------+-------+
| yaos | caimb | xies | liups |
+------+-------+------+-------+
| 2    | 3     | 1    | 4     |
+------+-------+------+-------+
1 row in set (0.01 sec)Note
开启的phpmyadmin容器中是没有数据库的
这里填写的localhost:3306是因为mysql容器和phpmyadmin容器公用一个网络站
5. 容器内外网的访问
5.1 容器访问外网

在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网 在rhel7之后的版本中通过nftables添加地址伪装来访问外网。

#清理网络环境,回到原来的网络环境
[root@node9 ~]# docker rm -f mysql
[root@node9 ~]# docker rm -f mysqladmin
[root@node9 ~]# docker network rm mynet2
mynet2
[root@node9 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
540ffd549691   bridge    bridge    local
1b469e272a9a   host      host      local
ce6ef696809d   none      null      local#切换模式iptables
grubby --update-kernel ALL --args iptables=true   #之前配置过就不用再配置。iptables是为了看效果,一般不用这个。#启动一个网络
[root@node9 ~]# docker run --rm -it --name test busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:14 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:1728 (1.6 KiB)  TX bytes:0 (0.0 B)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)/ # ping www.baidu.com
PING www.baidu.com (36.155.132.76): 56 data bytes
64 bytes from 36.155.132.76: seq=0 ttl=127 time=27.229 ms   #这里可以先ping可不可以通,之后再关掉iptables -t nat -D POSTROUTING 1 这个协议,再ping一下。
[root@node9 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCALChain INPUT (policy ACCEPT)
target     prot opt source               destination         Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCALChain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0 #内网访问外网策略
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
5.2 外网访问docker容器

端口映射 -p 本机端口:容器端口来暴漏端口从而达到访问效果。

#通过docker-proxy对数据包进行内转
[root@docker ~]# docker run -d --name webserver --rm -p 80:80 nginx
[root@node9 ~]# ps ax | grep proxy3572 ?        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 803578 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container-port 803666 pts/1    S+     0:00 grep --color=auto proxy#通过dnat策略来完成浏览内转,有双保险。
[root@node9 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCALChain INPUT (policy ACCEPT)
target     prot opt source               destination         Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCALChain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80Chain 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:8#删掉DNAT,再外面curl 172.25.254.100。应该是通的。因为有双保险。
iptables -t nat -D DOCKER 2
iptables -t nat -nL
[root@node9 ~]# curl 172.25.254.100
6. docker跨主机网络

在生产环境中,我们的容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力 跨主机网络解决方案 docker原生的overlay和macvlan 第三方的flannel、weave、calico 众多网络方案是如何与docker集成在一起的 libnetwork docker容器网络库 CNM (Container Network Model)这个模型对容器网络进行了抽象

6.1 CNM (Container Network Model)

CNM分三类组件 Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace) Endpoint:作用是将sandbox接入network (veth pair) Network:包含一组endpoint,同一network的endpoint可以通信

6.2 macvlan网络方式实现跨主机通信

macvlan网络方式

  • Linux kernel提供的一种网卡虚拟化技术。

  • 无需Linux bridge,直接使用物理接口,性能极好

  • 容器的接口直接与主机网卡连接,无需NAT或端口映射。

  • macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络

  • vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094

macvlan网络间的隔离和连通

  • macvlan网络在二层上是隔离的,所以不同macvlan网络的容器是不能通信的

  • 可以在三层上通过网关将macvlan网络连通起来

  • docker本身不做任何限制,像传统vlan网络那样管理即可 实现方法如下:

#在两台docker主机上各添加一块网卡,设置仅主机模式,开启混杂模式:
#一台:172.25.254.100 双网卡  一台:172.25.254.200  双网卡
#两台机子都要有docker;提前下载busybox镜像包。
#172.25.254.100    #两台机子都需要打开模式
[root@docker ~]# ip link set eth1 promisc on
[root@docker ~]# ip link set up eth1
[root@docker ~]# ifconfig eth1
eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
ether 00:0c:29:ec:fc:dd txqueuelen 1000 (Ethernet)
RX packets 83 bytes 8696 (8.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0#添加macvlan网路;#两台机子都需要添加
[root@docker ~]# docker network create \
-d macvlan \
--subnet 4.4.4.0/24 \
--gateway 4.4.4.4 \
-o parent=eth1 macvlan1
[root@docker ~]# docker network ls#测试
#在172.25.254.100中
[root@docker ~]# docker run -it --rm --name busybox --network macvlan1 --ip 4.4.4.2 busybox
/ # ifconfig
/ # ping 4.4.4.1
#在172.25.254.200中
[root@docker-node2 ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.200 --rm busybox
/ # ifconfig

相关文章:

Docker 进阶构建:镜像、网络与仓库管理

目录 三. docker镜像构建 1. docker镜像结构 2. 镜像运行的基本原理 3. 镜像获得方式 4. 镜像构建 5. Dockerfile实例 6. 镜像优化方案 6.1. 镜像优化策略 6.2. 镜像优化示例:缩减镜像层 6.3. 镜像优化示例:多阶段构建 6.4. 镜像优化示例:使用最精简镜像 四. docke…...

opencv学习:图像轮廓识别及代码实现

图像轮廓 1.获取图像轮廓 cv2.findContours() 函数是 OpenCV 库中用于检测图像中轮廓的函数。它可以检测到图像中所有连通区域的边界&#xff0c;并返回这些轮廓的列表。从 OpenCV 3.4 版本开始&#xff0c;这个函数的返回值和参数有所变化&#xff0c;以下是详细的参数说明&…...

存储课程学习笔记2_借助内核插入一个文件系统,用文件夹下测试文件系统(mount文件系统到目录下是入口)

裸盘是如何能达到我们日常操作目录那样&#xff0c;按目录依次访问文件等&#xff0c;实际上就是基于裸盘上&#xff0c;用文件系统进行控制。 0&#xff1a;总结。 0&#xff1a;mount是入口&#xff0c;一个裸盘先赋予文件系统&#xff0c;然后mount后才可以用。 1&#xf…...

chunk-vendors.js 文件过大导致页面加载缓慢解决方案

1、路由懒加载 在 Webpack 中&#xff0c;我们可以使用动态 import语法来定义代码分块点 (split point)&#xff1a; import(./Foo.vue) // 返回 Promise如果您使用的是 Babel&#xff0c;你将需要添加 syntax-dynamic-import 插件&#xff0c;才能使 Babel 可以正确地解析语…...

【Postgresql】地理空间数据的存储与查询,查询效率优化策略,数据类型与查询速度的影响

注&#xff1a;使用postgresql数据库会用到PostGIS 扩展。 一、安装PostGIS 扩展 在 PostgreSQL 中遇到错误 “type geography does not exist” 通常意味着你的 PostgreSQL 数据库还没有安装 PostGIS 扩展&#xff0c;或者 PostGIS 扩展没有被正确地安装在你的数据库中。geo…...

设计模式应用

单例模式 RunTime类是单例模式的体现&#xff0c;getRunTime()方法会返回一个唯一的实例。确保程序中只有一个唯一的RunTime类对象建造者模式 StringBuilder和StringBuffer是建造者模式的体现工厂模式 Calender类中Calender.getInstance()方法 DriverManager.getConnection()方…...

Android开机启动流程

Android开机启动流程 systemReady启动"added application" frameworks/base/services/java/com/android/server/SystemServer.java mainnew SystemServer().run();startBootstrapServicesmActivityManagerService ActivityManagerService.Lifecycle.startService(…...

数据结构基本知识

一、什么是数据结构 1.1、组织存储数据 ---------》内存&#xff08;存储&#xff09; 1.2、研究目的 如何存储数据&#xff08;变量&#xff0c;数组....)程序数据结构算法 1.3、常见保存数据的方法 数组&#xff1a;保存自己的数据指针&#xff1a;是间接访问已经存在的…...

浙大数据结构:02-线性结构4 Pop Sequence

这道题我们采用数组来模拟堆栈和队列。 简单说一下大致思路&#xff0c;我们用栈来存1234.....&#xff0c;队列来存输入的一组数据&#xff0c;栈与队列进行匹配&#xff0c;相同就pop 机翻 1、条件准备 stk是栈&#xff0c;que是队列。 tt指向的是栈中下标&#xff0c;fr…...

java开发,记录一些注解和架构 pojo、entity、respository

最近接了一个项目&#xff0c;说是项目其实也不算是项目&#xff0c;因为是把这个项目赛到其他项目中的。 熟悉一些这个项目的功能&#xff0c;梳理了一下&#xff0c;在代码开发中主要关心pojo、entity、respository、controller、service。 在这里主要记录前3个的流程与作用…...

MatLab基础学习01

MatLab基础学习01 1.基础入门2.MatLab的数据类型2.1数字2.2字符串2.3矩阵2.4.元胞数组2.5结构体 3.MatLab的矩阵的操作3.1矩阵定义与构造3.2矩阵的下标取值 4.MatLab的逻辑流程4. For循环结构4.2 While循环&#xff0c;当条件成立的时候进行循环4.3 IF end 1.基础入门 matlba必…...

第 5 章多视图几何

本章讲解如何处理多个视图&#xff0c;以及如何利用多个视图的几何关系来恢复照相机位置信息和三维结构。通过在不同视点拍摄的图像&#xff0c;我们可以利用特征匹配来计算出三维场景点以及照相机位置。本章会介绍一些基本的方法&#xff0c;展示一个三维重建的完整例子&#…...

IOS 开发者账号注册流程

注册步骤 准备资料 营业执照 法人信息&#xff08;电话、身份证信息&#xff09; 注册邮箱&#xff08;公司邮箱&#xff09; 开发者信息&#xff08;电话、身份证信息、邮箱&#xff09;1. 注册AppleID 注册地址&#xff1a; https://appleid.apple.com/account 填写表单信…...

netty之NioEventLoop和NioEventLoopGroup

类结构图 NioEventLoopGroup #mermaid-svg-5g1iVjr5oyhqXK92 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5g1iVjr5oyhqXK92 .error-icon{fill:#552222;}#mermaid-svg-5g1iVjr5oyhqXK92 .error-text{fill:#55222…...

睿考网:中级经济师考试题型有哪些?

中级经济师考试时间在每年的11月份&#xff0c;2024年考试时间定于11月16-17日&#xff0c;考试科目为《经济基础知识》与《专业知识与实务》两科。 《专业知识与实务》有10个专业&#xff0c;分别是工商管理、知识产权、农业经济、财政税收、金融、保险、运输经济、人力资源管…...

kubernetes集群部署Confluence 7.2.0+mysql 5.7(自测有效)

背景介绍&#xff1a; Confluence是一个专业的企业知识管理与协同软件。使用简单&#xff0c;但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论&#xff0c;信息推送。 这里介绍的使用的是Confluence 7.2.0版本的。 一、在kubernetes集群部署 1…...

Vmware ubuntu22.04 虚拟机 连接Windows主机虚拟串口

1. Windows虚拟串口配置 虚拟串口下载&#xff1a;虚拟串口 VSPD 的使用_vspd使用教程-CSDN博客 虚拟串口使用&#xff1a;使用虚拟串口在一台电脑上模拟串口通讯_pc怎么模拟一主多从串口-CSDN博客 2. ubuntu虚拟串口配置 Vmware ubuntu22.04 虚拟机 连接windows主机虚拟串口…...

Postgresql碎片整理

创建pgstattuple 扩展 CREATE EXTENSION pgstattuple 获取表的元组&#xff08;行&#xff09;信息&#xff0c;包括空闲空间的比例和行的平均宽度 SELECT * FROM pgstattuple(表名); 查看表和索引大小 SELECT pg_relation_size(表名), pg_relation_size(索引名称); 清理碎片方…...

【最新华为OD机试E卷-支持在线评测】字母组合(200分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…...

力扣493.翻转对

class Solution {public static int MAXN 50001;public static int[] help new int[MAXN];public static void main(String[] args) {}public static int reversePairs(int[] arr) {return counts(arr, 0, arr.length - 1);}//统计l …… r上反转对的数量&#xff0c;同时计算…...

潜望长焦+快充:vivo X200系列,小尺寸手机的大突破

在智能手机市场日益激烈的竞争中&#xff0c;厂商们不断推陈出新&#xff0c;以满足消费者多样化的需求。vivo作为中国知名的智能手机品牌&#xff0c;一直以其创新的设计和强大的功能赢得市场的认可。 近日&#xff0c;vivo X200系列的即将发布引起了广泛关注&#xff0c;特别…...

Stable Diffusion训练LoRA模型参数详细说明(阿里巴巴堆友AI)

工具&#xff1a;线上模型训练堆友AI 一、训练参数 批量大小 (Batch Size) 作用&#xff1a;每次训练中使用的样本数量。参考值&#xff1a;可以从 8 到 64&#xff0c;取决于显存大小。 训练轮数 (Epochs) 作用&#xff1a;完整遍历训练数据的次数。参考值&#xff1a;通…...

Learn ComputeShader 12 Setting up a buffer-based particle effect

unity有自己的粒子系统&#xff0c;但是这次我们要尝试创建一个我们自己的粒子系统&#xff0c;而且使用计算着色器有下面这些好处。总而言之&#xff0c;计算着色器适合处理大规模的数据集。例如&#xff0c;能够高效地处理数万个甚至数百万个粒子的计算。这对于粒子系统这样的…...

【STL中容器汇总】map、list、vector等详解

容器学习分享 1、STL简介1.1、STL六大组件 2、vector容器2.1、vector 基本操作2.2、vector容器示例2.3、vector容器存放自定义数据类型示例2.3、vector嵌套vector示例 3、list 容器3.1使用示例3.2、list容器基本函数 4、map容器4.1、map函数原型4.2、map函数示例 1、STL简介 ST…...

Semantic Kernel + Natasha:一小时快速生成100个API的奇迹

大家好&#xff0c;我今天带来了一个让人瞠目结舌的实验&#xff1a;在一小时内快速生成了100个API&#xff01; 其实如果手速高&#xff0c;可以更多。要知道&#xff0c;这得益于之前介绍过的Natasha —— 一个可以动态编译并加载代码的神奇工具。 动态编程神器! 探秘.Net…...

rancher upgrade 【rancher 升级】

文章目录 1. 背景2. 下载3. 安装4. 检查5. 测试5.1 创建项目5.2 创建应用5.3 删除集群5.4 注册集群 1. 背景 rancher v2.8.2 升级 v2.9.1 2. 下载 下载charts helm repo add rancher-latest https://releases.rancher.com/server-charts/latest helm repo update helm fetc…...

【Linux】多线程:线程互斥、互斥锁、线程安全

目录 一、多线程访问公共资源时所产生的问题 二、互斥相关背景概念 互斥量mutex&#xff08;锁&#xff09;的引入 三、互斥量 1、初始化互斥量&#xff08;mutex&#xff09; 2、互斥量加锁 3、互斥量解锁 4、 销毁互斥量 四、互斥量的使用 1、使用静态互斥量 2、…...

进程之间的通信方式

前言 每个进程的用户地址空间都是独立的&#xff0c;一般而言是不能互相访问的&#xff0c;但内核空间是每个进程都共享的&#xff0c;所以进程之间要通信必须通过内核。 Linux提供了以下进程通信方式&#xff1a; 一、管道 所谓的管道&#xff0c;就是内核里面的一串缓存。…...

动手学深度学习(pytorch)学习记录26-卷积神经网路(LeNet)[学习记录]

目录 LeNet模型训练 LeNet 总体来看&#xff0c;LeNet&#xff08;LeNet-5&#xff09;由两个部分组成&#xff1a; 卷积编码器&#xff1a;由两个卷积层组成; 全连接层密集块&#xff1a;由三个全连接层组成。 每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均…...

log4j 和 java.lang.OutOfMemoryError PermGen space

还是OneCoder在项目中沙箱的问题&#xff0c;用classloader隔离做的沙箱&#xff0c;反复运行用户的任务&#xff0c;出现永生区内存溢出&#xff1a; java.lang.OutOfMemoryError: PermGen space 这个问题在tomcat重复热部署的时候其实比较常见。其道理也和我们沙箱的道理基本…...