Joe Blog

容器镜像同步工具 skopeo 初体验

背景

最近对于有上一个项目,由于是容器镜像形式交付并在内网部署:需要在内部网络拉取外网镜像仓库镜像,这样就需要原本不通外网的服务器节点通过代理的形式(网络复杂,巨慢)来拉取外网镜像。

为了解决拉取镜像耗时巨大的问题,这边考虑在内网自建镜像仓库Harbor,通过镜像同步的方式来拉取外网公共仓库的镜像存储到本地镜像仓库,实现内部节点拉取本地镜像来解决该问题。

image分析

参考浅谈docker中镜像和容器在本地的存储

docker镜像在本地磁盘的存储

我们常规的操作是用docker retag来给镜像重新打标签,然后docker push到我们新的仓库地址,这个也是最简单的方法

# 假设从dockerhub公共镜像仓库拉取 library/alpine:latest
# docker pull
root@ubuntu:~# docker pull alpine:latest
latest: Pulling from library/alpine
596ba82af5aa: Pull complete 
Digest: sha256:d9a7354e3845ea8466bb00b22224d9116b183e594527fb5b6c3d30bc01a20378
Status: Downloaded newer image for alpine:latest
# docker tag 
root@ubuntu:~# docker tag alpine:latest harbor.foo.com/library/alpine:latest
# docker push
root@ubuntu:~# docker push harbor.foo.com/library/alpine:latest

上述方法对于单个镜像操作,没有什么大的问题,但是涉及批量镜像迁移就会有一个问题:因为 docker pull –> docker tag –> docker push 的过程中会对镜像的 layer 进行解压缩,registry 中存储的镜像 layer 格式是 vnd.docker.image.rootfs.diff.tar.gzip,因为 docker pull 镜像时会对 registry 上的 layer 进行解压缩,这一点和我们解压缩一些 gzip 压缩的资源一样道理,为了减少网络传输的流量。这样可以顺推 docker push的时候也是类似,所以只是将镜像从一个 registry 复制到另一个 registry 来说,这些过程将在解压缩耗时巨大,显然不是最佳方案。

既然我们已经知道了在做镜像仓库迁移的时候的性能瓶颈在哪。那我们能不能有方法来规避这个解压缩的过程,直接是blob级别的复制,而不涉及layer的解压缩,那不是在迁移速度方面飞起。

由此引出了Skoepo 这个工具,可以使用 skopeo copy 直接从一个 registry 中复制镜像原始的 layer 到另一个 registry 中,期间不会涉及镜像 layer 解压缩操作

Skoepo

Skoepo的github项目地址:https://github.com/containers/skopeo

用法

skopeo --help
Various operations with container images and container image registries

Usage:
  skopeo [command]

Available Commands:
  copy                                          Copy an IMAGE-NAME from one location to another
  delete                                        Delete image IMAGE-NAME
  help                                          Help about any command
  inspect                                       Inspect image IMAGE-NAME
  list-tags                                     List tags in the transport/repository specified by the REPOSITORY-NAME
  login                                         Login to a container registry
  logout                                        Logout of a container registry
  manifest-digest                               Compute a manifest digest of a file
  standalone-sign                               Create a signature using local files
  standalone-verify                             Verify a signature using local files
  sync                                          Synchronize one or more images from one location to another

Flags:
      --command-timeout duration   timeout for the command execution
      --debug                      enable debug output
  -h, --help                       help for skopeo
      --insecure-policy            run the tool without any policy check
      --override-arch ARCH         use ARCH instead of the architecture of the machine for choosing images
      --override-os OS             use OS instead of the running OS for choosing images
      --override-variant VARIANT   use VARIANT instead of the running architecture variant for choosing images
      --policy string              Path to a trust policy file
      --registries.d DIR           use registry configuration files in DIR (e.g. for container signature storage)
      --tmpdir string              directory used to store temporary files
  -v, --version                    Version for Skopeo

Use "skopeo [command] --help" for more information about a command.

可以看到 skopeo 的功能很简单:

skoepo copy

支持可以在各种存储机制之间复制容器镜像,包括:

$ skopeo copy docker://quay.io/buildah/stable docker://registry.internal.company.com/buildah
$ skopeo copy oci:busybox_ocilayout:latest dir:existingemptydirectory

#### skoepo delete

$ skopeo delete docker://localhost:5000/imagename:latest

skoepo sync 支持的参数更多

$ skopeo sync --src docker --dest dir registry.example.com/busybox /media/usb
$ skopeo sync --src dir --dest docker /media/usb/busybox:1-glibc my-registry.local.lan/test/
$ skopeo sync --src docker --dest dir --scoped registry.example.com/busybox /media/usb

Images are located at:

/media/usb/registry.example.com/busybox:1-glibc
/media/usb/registry.example.com/busybox:1-musl
/media/usb/registry.example.com/busybox:1-ubuntu
...
/media/usb/registry.example.com/busybox:latest
$ skopeo sync --src docker --dest docker registry.example.com/busybox my-registry.local.lan

Destination registry content:

  REPO                         TAGS
  registry.local.lan/busybox   1-glibc, 1-musl, 1-ubuntu, ..., latest
  skopeo sync --src docker --dest docker registry.example.com/repo/busybox my-registry.local.lan/repo

Destination registry content:

  REPO                              TAGS
  registry.local.lan/repo/busybox   1-glibc, 1-musl, 1-ubuntu, ..., latest

skoepo inspect

这个命令可以查看一个镜像的 image config 和 mainfests文件,和 crictl inspect 命令差不多

skopeo inspect docker://alpine:latest --raw | jq "."
{
  "manifests": [
    {
      "digest": "sha256:4661fb57f7890b9145907a1fe2555091d333ff3d28db86c3bb906f6a2be93c87",
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      },
      "size": 528
    }
}

镜像存在方式

IMAGE NAMES example
containers-storage: containers-storage:
dir: dir:/PATH
docker:// docker://alpine:latest
docker-daemon: docker-daemon:alpine:latest
docker-archive: docker-archive:alpine.tar (docker save)
oci: oci:alpine:latest