云原生容器化-4 Docker仓库

1.Docker仓库

1.1 Docker Hub

docker仓库用于存放docker镜像,可以分为公用和私有两种。Docker Hub是全球公用的仓库,因服务器在国外,国内基本不可以;一般需要配置阿里、腾讯等加速器。公司内部而言,可以搭建私有的Docker仓库(如Harbor)。

说明 :使用Docker Hub下载镜像时,不需要登录;但是推送、删除、修改时需要登录。

登录与注销涉及如下命令:

shell 复制代码
#登录时携带用户名、密码、仓库地址信息
docker login --username test --password test@123 192.168.0.22:8000
docker login --username seong --password 3er4#ER$ 192.168.0.22:8000
#注销时需要仓库信息
docker logout 192.168.0.22:8000

注册成功后,在/root/.docker/config.json文件中记录仓库登录成功信息:

json 复制代码
{
        "auths": {
                "192.168.0.22:8000": {
                        "auth": "c2Vvbmc6M2VyNCNFUiQ="
                }
        }
}

注销命令执行时,将删除文件中对应信息(可以重复注销)。

1.2 常见的本地仓库:Registory和Harbor

Docker提供了registry镜像,可以较为方便地搭建仓库。Harbor提供了对用户更为友好的UI界面,推荐使用Harbor。需要注意: Harbor通过docker-compose管理,因此安装Harbor是需要先安装/docker-compose,详细的安装流程请参考服务器环境搭建-2 Docker与Harbor

1.3 配置docker仓库

docker的配置文件路径为/etc/docker/daemon.json,可以通过registry-mirrors属性添加docker仓库。改动配置文件后,需要重启docker(执行service docker restart)生效。如可以配置腾讯的docker仓库镜像:

json 复制代码
{
    "registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
}

默认情况下,docker使用https协议与仓库通信。将上述搭建的Harbor仓库配置为docker的仓库地址时会报错: http: server gave HTTP response to HTTPS client.

可以通过在insecure-registries属性中添加白名单地址来规避。如Harbor仓库的地址为:"http://192.168.0.22:8000", 可以配置为:

json 复制代码
{
    "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],       
    "insecure-registries": ["192.168.0.22:8000"]    
} 

除了在daemon.json配置文件中修改外,还可以再docker的service文件(/usr/lib/systemd/system/docker.service)中进行配置:

复制代码
[Service]
Type=notify
ExecStart=/usr/bin/dockerd --insecure-registry=192.168.0.22:8000  -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always

ExecStart表示进程启动命令,通过--insecure-registry参数设置允许通过http访问的仓库地址。

说明:修改docker.service文件后,需要执行systemctl daemon-reload使得配置文件生效;然后执行service docker restart使用新的service文件重启docker.

2. Docker Registry v2 API介绍和案例分析

Docker Registry v2 API是Docker引擎与Docker Registry进行交互时的接口规范。Docker引擎进行镜像的下拉、删除、推送和修改时需要调用Docker Registry提供的接口。

Docker对容器和镜像进行了分层设计,API也以分层为基础。Docker镜像数据包括:数据(blob)和元数据(manifest)两个部分,前者是实际的二进制数据,后者是镜像的描述数据,V2 API为这两部分分别提供了接口。

本文介绍推送和下拉镜像相关的API,其他API请参考: Distribution Registry / Reference Overview / HTTP API V2

2.1 API接口版本协商

2.1.1 API接口版本协商

url : GET /v2/
参数 :无
响应: 返回200 OK表示请求成功; 返回401未经授权.

2.1.2 案例:

http 复制代码
GET /v2/ HTTP/1.1
Host: 192.168.0.22:8000
User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\))
Accept-Encoding: gzip
Connection: close

HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
X-Content-Type-Options: nosniff
Date: Mon, 05 Feb 2024 01:48:16 GMT
Connection: close

{}

说明:Docker引擎与仓库交互前,会使用该接口进行协议确认。收到 200 OK表示仓库支持V2版本API,即Docker引擎可继续使用V2 API与仓库交互。

2.2 推送镜像

2.2.1 推送镜像的 manifests

url : PUT /v2/<name>/manifests/<reference>
参数 :

1\] `name`: 镜像名称 \[2\] `reference`: 标签/摘要 **响应**: 返回 201 Created表示已成功推送。 #### 2.2.2 推送镜像的 blobs **url** : PUT /v2//blobs/uploads/?digest= **参数** : \[1\] `name`: 镜像仓库名称 \[2\] uuid: 唯一ID标识 \[3\] digest: blob 的摘要 **响应**: 返回 201Created表示已成功推送。 #### 2.2.3 案例: 执行如下命令将从Docker Hub仓库下载的hello-world镜像,上传到本地仓库192.168.0.22:8000上: ```Python docker pull hello-world docker tag hello-world 192.168.0.22:8000/hello-world docker push 192.168.0.22:8000/hello-world ``` 在本地通过docker history命令可以看出hello-world包含两个镜像层, 其中一层镜像ID为d2c94e258dcb: ```shell [root@VM-4-6-centos ~]# docker history hello-world IMAGE CREATED CREATED BY SIZE COMMENT d2c94e258dcb 9 months ago CMD ["/hello"] 0B buildkit.dockerfile.v0 9 months ago COPY hello / # buildkit 13.3kB buildkit.dockerfile.v0 ``` 同时在环境上抓包,如下所示: ![在这里插入图片描述](https://file.jishuzhan.net/article/1757542345626095617/6fbabb01e4809e6f545aa9f63f299869.webp) 整个流程可以分为两个部分:上传各个镜像层的blobs数据和上传整个镜像的manifests数据; **\[1\] 上传各个镜像层的blobs数据** 由于hello-world包含两个镜像层c1ec31e和d2c94e,因此分别进行镜像层数据的推送。在每次推送过程会经过校验和传输两个阶段: (1)通过HEAD请求携带镜像的ID信息查询镜像层在仓库是否存在,收到200表示已存在,不需要上传,收到404表示不存在,(2)上传镜像层数据。 上传完成后,还会再次通过HEAD请求校验是否上传完成。 **\[2\] 上传整个镜像的manifests数据** 上述上传hello-world:latest镜像元数据的抓包信息如下: ```http PUT /v2/hello-world/manifests/latest HTTP/1.1 Host: 192.168.0.22:8000 User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\)) Content-Length: 524 Content-Type: application/vnd.docker.distribution.manifest.v2+json Accept-Encoding: gzip Connection: close { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 581, "digest": "sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 2459, "digest": "sha256:c1ec31eb59444d78df06a974d155e597c894ab4cda84f08294145e845394988e" } ] }HTTP/1.1 201 Created Docker-Content-Digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 Docker-Distribution-Api-Version: registry/2.0 Location: http://192.168.0.22:8000/v2/hello-world/manifests/sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 X-Content-Type-Options: nosniff Date: Mon, 05 Feb 2024 01:48:16 GMT Content-Length: 0 Connection: close ``` 进一步测试将hello-world打包成beta版本,然后推送到本地192.168.0.22:8000仓库: docker tag hello-world 192.168.0.22:8000/hello-world:beta2 docker push 192.168.0.22:8000/hello-world:beta2 同时在环境上抓包: ![在这里插入图片描述](https://file.jishuzhan.net/article/1757542345626095617/516cad89845a9b75949ce2b1ac420666.webp) 通过HEAD请求携带镜像的ID信息查询镜像层在仓库是否存在,收到200表示已存在,不需要上传镜像层数据,只需上传镜像的manifests即可。 由此也可以看出,Docker仓库将镜像层与镜像的元数据是分开存储的。镜像层可以被不同的镜像重复使用。 ### 2.3 拉取镜像 #### 2.3.1 获取镜像的manifests(元数据) **url** : `GET /v2//manifests/` **参数** : \[1\] `name`: 镜像名称 \[2\] `reference`: 标签/摘要 **响应**: 包含manifest信息的JSON 对象。 #### 2.3.2 获取镜像的blobs(二进制数据) **url** : `GET /v2//blobs/` **参数** : \[1\] `name`: 镜像名称 \[2\] `digest`: blob 的摘要 **响应**: 返回镜像的 二进制数据 #### 2.3.3 案例 将本地的hello-world:latest镜像删除,然后执行 docker pull 192.168.0.22:8000/hello-world从仓库拉重新拉取hello-world:latest镜像时,具体执行过程如下: \[1\] 通过HEAD请求获取hello-world:latest版本镜像的摘要sha256,如果返回404表示镜像不存在 ```http HEAD /v2/hello-world/manifests/latest HTTP/1.1 Host: 192.168.0.22:8000 User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\)) Accept: application/vnd.oci.image.manifest.v1+json Accept: application/vnd.docker.distribution.manifest.v2+json Accept: application/vnd.docker.distribution.manifest.list.v2+json Accept: application/vnd.oci.image.index.v1+json Accept: application/vnd.docker.distribution.manifest.v1+prettyjws Accept: application/json Connection: close HTTP/1.1 200 OK Content-Length: 524 Content-Type: application/vnd.docker.distribution.manifest.v2+json Docker-Content-Digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 Docker-Distribution-Api-Version: registry/2.0 Etag: "sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7" X-Content-Type-Options: nosniff Date: Mon, 05 Feb 2024 03:43:16 GMT Connection: close ``` \[2\] 得到sha256信息为d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7, 然后将得到的摘要作为参数调用GET方法获取镜像的元数据: ```http GET /v2/hello-world/manifests/sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 HTTP/1.1 Host: 192.168.0.22:8000 User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\)) Accept: application/json Accept: application/vnd.oci.image.manifest.v1+json Accept: application/vnd.docker.distribution.manifest.v2+json Accept: application/vnd.docker.distribution.manifest.list.v2+json Accept: application/vnd.oci.image.index.v1+json Accept: application/vnd.docker.distribution.manifest.v1+prettyjws Accept-Encoding: gzip Connection: close HTTP/1.1 200 OK Content-Length: 524 Content-Type: application/vnd.docker.distribution.manifest.v2+json Docker-Content-Digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 Docker-Distribution-Api-Version: registry/2.0 Etag: "sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7" X-Content-Type-Options: nosniff Date: Mon, 05 Feb 2024 03:43:16 GMT Connection: close { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 581, "digest": "sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 2459, "digest": "sha256:c1ec31eb59444d78df06a974d155e597c894ab4cda84f08294145e845394988e" } ] } ``` \[3\] 从镜像的 manifests信息得知: hello-world:latest镜像由上下(d2c94e258dcb...)和(c1ec31eb5944...)两层组成。 Docker引擎判断本地是否有对应的镜像层,如果没有,会依次向仓库发送/v2//blobs/请求获取镜像层数据。此时本地环境不存在这两个镜像层,因此分别发送了两次请求: 请求c1ec31eb5944层镜像: ```http GET /v2/hello-world/blobs/sha256:c1ec31eb59444d78df06a974d155e597c894ab4cda84f08294145e845394988e HTTP/1.1 Host: 192.168.0.22:8000 User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\)) Accept-Encoding: gzip Connection: close .....数据.... ``` 请求d2c94e258dcb层镜像: ```http GET /v2/hello-world/blobs/sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a HTTP/1.1 Host: 192.168.0.22:8000 User-Agent: docker/24.0.4 go/go1.20.5 git-commit/4ffc614 kernel/3.10.0-1160.92.1.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/24.0.4 \(linux\)) Accept-Encoding: gzip Connection: close .....数据.... ``` 上述流程的抓包信息如下: ![在这里插入图片描述](https://file.jishuzhan.net/article/1757542345626095617/aa2abe01290a5bcc5d533bc3f464d693.webp) 此时,再次执行docker pull 192.168.0.22:8000/hello-world指令,抓包信息如下: ![在这里插入图片描述](https://file.jishuzhan.net/article/1757542345626095617/f3627b9c953a0d1ac0fee7ec880d19a6.webp) 此时Docker引擎判断本地已有对应的镜像,无需再从仓库下载。 ## 3.总结 Docker仓库的搭建、配置、使用较为简单,上手操作就能掌握,重点在于理解分层的概念。从上述镜像的推送和拉取过程可以看出,Docker容器的镜像以层为颗粒度,从而减少了不必要的数据存储和传输。后续在介绍Docker容器中也会提到分层的概念,说明分层对降低计算机资源占用率的重要意义。

相关推荐
小叶子来了啊2 分钟前
信息系统运行管理员:临阵磨枪版
运维·服务器·数据库
-天涯7611 分钟前
5.13/14 linux安装centos及一些操作命令随记
linux·运维·服务器
慧一居士11 分钟前
Kubernetes 中kind类型和各类型详细配置完整示例介绍
云原生·kubernetes·yaml配置
佩奇的技术笔记33 分钟前
CentOS系统中升级Python 3.12.2版本
linux·运维·服务器
北漂老男孩42 分钟前
主流数据库运维故障排查卡片式速查表与视觉图谱
运维·数据库
薯条不要番茄酱1 小时前
【SpringBoot】从零开始全面解析SpringMVC (二)
java·spring boot·后端
小林学习编程1 小时前
Springboot考研信息平台
spring boot·后端·考研
云手机管家2 小时前
CDN加速对云手机延迟的影响
运维·服务器·网络·容器·智能手机·矩阵·自动化
云手机管家2 小时前
账号风控突破:云手机设备指纹篡改检测与反制技术解析
android·运维·网络协议·网络安全·智能手机·矩阵·自动化
孤的心了不冷2 小时前
【Docker】CentOS 8.2 安装Docker教程
linux·运维·docker·容器·eureka·centos