8. 登陆(skopeo login)
我这里有三个仓库地址
- Docker 官方 hub 仓库:
docker.io
- Harbor 私有仓库:
harbor.fumai.com
- Registry 私有仓库:192.168.10.80:5000
在使用 skopeo 前,如果 src 或 dest 镜像是在 registry 仓库中的并且配置了非 public 的镜像需要相应的 auth 认证, 此时我们可以使用 docker login 或者 skopeo login 的方式登录到 registry 仓库,然后默认会在~/.docker目录下生成 registry 登录配置文件 config.json ,该文件里保存了登录需要的验证信息,skopeo 拿到该验证信息才有权限往 registry push 镜像。
skopeo 使用来自 --creds(对于 skopeo inspect|delete)或 --src-creds|--dest-creds(对于 skopeo copy)标志的凭据,如果已设置;否则它使用由 skopeo 登录、podman 登录、buildah 登录或 docker 登录设置的配置。
8.1 配置私有仓库证书
由于我是使用 podman
容器工具,它的默认仓库认证证书存放位置是/etc/containers/certs.d
。
- 配置
registry
证书registry
仓库部署在我的本机容器中,证书挂载于本机/opt/registry/certs/
目录。
install -d /etc/containers/certs.d/192.168.10.80\:5000/ install /opt/registry/certs/* /etc/containers/certs.d/192.168.10.80\:5000/
install
是一个既能创建目录又能复制的命令。
2. 配置 harbor 证书
harbor
仓库在另一台机器
$ cat <<EOF >> vim /etc/hosts 192.168.10.81 harbor.fumai.com EOF
install -d /etc/containers/certs.d/harbor.fumai.com rsync root@192.168.10.81:/etc/docker/certs.d/harbor.fumai.com/* /etc/containers/certs.d/harbor.fumai.com/
8.2 podman 登陆各个仓库
登陆 docker.io
仓库
$ podman login -u ghostwritten docker.io Password: Login Succeeded!
登陆 registry 仓库
$ podman login -u registryuser -p registryuserpassword 192.168.10.80:5000 Login Succeeded!
登陆 harbor
仓库
$ podman login harbor.fumai.com -u admin -p Harbor12345 Login Succeeded!
Podman
登陆仓库生成的auth
文件在这里
$ cat /run/user/0/containers/auth.json { "auths": { "192.168.10.80:5000": { "auth": "cmVnaXN0cnl1c2VyOnJlZ2lzdHJ5dXNlcnBhc3N3b3Jk" }, "docker.io": { "auth": "Z2hvc3R3cml0dGVuOjEyMzQ1bXRyLg==" }, "harbor.fumai.com": { "auth": "YWRtaW46SGFyYm9yMTIzNDU=" } } }
skopeo
登陆 registry
仓库
8.3 skopeo 多种方式登陆仓库
skopeo login -u ghostwritten docker.io Password: Login Succeeded! $ skopeo login -u registryuser -p registryuserpassword 192.168.10.80:5000 Login Succeeded! $ skopeo login --cert-dir /etc/containers/certs.d/192.168.10.80\:5000 -u registryuser -p registryuserpassword 192.1 68.10.80:5000 Login Succeeded! $ skopeo login --authfile /run/user/0/containers/auth.json harbor.fumai.com $ echo 'Harbor12345' | skopeo login -u admin --password-stdin harbor.fumai.com Login Succeeded!
9. 复制镜像(skopeo copy)
skopeo copy 可以在各种存储机制之间复制容器镜像,包括:
Container registries
The Quay, Docker Hub, OpenShift, GCR, Artifactory …
Container Storage backends
github.com/containers/storage (Backend for Podman, CRI-O, Buildah and friends)
Docker daemon storage
Local directories
Local OCI-layout directories
9.1 本地镜像推送仓库
将本地镜像拷贝至192.168.10.80:5000
仓库
$ docker images localhost/busybox:latest REPOSITORY TAG IMAGE ID CREATED SIZE busybox latest 9d5226e6ce3f 4 days ago 1.24MB 如果你得容器以podman为引擎。 $ skopeo copy containers-storage:localhost/busybox:latest docker://192.168.10.80:5000/busybox:latest INFO[0000] Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled Getting image source signatures Copying blob 40cf597a9181 [--------------------------------------] 0.0b / 0.0b Copying config 9d5226e6ce [======================================] 1.4KiB / 1.4KiB Writing manifest to image destination Storing signatures #如果你得容器以docker为引擎。 $ skopeo copy docker-daemon:localhost/busybox:latest docker://192.168.10.80:5000/busybox:latest # 没有tls安全的registry的情况下这样操作。 $ skopeo copy --insecure-policy --dest-tls-verify=false --dest-authfile /root/.docker/config.json docker-daemon:localhost/busybox:latest docker://192.168.10.80:5000/busybox:latest
9.2 两仓库进行复制
192.168.10.80:5000
仓库的 alpine
镜像同步至 harbor.fumai.com
仓库
#两个仓库进行查询当前镜像内容 $ curl -k -u "registryuser:registryuserpassword" https://192.168.10.80:5000/v2/_catalog {"repositories":["alpine"]} $ curl -k -u "admin:Harbor12345" https://harbor.fumai.com/v2/_catalog {"repositories":[]} #镜像开始复制 $ skopeo copy docker://192.168.10.80:5000/alpine:latest docker://harbor.fumai.com/library/alpine:latest Getting image source signatures Copying blob 60f8044dac9f done Copying config bfe296a525 done Writing manifest to image destination Storing signatures #查询复制结果 $ curl -k -u "admin:Harbor12345" https://harbor.fumai.com/v2/_catalog {"repositories":["library/alpine"]} #查询镜像信息 $ skopeo inspect docker://harbor.fumai.com/library/alpine:latest { "Name": "harbor.fumai.com/library/alpine", "Digest": "sha256:39ec5d12ef5a81b29b26d756f6b9c11d8d454fc4158e3dac1e13240125558461", "RepoTags": [ "latest" ], "Created": "2022-11-12T04:19:23.199716539Z", "DockerVersion": "20.10.12", "Labels": null, "Architecture": "amd64", "Os": "linux", "Layers": [ "sha256:60f8044dac9f779802600470f375c7ca7a8f7ad50e05b0ceb9e3b336fa5e7ad3" ], "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] }
其它仓库同步方法:
# docker://quay.io的buildah 同步到docker://registry.internal.company.com $ skopeo copy docker://quay.io/buildah/stable docker://harbor.fumai.com/library/buildah #如果 registry 是一个没有tls验证的仓库并且以 docker 为容器引擎。 $ skopeo copy --insecure-policy --dest-tls-verify=false --dest-authfile /root/.docker/config.json docker://192.168.10.80:5000/alpine:latest docker://harbor.fumai.com/library/alpine:latest #如果 registry 是一个没有tls验证的仓库并且以 podman 为容器引擎。 $ skopeo copy --insecure-policy --dest-tls-verify=false --dest-authfile /run/user/0/containers/auth.json docker://192.168.10.80:5000/alpine:latest docker://harbor.fumai.com/library/alpine:latest
9.3 仓库镜像拷贝到本地目录
创建images
目录,从harbor.fumai.com
仓库复制至images
目录
$ install -d images $ skopeo copy docker://harbor.fumai.com/library/alpine:latest dir:images Getting image source signatures Copying blob 60f8044dac9f done Copying config bfe296a525 done Writing manifest to image destination Storing signatures $ ll images total 2864 -rw-r--r-- 1 root root 2918987 Nov 21 23:08 60f8044dac9f779802600470f375c7ca7a8f7ad50e05b0ceb9e3b336fa5e7ad3 -rw-r--r-- 1 root root 1471 Nov 21 23:08 bfe296a525011f7eb76075d688c681ca4feaad5afe3b142b36e30f1a171dc99a -rw-r--r-- 1 root root 428 Nov 21 23:08 manifest.json -rw-r--r-- 1 root root 33 Nov 21 23:08 version
保存OCI
格式
$ install -d images_OCI skopeo copy docker://harbor.fumai.com/library/alpine:latest oci:images_OCI $ tree images_OCI/ images_OCI/ ├── blobs │ └── sha256 │ ├── 096fca2180271e60f199e3bc1c3544dc0175e7e6abd9dbdd0e2058b17d96e8b7 │ ├── 60f8044dac9f779802600470f375c7ca7a8f7ad50e05b0ceb9e3b336fa5e7ad3 │ └── e9daf8b695a6e3c0c566a2e25b328ba25afbdd52a80d28198b9fbf5058130f09 ├── index.json └── oci-layout 2 directories, 5 files
或者如果没有登陆条件可以这样执行:
$ skopeo copy --src-creds=admin:harbor12345 docker://harbor.fumai.com/library/alpine:latest oci:local_oci_image
10. 同步镜像(Skopeo sync)
Skopeo sync
可以在容器仓库和本地目录之间同步镜像,其功能类似于阿里云的 image-syncer 工具, 实际上其比 image-syncer
更强大、灵活性更强一些
$ skopeo sync --src docker --dest dir registry.example.com/busybox /media/usb
10.1 仓库镜像同步至本地
将仓库中所有 busybox
镜像版本同步到本地目录
查询当前harbor.fumai.com
仓库 busybox版本
skopeo list-tags docker://harbor.fumai.com/library/busybox { "Repository": "harbor.fumai.com/library/busybox", "Tags": [ "latest", "stable" ] }
将busybox
镜像所有版本同步至本地
$ skopeo sync --src docker --dest dir harbor.fumai.com/library/busybox images_busybox INFO[0000] Tag presence check imagename=harbor.fumai.com/library/busybox tagged=false INFO[0000] Getting tags image=harbor.fumai.com/library/busybox INFO[0000] Copying image ref 1/2 from="docker://harbor.fumai.com/library/busybox:latest" to="dir:/images_busybox/busybox:latest" Getting image source signatures Copying blob 405fecb6a2fa done Copying config 9d5226e6ce done Writing manifest to image destination Storing signatures INFO[0000] Copying image ref 2/2 from="docker://harbor.fumai.com/library/busybox:stable" to="dir:/images_busybox/busybox:stable" Getting image source signatures Copying blob 405fecb6a2fa done Copying config 9d5226e6ce done Writing manifest to image destination Storing signatures INFO[0001] Synced 2 images from 1 sources $ tree images_busybox /images_busybox ├── busybox:latest │ ├── 405fecb6a2fa4f29683f977e7e3b852bf6f8975a2aba647d234d2371894943da │ ├── 9d5226e6ce3fb6aee2822206a5ef85f38c303d2b37bfc894b419fca2c0501269 │ ├── manifest.json │ └── version └── busybox:stable ├── 405fecb6a2fa4f29683f977e7e3b852bf6f8975a2aba647d234d2371894943da ├── 9d5226e6ce3fb6aee2822206a5ef85f38c303d2b37bfc894b419fca2c0501269 ├── manifest.json └── version 2 directories, 8 files
其他方式:
skopeo sync --src-creds=admin:Harbor12345 --src docker --dest dir harbor.fumai.com/library/busybox /images_busybox skopeo sync --src-authfile=/run/user/0/containers/auth.json --src docker --dest dir harbor.fumai.com/library/busybox /images_busybox
10.2 本地同步至仓库镜像
这次颠倒过来,从本地目录/images_busybox
同步至registry:192.168.10.80:5000
仓库
skopeo 登陆
skopeo login -u registryuser -p registryuserpassword 192.168.10.80:5000
开始同步
$ skopeo sync --src dir --dest docker /images_busybox 192.168.10.80:5000 INFO[0000] Copying image ref 1/2 from="dir:/images_busybox/busybox:latest" to="docker://192.168.10.80:5000/busybox:latest" Getting image source signatures Copying blob 405fecb6a2fa done Copying config 9d5226e6ce done Writing manifest to image destination Storing signatures INFO[0001] Copying image ref 2/2 from="dir:/images_busybox/busybox:stable" to="docker://192.168.10.80:5000/busybox:stable" Getting image source signatures Copying blob 405fecb6a2fa [--------------------------------------] 0.0b / 0.0b Copying config 9d5226e6ce [======================================] 1.4KiB / 1.4KiB Writing manifest to image destination Storing signatures INFO[0001] Synced 2 images from 1 sources
查询结果
$ skopeo list-tags docker://192.168.10.80:5000/busybox { "Repository": "192.168.10.80:5000/busybox", "Tags": [ "latest", "stable" ] }
成功。
其他同步方式:
skopeo sync --dest-creds=registryuser:registryuserpassword --src dir --dest docker /images_busybox 192.168.10.80:5000 skopeo sync --src-authfile=/run/user/0/containers/auth.json --src dir --dest docker /images_busybox 192.168.10.80:5000 #如果 registry 是一个没有tls验证的仓库 skopeo sync --insecure-policy --dest-tls-verify=false --src dir --dest docker /images_busybox 192.168.10.80:5000
10.3 两仓库同步
将harbor( harbor.fumai.com)
仓库的busybox
所有版本同步至registry(192.168.10.80:5000)
仓库
skopeo sync --src docker --dest docker harbor.fumai.com/library/busybox 192.168.10.80:5000
其他方式:
skopeo sync --src-creds=admin:Harbor12345 --dest-creds=registryuser:registryuserpassword --src docker --dest docker harbor.fumai.com/library/busybox 192.168.10.80:5000 skopeo sync --dest-authfile=/run/user/0/containers/auth.json --src-authfile=/run/user/0/containers/auth.json --src docker --dest docker harbor.fumai.com/library/busybox 192.168.10.80:5000
10.4 以配置文件方式进行同步
准备一个需要同步的资源清单
$ cat skopeo-sync.yml 192.168.10.80:5000: images: busybox: [stable] redis: - "latest" - "7.0.5" credentials: username: registryuser password: registryuserpassword tls-verify: true cert-dir: /etc/containers/certs.d/192.168.10.80:5000 docker.io: tls-verify: false images: httpd: - "latest" quay.io: tls-verify: false images: coreos/etcd: - latest
开始同步
$ skopeo sync --src yaml --dest docker skopeo-sync.yml harbor.fumai.com/library INFO[0000] Processing repo registry=docker.io repo=httpd INFO[0000] Processing repo registry=quay.io repo=coreos/etcd INFO[0000] Processing repo registry="192.168.10.80:5000" repo=busybox INFO[0000] Processing repo registry="192.168.10.80:5000" repo=redis INFO[0000] Copying image ref 1/1 from="docker://httpd:latest" to="docker://harbor.fumai.com/library/httpd:latest" Getting image source signatures Copying blob ff7b0b8c417a done Copying blob 4691bd33efec done Copying blob a603fa5e3b41 done Copying blob b1c114085b25 done Copying blob 9df1012343c7 done Copying config 8653efc8c7 done Writing manifest to image destination Storing signatures INFO[0015] Copying image ref 1/1 from="docker://quay.io/coreos/etcd:latest" to="docker://harbor.fumai.com/library/etcd:latest" Getting image source signatures Copying blob a3ed95caeb02 done Copying blob 96b0e24539ea done Copying blob d1eca4d01894 done Copying blob ff3a5c916c92 done Copying blob 8bc526247b5c done Copying blob ad732d7a61c2 done Copying blob a3ed95caeb02 skipped: already exists Copying blob a3ed95caeb02 skipped: already exists Copying blob 5f56944bb51c done Writing manifest to image destination Storing signatures INFO[0022] Synced 2 images from 2 sources INFO[0007] Copying image ref 1/1 from="docker://192.168.10.80:5000/busybox:stable" to="docker://harbor.fumai.com/library/busybox:stable" Getting image source signatures Skipping: image already present at destination INFO[0007] Copying image ref 1/2 from="docker://192.168.10.80:5000/redis:latest" to="docker://harbor.fumai.com/library/redis:latest" Getting image source signatures Copying blob a0056c8a01e3 done Copying blob 87b7cd6612f6 done Copying blob 656160ba04b8 done Copying blob a08cc0270959 done Copying blob d14ed0f181ce done Copying blob 39e3d9efeaec skipped: already exists Copying config 3358aea34e done Writing manifest to image destination Storing signatures INFO[0009] Copying image ref 2/2 from="docker://192.168.10.80:5000/redis:7.0.5" to="docker://harbor.fumai.com/library/redis:7.0.5" Getting image source signatures Copying blob a08cc0270959 skipped: already exists Copying blob d14ed0f181ce skipped: already exists Copying blob a0056c8a01e3 skipped: already exists Copying blob 87b7cd6612f6 skipped: already exists Copying blob 656160ba04b8 skipped: already exists Copying blob 39e3d9efeaec [--------------------------------------] 0.0b / 0.0b Copying config 3358aea34e [======================================] 7.5KiB / 7.5KiB Writing manifest to image destination Storing signatures
11. 删除镜像(skopeo delete)
11.1 skopeo 删除镜像
使用skopeo delete命令我们可以删除镜像 Tag,注意此处仅仅只是通过 registry API 来删除镜像的 tag(即删除了 tag 对 manifests 文件的引用)并非真正将镜像删除掉,如果想要删除镜像的 layer 还是需要通过 registry GC 的方式。
$ curl -k -u "admin:Harbor12345" https://harbor.fumai.com/v2/_catalog {"repositories":["library/alpine"]} #开始删除 $ skopeo delete docker://harbor.fumai.com/library/alpine:latest $ curl -k -u "admin:Harbor12345" https://harbor.fumai.com/v2/_catalog {"repositories":[]}
--debug
模式:
skopeo delete docker://harbor.fumai.com/library/busybox:latest --debug DEBU[0000] Loading registries configuration "/etc/containers/registries.conf" DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/000-shortnames.conf" DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/001-rhel-shortnames.conf" DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/002-rhel-shortnames-overrides.conf" DEBU[0000] Found credentials for harbor.fumai.com in credential helper containers-auth.json DEBU[0000] Using registries.d directory /etc/containers/registries.d for sigstore configuration DEBU[0000] Using "default-docker" configuration DEBU[0000] Using file:///var/lib/containers/sigstore DEBU[0000] Looking for TLS certificates and private keys in /etc/containers/certs.d/harbor.fumai.com DEBU[0000] crt: /etc/containers/certs.d/harbor.fumai.com/ca.crt DEBU[0000] cert: /etc/containers/certs.d/harbor.fumai.com/harbor.fumai.com.cert DEBU[0000] key: /etc/containers/certs.d/harbor.fumai.com/harbor.fumai.com.key DEBU[0000] GET https://harbor.fumai.com/v2/ DEBU[0000] Ping https://harbor.fumai.com/v2/ status 401 DEBU[0000] GET https://harbor.fumai.com/service/token?account=admin&scope=repository%3Alibrary%2Fbusybox%3A%2A&service=harbor-registry DEBU[0000] GET https://harbor.fumai.com/v2/library/busybox/manifests/latest DEBU[0000] DELETE https://harbor.fumai.com/v2/library/busybox/manifests/sha256:f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab DEBU[0000] Deleting /var/lib/containers/sigstore/library/busybox@sha256=f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab/signature-1
11.2 curl 方式删除
$ curl -k -u "registryuser:registryuserpassword" --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET https://192.168.10.80:5000/v2/busybox/manifests/latest HTTP/2 200 content-type: application/vnd.docker.distribution.manifest.v2+json docker-content-digest: sha256:f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab docker-distribution-api-version: registry/2.0 etag: "sha256:f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab" x-content-type-options: nosniff content-length: 527 date: Tue, 22 Nov 2022 10:51:14 GMT $ curl -s -k -u "registryuser:registryuserpassword" --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET https://192.168.10.80:5000/v2/busybox/manifests/latest | grep -i "Docker-Content-Digest" | cut -d ' ' -f 2 sha256:f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab $ curl -u 'registryuser:registryuserpassword' -k -X DELETE https://192.168.10.80:5000/v2/busybox/manifests/sha256:f75f3d1a317fc82c793d567de94fc8df2bece37acd5f2bd364a0d91a0d1f3dab
我写了一个关于通过 API 删除仓库镜像的delete_images.sh
脚本,当然你的仓库需要配置REGISTRY_STORAGE_DELETE_ENABLED=true
,才能执行删除操作,否则不支持。
#!/bin/bash default() { Images=${1-'busybox:latest'} Registry_Url=${2-'192.168.10.80:5000'} Registry_Username=${3-'registryuser'} Registry_Password=${4-'registryuserpassword'} } help() { echo "Usage:" echo "test.sh [-i Images] [-h Registry_Url] [-u Registry_Username] [-p Registry_Password] [-d]" echo "Description:" echo " Images,One or more mirror images,exmple: (busybox:latest alpine:latest)." echo " Registry_Url, registry name,exmaple: docker.io." echo " Registry_Username, registry username,exmaple: 'admin'." echo " Registry_Password, registry password,exmaple: 'Harbor12345'." echo " -d, Indicates the deletion action." exit -1 } delete() { for Image in ${Images} do Image_Name=`echo $Image | cut -d ':' -f 1 ` Image_Version=`echo $Image | cut -d ':' -f 2` echo " Starting delete ${Registry_Url}/$Image_Name:$Image_Version..." DockerContentDigest=$(curl -s -k -u "$Registry_Username:$Registry_Password" --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET "https://${Registry_Url}/v2/${Image_Name}/manifests/${Image_Version}" | grep -i "Docker-Content-Digest" | cut -d ' ' -f 2 ) DockerContentDigest=${DockerContentDigest%$'\r'} if [[ $DockerContentDigest != '' ]];then curl -u ${Registry_Username}:${Registry_Password} -k -X DELETE https://${Registry_Url}/v2/${Image_Name}/manifests/${DockerContentDigest} && [ $? == 0 ] && echo "Ok, $Registry_Url/$Image delete sucessful!" else echo "Sorry, $Registry_Url/$Image not find!" fi done } #[ $# == 0 ] && help [ $# == 0 ] && default && delete && exit 0 while getopts 'i:h:u:p:d' OPT; do case $OPT in i) Images="$OPTARG";; h) Registry_Url="$OPTARG";; u) Registry_Username="$OPTARG";; p) Registry_Password="$OPTARG";; d) delete;; h) help;; ?) help;; esac done
执行效果:我们尝试删除仓库192.168.10.80:5000
的busybox:latest
镜像。
$ skopeo list-tags docker://192.168.10.80:5000/alpine { "Repository": "192.168.10.80:5000/alpine", "Tags": [ "latest" ] } $ bash delete_images.sh -i alpine:latest -h 192.168.10.80:5000 -u registryuser -p registryuserpassword -d Starting delete 192.168.10.80:5000/alpine:latest... Ok, 192.168.10.80:5000/alpine:latest delete sucessful! $ skopeo list-tags docker://192.168.10.80:5000/alpine { "Repository": "192.168.10.80:5000/alpine", "Tags": [] }
关于skopeo
的练习就到此结束了。
参考: