一 Docker简介

1.1 什么是docker?

官方站点:https://docs.docker.com/

image-20251004025136295

要理解什么是Docker就先明白为什么需要 Docker?(核心痛点)

在 Docker 出现前,开发和运维常面临 “环境不一致” 的噩梦:

  • 开发电脑上:Windows/macOS 系统,安装了 Python 3.8、MySQL 5.7,依赖库版本精确匹配,代码跑得很顺畅。
  • 测试 / 生产服务器上:Linux 系统,可能预装了 Python 3.6、MySQL 8.0,甚至缺少某个隐藏依赖,导致代码报错、功能失效。
  • 本质原因:软件运行需要 “操作系统内核 + 系统库 + 依赖包 + 配置” 的完整环境,不同机器的环境差异会打破运行一致性。

Docker 的解决方案是:把软件和它依赖的 “最小环境” 一起打包成一个独立的 “容器”,这个容器能在任何支持 Docker 的机器上 “原样运行”,无需再手动配置环境。

Docker 的核心概念:3 个关键组件

image-20251004025730524

要理解 Docker,必须先掌握它的 3 个核心概念,它们是 Docker 工作的基础:

概念 核心作用 类比(生活化理解)
镜像(Image) 软件的 “安装包” 或 “模板”,包含运行软件所需的所有文件(代码、依赖、配置、系统库) 手机 App 的 “安装包(.apk/.ipa)”
容器(Container) 镜像的 “运行实例”,是一个独立的、可执行的环境(镜像加载后在内存中形成的进程) 手机上 “已安装并正在运行的 App”
仓库(Repository) 存储和分发镜像的 “仓库”,类似代码仓库(如 GitHub) 手机的 “应用商店(App Store)”

概念间的关系(流程):

  1. 开发者在本地编写代码,然后将 “代码 + 依赖环境” 打包成 镜像
  2. 将镜像上传到 仓库(如 Docker Hub,官方公共仓库);
  3. 运维人员从仓库下载镜像,在服务器上启动镜像,生成 容器(软件开始运行)。

整个过程中,“镜像” 是 “不变的模板”,“容器” 是 “可变的运行实例”—— 比如一个 Nginx 镜像,可以启动 10 个容器,对应 10 个独立的 Nginx 服务。

1.2 Docker与传统虚拟机区别

Docker 不是虚拟机!(关键区别)

很多人会把 Docker 和虚拟机(VM,如 VMware、VirtualBox)混淆,但两者的底层原理完全不同,效率差距极大:

image-20251004025641787

对比维度 Docker(容器) 传统虚拟机(VM)
底层依赖 共享宿主机的操作系统内核(仅模拟用户空间) 虚拟完整的操作系统(内核 + 用户空间)
资源占用 极轻量(MB 级),启动快(秒级) 重量级(GB 级),启动慢(分钟级)
隔离性 进程级隔离(隔离性中等) 系统级隔离(隔离性极强)
适用场景 部署微服务、应用打包、环境一致性保障 运行不同内核的系统(如 Windows 跑 Linux)

简单说:虚拟机是 “模拟一台完整电脑”,而 Docker 是 “模拟一个独立的应用进程”—— 前者资源开销大,后者轻量高效,更适合现代软件部署。

1.3 Docker 的核心优势

  1. 环境一致性:“一次构建,到处运行”,彻底解决 “开发能跑,生产报错” 的问题。
  2. 轻量高效:容器共享宿主机内核,启动快、占用资源少,一台服务器可运行成百上千个容器。
  3. 隔离性:每个容器是独立的 “沙箱”,进程、文件、网络互不干扰(比虚拟机弱,但满足大部分场景)。
  4. 易于扩展:支持快速复制容器(如 1 个 Nginx 容器扩展到 10 个),配合 Kubernetes(K8s)可实现自动化扩缩容。
  5. 版本控制:镜像支持版本管理(如 nginx:1.21nginx:1.22),可快速回滚到历史版本。

1.4 Docker 的常见应用场景

  1. 开发环境统一:团队成员通过 Docker 镜像获取一致的开发环境,无需手动配置依赖(比如前端的 Node.js 环境、后端的 Java 环境)。

  2. 微服务部署:现代微服务架构(如 Spring Cloud、K8s)的基础 —— 每个微服务打包成一个镜像,独立部署、升级。

  3. 持续集成 / 持续部署(CI/CD):在自动化流水线中,用 Docker 打包应用,然后自动部署到测试 / 生产环境。

  4. 快速测试:启动一个临时容器测试新功能,测试完成后直接删除,不污染宿主机环境(如测试不同版本的数据库)。

    image-20251004025837394

  • 在企业中docker作为业务的最小载体而被广泛应用
  • 通过docker企业可以更效率的部署应用并更节省资源

[!NOTE]

IaaS(Infrastructure as a Service),即基础设施即服务

PaaS是(Platform as a Service)即指平台即服务

SaaS(Software as a Service)软件运营服务是

二 部署docker

1.配置软件仓库,安装docker

[root@docker-node1 ~]# vim /etc/yum.repos.d/docker.repo
[docker-ce]
name = docker-ce
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck = 0

2.删除redhat系统自带的podman,防止与docker冲突

[root@docker-node1 ~]# rpm -qa | grep podman
podman-4.9.4-0.1.el9.x86_64
cockpit-podman-84.1-1.el9.noarch

3.安装docker-ce并启动服务

[root@docker-node1 ~]# dnf install docker-ce.x86_64  -y
[root@docker-node1 ~]# systemctl enable --now docker
#查看docker详细信息
[root@docker-node1 ~]# docker info

4.docker初始化设置,激活内核网络选项

#编辑docker启动文件,设定其使用iptables的网络管理设定方式,默认使用nftables
[root@docker-node1 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock  --iptables=true
[root@docker-node1 ~]# systemctl daemon-reload
[root@docker-node1 ~]# systemctl restart docker


#以下操作只要在rhel7上做
]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
]# modprobe br_netfilter
]# vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

#rhel9只需要打开内核路由功能,因为容器在运行时是通过桥接模式连接真实主机
[root@docker-node1 ~]# echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf
[root@docker-node1 ~]# sysctl -p
net.ipv4.ip_forward = 1

三 Docker的基本操作

1.docker镜像命令基本操作

1.从镜像仓库搜索镜像

#docker默认镜像仓库是docker.io,使用docker的镜像仓库需要VPN加速
[root@Docker-node1 ~]# docker search  nginx
NAME           DESCRIPTION                                      STARS     OFFICIAL
nginx          Official build of Nginx.                         20094     [OK]
参数 说明
NAME 镜像名称
DESCRIPTION 镜像说明
STARS 点赞数量
OFFICIAL 是否是官方的

2.从镜像仓库拉取镜像

[root@Docker-node1 ~]# docker pull busybox
[root@Docker-node1 ~]# docker pull nginx:1.26-alpine	#alpine版本,nginx镜像的最小安装发行版本

3.导入与导出镜像

#导入镜像到本地
[root@docker-node1 ~]# docker load -i nginx-latest.tar.gz
#导出镜像
[root@docker-node1 ~]# docker save -o fjw.tar nginx:latest timinglee/game2048:latest
#当本地镜像比较多时,可以使用awk来全部导出
[root@docker-node1 ~]# docker save -o yyy.tar `docker images | awk 'NR>1{print $1":"$2}'`

[!NOTE]

  • -i:input,用于导入镜像;

  • -o:output;

    1.用于指定导出镜像的位置;

    2.可以同时导出多个镜像到一个文件中;

    3.指定.tar可以导出并打包。

4.查看本地镜像与详细信息

#查看本地镜像
[root@docker-node1 packages]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    5ef79149e0ec   11 months ago   188MB
busybox      latest    65ad0d468eb1   2 years ago     4.26MB
centos       7         eeb6ee3f44bd   3 years ago     204MB

#查看镜像详细信息
[root@docker-node1 packages]# docker image inspect busybox:latest
[root@docker-node1 packages]# docker inspect centos:7

5.删除镜像

[root@docker-node1 packages]# docker rmi nginx:latest
#通过``优先执行里面的内容通过awk来删除所有的本地镜像,当本地镜像较多时可以一次性删除
[root@docker-node1 packages]# docker rmi  `docker images | awk 'NR>1{print $1":"$2}'`

2.docker容器命令基本操作

1.启动容器

[!NOTE]

容器命令参数

-d			#后台运行
-i			#交互式运行
-t			#打开一个终端
--name		#指定容器名称
-p			#端口映射 -p 80:8080 	把容器8080端口映射到本机80端口
--rm		#容器停止自动删除容器
--network	#指定容器使用的网络,容器默认使用桥接网络;可以改为host,none等
#-d后台运行一个容器,-p 1234:8080把容器8080端口映射到本机1234端口
[root@docker-node1 ~]# docker run -d --name mario -p 1234:8080 timinglee/mario:latest

#运行一个使用shell交互的容器,-it:与容器进行终端交互,-i表示保持标准输入打开,-t表示分配一个伪终端
[root@Docker-node1 ~]# docker run -it --name centos centos:7
[root@3ba22e59734f /]#
#进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器

#容器开启后没停止在后台运行时

#当退出容器后没停止容器,可以使用attach重新与容器交互
[root@docker-node1 ~]# docker attach centos

#当退出容器后没停止容器,也可以使用docker exec -it 指定shell创建一个新进程重新进入容器交互
[root@docker-node1 ~]# docker exec -it centos bash/sh

#如果容器停止了可以start开启容器进行交互运行
[root@docker-node1 ~]# docker start mario

#可以在容器中执行命令

[root@docker-node1 packages]# docker exec -it centos ls
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

[!WARNING]

有些镜像开启容器没有后台驻守程序,在运行时不加-it参数运行后会关闭!!

有驻守程序不加-it参数的话会占用当前终端

运行应用服务器或web服务器端口映射的默认会使用除shell外的驻守程序;

如果使用shell为驻守程序会导致服务不可用

image-20250806025852132

2.查看容器运行信息

[root@Docker-node1 ~]# docker ps					#查看当前运行容器
[root@Docker-node1 ~]# docker ps -a					#查看所有容器,包括停止的容器
[root@Docker-node1 ~]# docker inspect busybox		#查看容器运行的详细信息

3.停止和运行容器

[root@docker-node1 ~]# docker start mario			#停止容器
[root@Docker-node1 ~]# docker kill busybox			#杀死容器,可以使用信号
[root@docker-node1 ~]# docker stop mario			#开启停止的容器

[!NOTE]

容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

4.删除容器

[root@Docker-node1 ~]# docker rm centos7			#删除停止的容器
[root@Docker-node1 ~]# docker rm -f busybox			#删除运行的容器
[root@Docker-node1 ~]# docker container prune -f	#删除所有停止的容器

5.容器内容提交

默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件;

如果想永久保存,那么我们需要把动作提交,提交后会生成新的镜像;

当我们在运行新镜像后即可看到我们提交的内容。

[root@docker-node1 docker]# docker run -it --name test busybox:latest
/ # touch testfile										#在容器中建立文件
/ # ls
bin       dev       etc       home      lib       lib64     proc      root      sys       testfile  tmp       usr       var
/ # exit
[root@docker-node1 docker]# docker rm test				#删掉容器后开启新的容器文件不存在
test
[root@docker-node1 docker]# docker run -it --name test busybox:latest
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # touch testfile							#想要永久保存
/ # ls
bin       dev       etc       home      lib       lib64     proc      root      sys       testfile  tmp       usr       var
/ # [root@docker-node1 docker]#				#退出不停止容器<ctl><p+q>
#使用commit命令来提交内容,构建一个镜像
[root@docker-node1 docker]# docker commit -m "add testfile" test busybox:testv1

[root@docker-node1 docker]# docker images
busybox           testv1    bc50de975732   6 seconds ago       4.26MB

[root@docker-node1 docker]# docker image history busybox:testv1
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
bc50de975732   30 seconds ago   sh                                  21B       add testfile
65ad0d468eb1   2 years ago      BusyBox 1.36.1 (glibc), Debian 12   4.26MB

[!NOTE]

此方法不利于企业审计,所以不推荐使用,在企业中我们多用Dockerfile来构建镜像

6.系统与容器之间的文件传输

#把容器中的文件复制到本机
[root@docker-node1 docker]# docker cp test:/etc/hosts /root/docker/
#把本机文件复制到容器中
[root@docker-node1 docker]# docker cp ./centos.repo test:/etc

7.查询容器内部日志

[root@docker-node1 docker]# docker logs test
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # touch testfile
/ # ls
bin       dev       etc       home      lib       lib64     proc      root      sys       testfile  tmp       usr       var
/ #
/ #
/ # ls
bin       dev       etc       home      lib       lib64     proc      root      sys       testfile  tmp       usr       var
/ #
/ # cd etc/
/etc # ;s
sh: syntax error: unexpected ";"
/etc # ls
group          hosts          mtab           nsswitch.conf  resolv.conf
hostname       localtime      network        passwd         shadow
/etc # ls
centos.repo    hostname       localtime      network        passwd         shadow
group          hosts          mtab           nsswitch.conf  resolv.conf
/etc # cat centos.repo
[centos]
name = centos
baseurl = https://mirrors.aliyun.com/centos/7/os/x86_64/
gpgcheck = 0

四 docker镜像构建

1.构建参数

FROM 指定源镜像
COPY 复制文件
MAINTAINER 指定作者信息,最新版docker已经用LABEL KEY="VALUE"代替
ADD 功能与copy相似,区别就是在添加压缩包时,add是解包后再添加进容器;而copy是直接添加压缩包不提供解包功能
ENV 变量,指定环境变量 eg: ENV FILENAME test
EXPOSE 暴露容器端口
VOLUME 申明数据卷,通常指数据挂载点
WORKDIR 进入容器时切换路径
RUN 在镜像构建过程运行指令存入镜像中
CMD 在启动容器后执行的一个命令,eg: echo $FILENAME 会调用shell解析,显示在当前终端
ENTRYPOINT 和CMD功能和用法类似,但动作不可被覆盖

2.参考示例及其用法

#基本框架

#FROM COPY 和LABEL用法
#构建镜像时文件都要在同一个目录
[root@docker-node1 ~]# mkdir docker
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# cp /root/anaconda-ks.cfg  .

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest			#指定使用的基础镜像
LABEL CREATEUSER=fjw		#指定作者信息    
COPY anaconda-ks.cfg /		#复制当前目录文件到容器指定位置

#开始构建
[root@docker-node1 docker]# docker build -t fjw:v1 .

#查看镜像fjw:1的构建历史
[root@docker-node1 docker]# docker history fjw:v1
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
f6596bad8e55   12 seconds ago   COPY anaconda-ks.cfg / # buildkit   1.2kB     buildkit.dockerfile.v0
<missing>      12 seconds ago   LABEL CREATEUSER=fjw                0B        buildkit.dockerfile.v0
<missing>      2 years ago      BusyBox 1.36.1 (glibc), Debian 12   4.26MB

#验证
[root@docker-node1 docker]# docker run -it --name fjw fjw:v1
/ # ls
anaconda-ks.cfg  dev              home             lib64            root             tmp              var
bin              etc              lib              proc             sys              usr

#add与copy区别

[root@docker-node1 docker]# touch fjw1 fjw2 fjw3
[root@docker-node1 docker]# tar zcf fjw.tar.gz fjw1 fjw2 fjw3
 
#add用法
[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
ADD fjw.tar.gz /

[root@docker-node1 docker]# docker build -t fjw:v2 .

#copy用法
[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /

[root@docker-node1 docker]# docker build -t fjw:v3 .

验证

image-20250807010019602

image-20250807010359049

#ENV

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw

[root@docker-node1 docker]# docker build -t fjw:v4 .

验证

image-20250807010938314

#EXPOSE

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw
EXPOSE 80		#暴露的端口,构建的容器需要运行业务就需要暴露端口

[root@docker-node1 docker]# docker build -t fjw:v5 .

验证

image-20250807011346589

#WORKDIR

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw
EXPOSE 80
WORKDIR /etc	#运行容器后直接在/etc目录中

[root@docker-node1 docker]# docker build -t fjw:v6 .

验证

image-20250807011630149

#RUN

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw
EXPOSE 80
WORKDIR /etc
RUN touch haha1 haha2 haha3	   #运行容器时在工作目录中创建文件

[root@docker-node1 docker]# docker build -t fjw:v7 .

验证

image-20250807011902772

#CMD

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw
EXPOSE 80
WORKDIR /etc
RUN touch haha1 haha2 haha3
CMD echo $name

[root@docker-node1 docker]# docker build -t fjw:v8 .

验证

image-20250807012541188

#ENTRYPOINT

[root@docker-node1 docker]# vim dockerfile
FROM busybox:latest
LABEL CREATEUSER=fjw
COPY fjw.tar.gz /
ENV name=fjw
EXPOSE 80
WORKDIR /etc
RUN touch haha1 haha2 haha3
ENTRYPOINT echo $name		#与CMD类似但是不能被覆盖

[root@docker-node1 docker]# docker build -t fjw:v9 .

验证

image-20250807013022850

3.镜像构建实例

前提:使用centos镜像构建一个aliyun的镜像仓库,centos源镜像不能安装软件

#构建一个安装nginx的webserver镜像

1.建立构建目录,编写构建文件

[root@docker-node1 ~]# mkdir docker
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# cp /mnt/nginx-1.26.1.tar.gz .
[root@docker-node1 docker]# vim dockerfile
FROM centos.repo:latest
ADD nginx-1.26.1.tar.gz /mnt
RUN yum install gcc make pcre-devel openssl-devel -y
WORKDIR /mnt/nginx-1.26.1
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc		#注释掉调试模式的编译参数,减少最终镜像体积
RUN ./configure --with-http_ssl_module --with-http_stub_status_module
RUN make && make install
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]						#将 Nginx 的网页根目录设为数据卷,方便外部挂载自定义页面
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]		#启动 Nginx 并以非后台模式运行(确保容器不退出)

2.通过dockerfile构建文件生成镜像

[root@docker-node1 docker]# docker build -t webserver:v1 .

3.测试镜像可用性

[root@docker-node1 docker]# docker run -d --name nginx -p 88:80 webserver:v1

测试,访问端口映射的88端口

image-20250807015619410

4.查看容器详情

[root@docker-node1 docker]# docker inspect nginx

4.镜像优化方案

1.缩减镜像层

[root@docker-node1 docker]# vim Dockerfile
FROM centos.repo:latest
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install gcc make pcre-devel openssl-devel -y && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module &&  make && make install
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

[root@docker-node1 docker]# docker build -t webserver:v2 .

2.多阶段构建

[root@docker-node1 docker]# vim Dockerfile
FROM centos.repo:latest as built
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install gcc make pcre-devel openssl-devel -y && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module &&  make && make install && cd .. && rm -rf nginx-1.26.1 && yum clean all

FROM centos.repo:latest
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@docker-node1 docker]# docker build -t webserver:v3 .

3.使用最精简镜像

[root@docker-node1 docker]# vim Dockerfile
FROM nginx:1.23 AS base
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

FROM gcr.io/distroless/base-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]

五 搭建docker私有仓库

什么是docker仓库

在搭建docker私有仓库之前,先了解什么是docker的仓库?

Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。

它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。

Docker 仓库可以分为公共仓库和私有仓库:

  • 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。
    • 例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
  • 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。
    • 比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中,以保证安全性和控制访问权限。

通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。

docker仓库的工作原理

image-20251010162212117

仓库中的三个角色

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

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

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

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的请求传递镜像到客户端

push原理

镜像上传的步骤:

1.client向index发送上传请求并完成用户认证

2.index会发方token给client来证明client的合法性

3.client携带index提供的token连接Registry

4.Registry向index合适token的合法性

5.index证实token的合法性

6.Registry开始接收客户端上传过来的镜像

docker hub

官网:https://hub.docker.com/

image-20251010162119281

Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。

它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。

以下是 Docker Hub 的一些关键特点和优势:

  1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、Web 服务器等众多应用的镜像。
    • 例如,您可以轻松找到 Ubuntu、CentOS 等操作系统的镜像,以及 MySQL、Redis 等数据库的镜像。
  2. 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。
  3. 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。
  4. 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。
  5. 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。

搭建简单的registry仓库

为什么搭建私有仓库?

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

  • 需要internet连接,速度慢
  • 所有人都可以访问
  • 由于安全原因企业不允许将镜像放到外网

好消息是docker公司已经将registry开源,我们可以快速构建企业私有仓库

地址: https://docs.docker.com/registry/deploying/

1.下载regisrty镜像

#从公共仓库下载,需要挂梯子
[root@docker-node1 docker]# docker pull registry
#从本地镜像包导入
[root@docker-node1 docker]# docker load -i /mnt/packages/registry.tag.gz

2.运行registry

#--restart=always 在docker开启时同时运行registry这个容器
[root@docker-node1 docker]# docker run -d -p 5000:5000 --restart=always --name repo registry:latest

[root@docker-node1 docker]# docker ps -a
CONTAINER ID   IMAGE                COMMAND                  CREATED             STATUS                      PORTS                                         NAMES
e8003291c44e   registry:latest      "/entrypoint.sh /etc…"   11 minutes ago      Up 7 minutes                0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp   repo

3.上传镜像到仓库中

#给上传的镜像打上标签
[root@docker-node1 docker]# docker tag busybox:latest 172.25.254.10:5000/busybox:latest


#docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@docker-node1 docker]# docker push 172.25.254.10:5000/busybox:latest
The push refers to repository [172.25.254.10:5000/busybox]
Get "https://172.25.254.10:5000/v2/": http: server gave HTTP response to HTTPS client

#配置非加密端口
[root@docker-node1 docker]# vim /etc/docker/daemon.json

[root@docker-node1 docker]# cat /etc/docker/daemon.json
{
    "insecure-registries" : ["http://172.25.254.10:5000"]
}

[root@docker-node1 docker]# systemctl restart docker

[root@docker-node1 docker]# docker push 172.25.254.10:5000/busybox:latest
The push refers to repository [172.25.254.10:5000/busybox]
d51af96cf93e: Pushed
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527

#查看镜像上传
[root@docker-node1 docker]# curl 172.25.254.10:5000/v2/_catalog
{"repositories":["busybox"]}

搭建加密仓库

#生成公钥与证书
[root@docker-node1 docker]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout /data/certs/fy.org.key \
> -addext "subjectAltName = DNS:reg.fy.org" \		#使用域名作为仓库名称
> -x509 -days 365 -out /data/certs/fy.org.crt
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:GD
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:fy.org
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.fy.org	  #要与-addext的域名相同,否则docker验证过不去	
Email Address []:11

#启动存放镜像的仓库容器
[root@docker-node1 docker]# docker run -d -p 443:443 --restart=always --name repo \
> -v /opt/registry:/var/lib/registry \		#将主机的 /opt/registry 目录挂载到容器内的仓库数据目录(存储镜像数据),实现数据持久化
> -v /data/certs:/certs \
> -e  REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fy.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/fy.org.key registry

#查看运行情况
[root@docker-node1 docker]# docker ps -a
CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS                      PORTS                                               NAMES
e00abc56cc13   registry             "/entrypoint.sh /etc…"   9 seconds ago   Up 8 seconds                0.0.0.0:443->443/tcp, [::]:443->443/tcp, 5000/tcp   repo

#如果有问题就查看容器日志
[root@docker-node1 docker]# docker logs repo
#此时如果不生成证书目录,直接推送或拉取镜像会报错
[root@docker-node1 docker]# docker tag busybox:latest reg.fy.org/busybox:latest
[root@docker-node1 docker]# docker push reg.fy.org/busybox:latest
Error response from daemon: Get "https://reg.timinglee.org/v2/": tls: failed to
verify certificate: x509: certificate signed by unknown authority


#服务端作为客户端使用时,直接在本机拷贝就行
[root@docker-node1 docker]# mkdir /etc/docker/certs.d/reg.fy.org/ -p
[root@docker-node1 docker]# cp /data/certs/fy.org.crt /etc/docker/certs.d/reg.fy.org/ca.crt
[root@docker-node1 docker]# systemctl restart docker		#重启docker读取生效

[root@docker-node1 docker]# docker tag busybox:latest reg.fy.org/busybox:latest
[root@docker-node1 docker]# docker push reg.fy.org/busybox:latest

[root@docker-node1 docker]# curl -k https://reg.fy.org/v2/_catalog
{"repositories":["busybox"]}

[root@docker-node1 docker]# cat /etc/hosts
......
172.25.254.10  reg.fy.org

#使用另一个客户端测试

#先添加镜像仓库的本地域名解析
[root@docker-node2 docker]# cat /etc/hosts
......
172.25.254.10  reg.fy.org

#为客户端建立证书
[root@docker-node1 reg.fy.org]# scp -r /etc/docker/certs.d/ root@172.25.254.20:/etc/docker/

#查看镜像仓库里的镜像
[root@docker-node2 ~]# curl -k https://reg.fy.org/v2/_catalog
{"repositories":["busybox","nginx"]}

#拉取镜像到本地
[root@docker-node2 ~]# docker pull reg.fy.org/busybox	#不加版本默认是latest
[root@docker-node2 ~]# docker pull reg.fy.org/nginx
[root@docker-node2 ~]# docker imges
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
reg.fy.org/nginx     latest    5ef79149e0ec   11 months ago   188MB
reg.fy.org/busybox   latest    65ad0d468eb1   2 years ago     4.26MB

仓库建登录认证

1.安装建立认证文件的工具包与创建认证用户

#安装工具包
[root@docker-node1 ~]# dnf install httpd-tools -y

#建立认证文件并创建用户
[root@docker-node1 ~]# mkdir /data/auth
[root@docker-node1 ~]# htpasswd -Bc /data/auth/htpasswd admin	#-B 强制使用最安全加密方式
New password:
Re-type new password:
Adding password for user admin
[root@docker-node1 ~]# htpasswd -B /data/auth/htpasswd fjw		#创建第二个用户时不用+c,不然会覆盖
New password:
Re-type new password:
Adding password for user fjw

[root@docker-node1 ~]# cat /data/auth/htpasswd
admin:$2y$05$lwl8H1OPdMW2k54k0jPSi.BQnbj9JlbNFX7KH45HwMqbKsq5KJsha
fjw:$2y$05$BTfy0UcXi5oszxiH8VZxmug2/PTq7LIb5m.DnOlX.lztW8irYmTly

2.运行仓库容器,并添加认证到仓库容器中


[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
> --name registry -v /opt/registry:/var/lib/registry \
> -v /data/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fy.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/fy.org.key \
> -v /data/auth:/auth \
> -e "REGISTRY_AUTH=htpasswd" \
> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
> registry

[root@docker-node1 ~]# docker ps -a
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS                          PORTS     NAMES
9e4fb308ed91   registry   "/entrypoint.sh /etc…"   44 seconds ago   Restarting (1) 14 seconds ago             repo

3.访问测试

#不加认证时,会禁止访问
[root@docker-node2 ~]# curl -k https://reg.fy.org/v2/_catalog
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}

#-u添加认证用户与密码
[root@docker-node2 ~]# curl -k https://reg.fy.org/v2/_catalog -uadmin:fjw
{"repositories":["busybox","nginx"]}		#做了容器挂载持久化

4.登录测试

#没有登录镜像仓库时直接拉取镜像
[root@docker-node2 ~]# docker pull reg.fy.org/nginx
Using default tag: latest
Error response from daemon: Head "https://reg.fy.org/v2/nginx/manifests/latest": no basic auth credentials

#使用认证用户登录镜像仓库
[root@docker-node2 ~]# docker login -uadmin -pfjw reg.fy.org
Login Succeeded

#登陆后拉取镜像到本地
[root@docker-node2 ~]# docker pull reg.fy.org/nginx
Using default tag: latest
latest: Pulling from nginx
Digest: sha256:127262f8c4c716652d0e7863bba3b8c45bc9214a57d13786c854272102f7c945
Status: Image is up to date for reg.fy.org/nginx:latest
reg.fy.org/nginx:latest
[root@docker-node2 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
reg.fy.org/nginx     latest    5ef79149e0ec   11 months ago   188MB

拓展

#查看认证信息
#在哪个用户登录就在哪个用户的家目录里的隐藏文件
[root@docker-node2 ~]# ls -a
[root@docker-node2 ~]# cd .docker/
[root@docker-node2 .docker]# cat config.json
{
        "auths": {
                "reg.fy.org": {
                        "auth": "YWRtaW46Zmp3"
                }
        }

#退出镜像仓库,查看认证信息
[root@docker-node2 .docker]# docker logout reg.fy.org
Removing login credentials for reg.fy.org
[root@docker-node2 .docker]# cat config.json
{
        "auths": {}
}

#补充
[root@docker-node2 ~]# vim /etc/docker/daemon.json
{
    "registry-mirrors": {"https://reg.fy.org"}
}

[root@docker-node2 ~]# systemctl restart docker
[root@docker-node2 ~]# docker info
......
 Registry Mirrors:
  https://reg.fy.org/
......

搭建企业级私有仓库

1.部署harbor

[root@docker-node1 ~]# tar zxf harbor-offline-installer-v2.5.4.tgz 
[root@docker-node1 ~]# cd harbor/

#拷贝模板,生成harbor配置文件
[root@docker-node1 harbor]# cp harbor.yml.tmpl harbor.yml
#编辑配置文件
[root@docker-node1 harbor]# vim harbor.yml

image-20250809005945587

#安装habor
[root@docker-node1 harbor]# ./install.sh --help
--with-notary			#扫描容器镜像,对容器镜像进行签名,确保来源可靠
--with-trivy 			#对仓库镜像进行扫描,及时发现漏洞,确保容器应用安全
--with-chartmuseum 		#存储和共享Helm Charts的服务器,助于管理k8s应用
[root@docker-node1 harbor]# ./install.sh --with-chartmuseum

#管理harbor的容器

[root@docker-node1 harbor]#	docker compose stop		#停止harbor的容器
[root@docker-node1 harbor]# docker compose start	#开启harbor的容器
[root@docker-node1 harbor]# docker compose up -d 	#部署/重建并启动

#查看导入的镜像与开启的容器

[root@docker-node1 harbor]# docker images
[root@docker-node1 harbor]# docker ps

补充

#由于docker版本更新,habor安装时会出现版本报错

image-20250809011643080

#解决方法

[root@docker-node1 harbor]#	docker compose stop	
[root@docker-node1 harbor]# vim docker-compose.yml
#version: '2.3'
[root@docker-node1 harbor]# docker compose start

2.管理仓库

1.登录,访问habor主机默认被端口映射到80

image-20250809012507685

2.建立仓库项目

#不建立的话默认上传的镜像会存放在library中

image-20250809012738148

3.上传镜像

#登录镜像仓库
[root@docker-node1 harbor]# docker login -uadmin -pfjw reg.fy.org

#上传与标签格式:仓库名称/目录/镜像名称
[root@docker-node1 harbor]# docker tag nginx:latest reg.fy.org/fjwyyy/nginx:latest
[root@docker-node1 harbor]# docker push reg.fy.org/fjwyyy/nginx:latest

#查看上传的镜像

image-20250809014243551

4.使用客户端进行拉取仓库镜像到本地

#要有本地解析,还要有证书
#登录仓库
[root@docker-node2 ~]# docker login -uadmin reg.fy.org
Password:
Login Succeeded

#拉取镜像到本地
#格式为目录/镜像名称 默认版本为latest不指定的话
[root@docker-node2 ~]# docker pull fjwyyy/nginx

#上传到默认library目录的镜像,在拉取时可以不指定目录
[root@docker-node2 ~]# docker pull busybox

跳转到下文

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐