Docker镜像制作与仓库搭建

2023-05-16

Docker

        • 1,docker镜像制作
        • 2,docker仓库搭建

1,docker镜像制作

docker官方和个人发布的镜像由于版本等各种原因,漏洞较多,已统计Docker Hub超过30%的官方镜像包含高位漏洞。此外,由于网络等原因也会造成docker pull 下载镜像的速度很慢。基于这种情况,我们可以手动定制docker系统镜像。构建镜像的方式有两种:

  • 使用docker commit命令
  • 使用docker build和Dockerfile文件

方式一:docker commit

步骤1:拉取一个基础镜像(其实就是OS)

docker pull centos

在这里插入图片描述
步骤2:创建一个交互式容器

docker run -it --name mycentos centos /bin/bash

在这里插入图片描述
这里的 ll 命令找不到,可能是因为版本问题,这个不影响,想要使用参考解决 ll 命令无法使用

步骤3:将需要的资源上传到宿主机上
在这里插入图片描述
注意!!!:本例是制作一个tomcat镜像,所以需要这些资源

步骤4:将宿主机上的资源拷贝到容器

docker cp apache-tomcat-7.0.64.tar.gz mycentos:/root

docker cp jdk-8u181-linux-x64.tar.gz mycentos:/root

在这里插入图片描述
在这里插入图片描述
步骤5:在容器安装jdk,解压并配置

# 解压jdk到/usr/local/目录下
tar -zxvf jdk-8u181-linux-x64.tar.gz -C /usr/local/

# 打开profile文件,配置环境
vi /etc/profile

在这里插入图片描述
在这里插入图片描述
这里就跟Linux安装jdk一样的,配置好之后刷新一下,就可以了

在这里插入图片描述

步骤6:在容器安装tomcat,解压并配置

# 解压tomcat到/usr/local/目录下
tar -zxvf apache-tomcat-7.0.64.tar.gz -C /usr/local/

# 编辑tomcat的setclsspath.sh文件
vi /usr/local/apache-tomcat-7.0.64/bin/setclasspath.sh

在这里插入图片描述
在这里插入图片描述

步骤7:将运行的mycentos容器提交为一个新的镜像,新的镜像名称为mytomcat

docker commit mycentos mytomcat

在这里插入图片描述
到这里,我们的镜像就已经制作好了

  • 端口映射

基于mytomcat镜像创建一个容器

docker run -itd --name t1 -p 8888:8080 mytomcat /bin/bash

#进入容器,并去执行startup.sh文件
docker exec t1 /usr/local/apache-tomcat-7.0.64/bin/startup.sh

在这里插入图片描述
访问看到如下效果就说明成功了

在这里插入图片描述

  • 容器/镜像打包
#1,镜像打包
docker save -o /root/tomcat7.tar mytomcat

#2,将打包的镜像上传到其他服务器
scp tomcat7.tar 其他服务器ip:.root


#1,容器打包
docker export -o /root/t1.tar t1
#2,导入容器
docker import t1.tar mytomcat:latest

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打包完成了,该导入了

docker load -i /root/tomcat7.tar

在这里插入图片描述
至此算是完成了

方式二:docker builder

Dockerfile使用基本的基于DSL语法的指令来构建一个Docker镜像,之后使用docker builder命令基于该Dockerfile中的指令构建一个新的镜像

  • DSL语法
    在这里插入图片描述
DSL语法:
1)FROM(指定基础image)
构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。
FROM命令告诉docker我们构建的镜像是以哪个(发行版)镜像为基础的。第一条指令必须是FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令。

该指令有两种格式:
FROM <image> 
指定基础image为该image的最后修改的版本。或者:

FROM <image>:<tag> 
指定基础image为该image的一个tag版本。

RUN后面接要执行的命令,比如,我们想在镜像中安装vim,只需在Dockfile中写入 RUN yum install -y vim

2)MAINTAINER(用来指定镜像创建者信息)
构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。

格式:
MAINTAINER <name>

3)RUN(安装软件用)
构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。

该指令有两种格式:
RUN <command>  

4)CMD(设置container启动时执行的操作)
设置指令,用于container启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。

该指令有三种格式:
CMD ["executable","param1","param2"]
CMD command param1 param2

当Dockerfile指定了ENTRYPOINT,那么使用下面的格式:
CMD ["param1","param2"]

其中:
ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。
所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。

5)ENTRYPOINT (设置container启动时执行的操作)
设置指令:指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。

两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。
当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖,只有最后一个CMD或者ENTRYPOINT有效。

# CMD指令将不会被执行,只有ENTRYPOINT指令被执行
CMD echo “Hello, World!” 
ENTRYPOINT ls -l 

另一种语法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;
ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。

FROM ubuntu 
CMD ["-l"] 
ENTRYPOINT ["/usr/bin/ls"] 

6)USER(设置container容器的用户)
设置指令,设置启动容器的用户,默认是root用户。

# 指定memcached的运行用户 
ENTRYPOINT ["memcached"] 
USER daemon 
或者
ENTRYPOINT ["memcached", "-u", "daemon"]

7)EXPOSE(指定容器需要映射到宿主机器的端口)
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址,而是使用宿主机器的IP地址和映射后的端口。
要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后再运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。
也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口,相应的运行容器的时候,可以配套的多次使用-p选项
EXPOSE <port> [<port>...]

# 映射一个端口 
EXPOSE port1 

# 相应的运行容器使用的命令 
docker run -p port1 image 

# 映射多个端口 
EXPOSE port1 port2 port3 
# 相应的运行容器使用的命令 
docker run -p port1 -p port2 -p port3 image 
# 还可以指定需要映射到宿主机器上的某个端口号 
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image

端口映射是docker比较重要的一个功能,原因在于我们每次运行容器的时候容器的IP地址不能指定而是在桥接网卡的地址范围内随机生成的。
宿主机器的IP地址是固定的,我们可以讲容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP的地址。
对于一个运行的容器,可以使用docker port加上容器中需要映射的端口和容器的ID来看该端口号在宿主机器上的映射端口。

8)ENV(用于设置环境变量)
主要用于设置容器运行时的环境变量

格式:
ENV <key> <value> 

设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。

假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:
ENV JAVA_HOME /path/to/java/dirent

9)ADD(从src复制文件到container的dest路径)
主要用于将宿主机中的文件添加到镜像中
构建指令,所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0:如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录:
如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式):如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>:
如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。

格式:
ADD <src> <dest> 

<src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;
<dest> 是container中的绝对路径

10)VOLUME(指定挂载点)
设置指定,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,
这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令

格式:
VOLUME ["<mountpoint>"]
VOLUME ["/tmp/data"]

运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器:
docker run -t -i -rm -volumes-from container1 image2 bash

其中:container1为第一个容器的ID,image2为第二个容器运行image的名字。

11)WORKDIR(切换目录)
设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。

格式:
WORKDIR /path/to/workdir 

# 在/p1/p2下执行vim a.txt 
WORKDIR /p1 WORKDIR p2 RUN vim a.txt 

12)ONBUILD(在子镜像中执行)

格式:
ONBUILD <Dockerfile关键字> 

ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行

dockerfile构建镜像:

步骤1:创建一个目录

mkdir rw-test

在这里插入图片描述
步骤2:编辑Dockerfile文件,注意D要大写

vim Dockerfile

编辑内容如下:

#pull down centos image
FROM docker.io/centos
MAINTAINER ruanwen onlien033_login@126.com
#install nginx
RUN yum install -y pcre pcre-devel openssl openssl-devel gcc gcc+ wget vim net-tools
RUN useradd www -M -s /sbin/nologin
RUN cd /usr/local/src && wget http://nginx.org/download/nginx-1.8.0.tar.gz && tar -zxvf nginx-1.8.0.tar.gz
RUN cd /usr/local/src/nginx-1.8.0 && ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module && make && make install

ENTRYPOINT /usr/local/nginx/sbin/nginx && tail -f /usr/local/nginx/logs/access.log

在这里插入图片描述
在这里插入图片描述
步骤3:在rw-test目录下构建镜像:

docker build -t rw_nginx --rm=true .

-t	表示选择指定生成镜像的用户名,仓库名和tag
--rm=true	表示指定在生成镜像过程中删除中间产生的临时容器
注意:上面构建命令中最后的.符合不要漏了,表示使用当前目录下的Dockerfile构建镜像

在这里插入图片描述
会依次运行Dockerfile文件的每一个步骤

步骤4:测试

docker run -ti -d --name test_nginx -p 8899:80 rw_nginx /bin/bash
docker exec test_nginx /bin/bash
#
通过浏览器访问:http://ip:8899

2,docker仓库搭建

Docker仓库(Repository)类似与代码仓库,是Docker集中存放镜像文件的地方。

  • docker hub

1,打开https://hub.docker.com/
2,注册账号,略
3,创建仓库(Create Repository):略
4,设置镜像标签
docker tag local-image:tagname new-repo:tagname
示例:docker tag hello-word:latest myqxin/test-hello-world:v1
5,登录docker hub
docker login(回车,输入账号和密码)
6,推送镜像
docker push new-repo:tagname
示例:docker push myqxin/test-hello-world:v1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我这里把test-hello-world弄成了test-hell-world,你们注意一下

  • 阿里云

略:参考官方文档

步骤:
1,创建阿里云账号
2,创建命令空间
3,创建镜像仓库
4,操作指南
$ sudo docker login --username=[账号名称] registry.cn-hangzhou.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/360buy/portal:[镜像版本号]
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/360buy/portal:[镜像版本号]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 搭建私有仓库

1,启动docker Registry,使用Docker官方提供的Registry镜像就可以搭建本地私有镜像仓库,具体指令如下。

docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v /mnt/registry:/var/lib/registry \
registry:2

在这里插入图片描述

指令参数说明:
-d:表示在后台运行该容器
-p 5000:5000:表示将私有镜像仓库容器内部默认暴露的5000端口映射到宿主机的5000端口
–restart=always:表示容器启动后自动启动本地私有镜像仓库
–name registry:表示为生成的容器命名为registry
-v /mnt/registry:/var/lib/registry:表示将容器内的默认存储位置/var/lib/registry中的数据挂载到宿主机的/mnt/registry目录下,这样当容器销毁后,在容器中/var/lib/registry目录下的数据会自动备份到宿主机指定目录
提示:
Docker Registry目前有v1和v2两个版本,v2版本并不是v1版本的简单升级,而是在很多功能上都有了改进和优化。v1版本使用的是Python开发的,而v2版本是用go语言开发的,v1版本本地镜像仓库容器中数据默认挂载点是/tmp/registry,而v2版本的本地镜像仓库容器中数据默认挂载点是/var/lib/registry

重命名镜像:之前推送镜像时,都是默认推送到远程镜像仓库,而本次是将指定镜像推送到本地私有镜像仓库。由于推送到本地私有镜像仓库的镜像名称必须符合“仓库IP:端口号/repository”的形式,因此需要按照要求修改镜像名称,具体操作指令如下。

docker tag hello-world:latest localhost:5000/myhellodocker

在这里插入图片描述

推送镜像:本地私有镜像仓库搭建并启动完成,同时要推送的镜像也已经准备就绪后,就可以将指定镜像推送到本地私有镜像仓库了,具体操作指令如下

docker push localhost:5000/myhellodocker

在这里插入图片描述

查看本地仓库镜像
http://localhost:5000/v2/myhellodocker/tags/list (注意:使用该地址时注意镜像名称)
由于做了目录挂载,因此可以在本地的该目录下查看:
/mnt/registry/docker/registry/v2/repositories
推送,不需要输入账号密码(不安全)

  • 配置私有仓库认证

1,查看Docker Registry私有仓库搭建所在服务器地址:ipconfig
例如:服务器地址为:192.168.204.130
2,生成自签名证书(在home目录下执行上述指令后)
要确保Docker Registry本地镜像仓库的安全性,还需要一个安全认证证书,来保证其他Docker机器不能随意访问该机器上的Docker Registry本地镜像仓库,所以需要在搭建Docker Registry本地镜像仓库的Docker主机上先生成自签名证书(如果已购买证书就无需生成),具体操作指令如下:

mkdir registry && cd registry && mkdir certs && cd certs

openssl req -x509 -days 3650 -subj '/CN=192.168.204.130:5000/' \    
 -nodes -newkey rsa:2048 -keyout domain.key -out domain.crt

指令参数说明:
-x509:x509是一个自签发证书的格式
rsa:2048,是证书算法长度
domain.key和domain.crt:就是生成的证书文件
3,生成用户名和密码
在Docker Registry本地镜像仓库所在的Docker主机上生成自签名证书后,为了确保Docker机器与该Docker Registry本地镜像仓库的交互,还需要生成一个连接认证的用户名和密码,使其他Docker用户只有通过用户名和密码登录后才允许连接到Docker Registry本地镜像仓库

cd .. && mkdir auth

docker run --entrypoint htpasswd registry:2 -Bbn ruanwen 123456 > auth/htpasswd

4、启动Docker Registry本地镜像仓库服务(将之前创建的容器删除)

docker run -d \ 
 -p 5000:5000 \  
 --restart=always \  
 --name registry \  
 -v /mnt/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 \ 
 -v `pwd`/certs:/certs \  
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \  
 -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ 
  registry:2

5、配置Docker Registry访问接
完成Docker Registry本地镜像仓库服务启动后,还需要在搭建了Docker Registry本地镜像仓库所在的Docker主机上配置供其他Docker机器访问的接口,具体指令如下:

sudo mkdir -p /etc/docker/certs.d/192.168.204.130:5000
sudo cp certs/domain.crt /etc/docker/certs.d/192.168.204.130:5000

6、Docker Registry私有仓库使用登记
在Docker机器终端使用sudo vim /etc/docker/daemon.json命令编辑daemon.json文件,在该文件中添加如下内容
{“insecure-registries”:[“192.168.200.162:5000”]}
7、重启并加载docker配置文件
sudo /etc/init.d/docker restart
二、验证测试1、装备镜像
docker tag hello-world:latest 192.168.200.162:5000/myhelloworld
2、推送镜像
docker push 192.168.200.141:5000/myhelloworld
送过程中出现错误,信息提示为:no basic auth credentials(即没有通过身份验证),所以无法进行推送,这也就说明身份验证的配置有效。要想成功推送,需要先登录成功后再推送
3、登录Docker Registry镜像仓库
docker login 192.168.200.162:5000
4、再次推送
docker push 192.168.200.139:5000/myhelloworld
5、结果验证

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Docker镜像制作与仓库搭建 的相关文章

随机推荐

  • 学习笔记30--ros-gazebo仿真的一些插件学习推荐以及一些urdf关节理解分享

    环境 ubuntu16 04 ros kinectic gazebo7 16 lt 一 gt gazebo支持以下几种插件类型 并且所有插件类型都可以链接到ros 但只能通过urdf文件引用 ModelPlugins xff0c 提供对Ph
  • 学习笔记32--仿真使用的urdf的物理属性定义解析

    环境 ubuntu16 04 ros kinetic gazebo7 16 导入 搞项目不一定要等到实际机器人结构出来 才能测试代码的 很多时候需要根据需要手动编写urdf来仿真测试的 那么 仿真时候 机器人的一些摩擦系数转动惯量是怎么定义
  • 学习笔记35-- 仿真时用到的d435以及16线雷达在urdf中定义以及launch注意点

    环境 ubuntu16 04 ros kinetics gazebo7 16 来源 仿真有d435以及16线雷达的urdf编写 注意 urdf采用的是 xacro编写的 d435 16vel urdf xacro span class to
  • 杂记7--opencv的ar码模块学习

    背景 xff1a 项目需要用到marker知识 xff0c 所以到官网上临时补一些知识 概要 xff1a 主要介绍marker一些接口的含义 xff0c 纯属个人理解 xff0c 有误则希望大佬不吝赐教 1 涉及ar码操作学习 xff0c
  • Maven-3.6.1下载与环境搭建(解决IDEA兼容问题)及其配置

    Maven 3 6 1下载与环境搭建 xff08 解决IDEA兼容问题 xff09 及配置 Maven下载路径配置系统环境路径配置测试 Maven的文件目录结构解析IDEA中Maven的配置IDEA中Maven的全局配置 注意 xff1a
  • 构建一个arm裸板轻量级的printf

    构建一个arm裸板轻量级的printf span class token keyword typedef span span class token keyword char span span class token operator s
  • 二维小游戏,飞机大战,图片素材

    二维小游戏 xff0c 飞机大战 xff0c 图片素材 高清大图下载链接 https download csdn net download qq 45706825 15042600
  • hallib_RTC

    RTC 一 配置参数 1 2 只有使能RTC之后才能选LSE 二 编写应用代码 1 在mspinit里面加上这个函数 xff0c 打开秒中断 xff0c 这个函数在 h文件里面 span class token function HAL R
  • hullib_Tim3TiggerAdc1

    Tim3TiggerAdc1 只有Tim3才可以用更新 xff08 TIM TRGO UPDATE xff09 触发adc xff0c 其他定时器都要用输出比较模式才可以 一 cubmax配置 1 配置tim3为500ms更新 xff0c
  • hullib_AdcBase

    AdcBase 也就是不用中断 xff0c 每次用软件触发的简单操作 一 cubmax配置 1 选好通道就可以了 xff0c 其他都不用管 二 需要编写的代码 1 在main函数while里面写上 span class token keyw
  • hullib_eeprom

    EEPROM 这个模拟iic真的搞了好久啊 xff0c 最后发现这个24c02写完之后至少要延时4ms再来读才可以 xff0c 要不然读的时候都是NACK 一 时序 自己看数据手册吧
  • hullib_PwmCapture

    PwmCapture 需要两个channel 一 cubemx配置 一个上升沿捕获 xff0c 一个下降沿捕获 打开中断 二 自己写的代码 1 开启两个通道的中断 span class token function HAL TIM IC S
  • 2021-03-16

    hullib Rtc 获取时间之后必须获取日期他才会有时间 HAL RTC GetTime amp hrtc amp sTime RTC FORMAT BIN HAL RTC GetDate amp hrtc amp sDate RTC F
  • hullib_PwmOutput

    hullib PwmOutput 一 cubmx需要配置的 1 这里一定是pwm Generation 而不是pwm outcompare 使用定时器的PWM模式只能在4个通道产生频率相同但占空比不同的输出信号 使用定时器的输出比较模式可以
  • 计算机类非全日制研究生

    北京市 10002 中国人民大学 院系所专业研究方向考试范围 159 信息学院 xff08 专业学位 xff09 085400 专业学位 电子信息 02 软件工程领域 xff08 非全 xff09 详情 159 信息学院 xff08 专业学
  • 史上最详细的Docker 镜像的制作-上传-拉取--部署(阿里云)

    Docker 镜像的制作 上传 拉取 部署 一 镜像 xff08 images xff09 1 什么是镜像 xff1f 2 镜像的组成和用途 xff08 1 xff09 Dockerfile xff08 2 xff09 scratch xf
  • 机动目标跟踪-Singer模型,当前统计模型,交互多模型与卡尔曼滤波的结合

    文章目录 非机动目标跟踪算法原理一 Singer 模型算法二 当前统计模型算法三 交互多模型算法 实验仿真一 低机动情况1 1 Singer模型参数设置1 2 当前统计模型参数设置1 3交互多模型参数设置1 4 对比分析 二 一般机动情况2
  • 用大白话解析函数调用,系统调用和API之间的关系

    一 官方的解释 大概了解一下 函数调用 函数调用是计算机编或运行时 xff0c 使用某个函数来完成相关命令 系统调用 系统调用是用户在程序中使用 访管指令 调用由操作系统提供的子功能集合 API 应用编程接口 xff08 Applicati
  • docker删除所有容器和镜像

    确保自己有权限 xff0c 一般先执行下面的命令获取管理员权限 span class token function sudo span span class token function su span 1 杀死运行的容器 xff1a sp
  • Docker镜像制作与仓库搭建

    Docker 1 xff0c docker镜像制作2 xff0c docker仓库搭建 1 xff0c docker镜像制作 docker官方和个人发布的镜像由于版本等各种原因 xff0c 漏洞较多 xff0c 已统计Docker Hub超