2. 常用容器引擎

1. 前言

对于普通用户来说,Docker 是最常用(也可能唯一的)的容器引擎,但容器引擎不止 Docker 一种,下面是一些常用容器引擎配置镜像加速的办法。

2. Containerd

Containerd 是一个开源的容器运行时,它是 Docker 容器引擎的核心组件,最初由 Docker 开发并贡献给 CNCF(云原生计算基金会)。

Containerd 的配置文件位于 /etc/containerd/config.toml,默认配置内容比较复杂,根据版本不同配置也不同,首先导出一份默认配置:

containerd config default > /etc/containerd/config.toml

配置文件较长,建议导出到 vscode 或其他常用的 GUI 编辑器中编辑。

Containerd 2.0 版本前,需要找到 [plugins."io.containerd.grpc.v1.cri".registry.mirrors],在里面添加镜像加速器,如下:

disabled_plugins = []
imports = []
oom_score = 0
plugin_dir = ""
required_plugins = []
root = "/var/lib/containerd"
state = "/run/containerd"
temp = ""
version = 2
...
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
          endpoint = ["https://hub.alduin.net"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
          endpoint = ["https://ghcr.alduin.net"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
          endpoint = ["https://gcr.alduin.net"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
          endpoint = ["https://k8s.alduin.net"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
          endpoint = ["https://quay.alduin.net"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."mcr.microsoft.com"]
          endpoint = ["https://mcr.alduin.net"]
...
  "io.containerd.timeout.bolt.open" = "0s"
  "io.containerd.timeout.shim.cleanup" = "5s"
  "io.containerd.timeout.shim.load" = "5s"
  "io.containerd.timeout.shim.shutdown" = "3s"
  "io.containerd.timeout.task.state" = "2s"

[ttrpc]
  address = ""
  gid = 0
  uid = 0

Containerd 2.0 版本后,配置文件的版本升级到了 3,需要找到 [plugins."io.containerd.cri.v1.images".registry.mirrors],在里面添加镜像加速器,如下:

...
      [plugins."io.containerd.cri.v1.images".registry.mirrors]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."docker.io"]
          endpoint = ["https://hub.alduin.net"]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."ghcr.io"]
          endpoint = ["https://ghcr.alduin.net"]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."gcr.io"]
          endpoint = ["https://gcr.alduin.net"]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."registry.k8s.io"]
          endpoint = ["https://k8s.alduin.net"]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."quay.io"]
          endpoint = ["https://quay.alduin.net"]
        [plugins."io.containerd.cri.v1.images".registry.mirrors."mcr.microsoft.com"]
          endpoint = ["https://mcr.alduin.net"]
...

编辑完成后,重启 containerd,然后使用 crictl 工具拉取镜像验证是否有效(ctr 工具无法使用镜像加速):

➜  ~ systemctl restart containerd
➜  ~ crictl pull registry.k8s.io/coredns:1.6.5
WARN[0000] image connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
Image is up to date for sha256:70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61

3. Podman & CRI-O

Red Hat 为了绕过 Docker 限制,投入了大量人力开发了全套容器工具,这些工具共享配置文件和镜像存储,使用以下配置文件可以一次性添加全部的容器镜像加速器。

创建一个文件:/etc/containers/registries.conf.d/zz-mirror.conf,内容如下:

[[registry]]
  prefix = "docker.io"
  location = "docker.io"
[[registry.mirror]]
  prefix = "docker.io"
  location = "hub.alduin.net"

[[registry]]
  prefix = "ghcr.io"
  location = "ghcr.io"
[[registry.mirror]]
  prefix = "ghcr.io"
  location = "ghcr.alduin.net"

[[registry]]
  prefix = "gcr.io"
  location = "gcr.io"
[[registry.mirror]]
  prefix = "gcr.io"
  location = "gcr.alduin.net"

[[registry]]
  prefix = "registry.k8s.io"
  location = "registry.k8s.io"
[[registry.mirror]]
  prefix = "registry.k8s.io"
  location = "k8s.alduin.net"

[[registry]]
  prefix = "quay.io"
  location = "quay.io"
[[registry.mirror]]
  prefix = "quay.io"
  location = "quay.alduin.net"

[[registry]]
  prefix = "mcr.microsoft.com"
  location = "mcr.microsoft.com"
[[registry.mirror]]
  prefix = "mcr.microsoft.com"
  location = "mcr.alduin.net"

文件格式为 TOML,每个镜像仓库 mirror 配置之间使用换行符隔离。

下面在命令行中启用 debug 级别的日志,可以看到 podman 使用加速器地址拉取到容器镜像:

➜  ~ podman --log-level debug pull registry.k8s.io/coredns:1.6.5
INFO[0000] podman filtering at log level debug
DEBU[0000] Called pull.PersistentPreRunE(podman --log-level debug pull registry.k8s.io/coredns:1.6.5)
DEBU[0000] Merged system config "/usr/share/containers/containers.conf"
DEBU[0000] Using conmon: "/usr/bin/conmon"
DEBU[0000] Initializing boltdb state at /var/lib/containers/storage/libpod/bolt_state.db
DEBU[0000] Using graph driver
DEBU[0000] Using graph root /var/lib/containers/storage
DEBU[0000] Using run root /run/containers/storage
DEBU[0000] Using static dir /var/lib/containers/storage/libpod
DEBU[0000] Using tmp dir /run/libpod
DEBU[0000] Using volume path /var/lib/containers/storage/volumes
DEBU[0000] Set libpod namespace to ""
DEBU[0000] Cached value indicated that overlay is supported
DEBU[0000] Cached value indicated that overlay is supported
DEBU[0000] Cached value indicated that metacopy is not being used
DEBU[0000] Cached value indicated that native-diff is usable
DEBU[0000] backingFs=extfs, projectQuotaSupported=false, useNativeDiff=true, usingMetacopy=false
INFO[0000] [graphdriver] using prior storage driver: overlay
DEBU[0000] Initializing event backend journald
DEBU[0000] Configured OCI runtime runsc initialization failed: no valid executable found for OCI runtime runsc: invalid argument
DEBU[0000] Configured OCI runtime krun initialization failed: no valid executable found for OCI runtime krun: invalid argument
DEBU[0000] Configured OCI runtime runj initialization failed: no valid executable found for OCI runtime runj: invalid argument
DEBU[0000] Configured OCI runtime kata initialization failed: no valid executable found for OCI runtime kata: invalid argument
DEBU[0000] Using OCI runtime "/usr/bin/crun"
INFO[0000] Setting parallel job count to 25
DEBU[0000] Pulling image registry.k8s.io/coredns:1.6.5 (policy: always)
DEBU[0000] Looking up image "registry.k8s.io/coredns:1.6.5" in local containers storage
DEBU[0000] Normalized platform linux/amd64 to {amd64 linux  [] }
DEBU[0000] Trying "registry.k8s.io/coredns:1.6.5" ...
DEBU[0000] Trying "registry.k8s.io/coredns:1.6.5" ...
DEBU[0000] Trying "registry.k8s.io/coredns:1.6.5" ...
DEBU[0000] Loading registries configuration "/etc/containers/registries.conf"
DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/shortnames.conf"
DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/zz-mirror.conf"
DEBU[0000] Failed to decode keys ["registry.mirror.prefix" "registry.mirror.prefix" "registry.mirror.prefix" "registry.mirror.prefix" "registry.mirror.prefix" "registry.mirror.prefix"] from "/etc/containers/registries.conf.d/zz-mirror.conf"
DEBU[0000] Normalized platform linux/amd64 to {amd64 linux  [] }
DEBU[0000] Attempting to pull candidate registry.k8s.io/coredns:1.6.5 for registry.k8s.io/coredns:1.6.5
DEBU[0000] parsed reference into "[overlay@/var/lib/containers/storage+/run/containers/storage]registry.k8s.io/coredns:1.6.5"
Trying to pull registry.k8s.io/coredns:1.6.5...
DEBU[0000] Copying source image //registry.k8s.io/coredns:1.6.5 to destination image [overlay@/var/lib/containers/storage+/run/containers/storage]registry.k8s.io/coredns:1.6.5
DEBU[0000] Using registries.d directory /etc/containers/registries.d
DEBU[0000] Trying to access "k8s.alduin.net/coredns:1.6.5"
DEBU[0000] No credentials matching k8s.alduin.net/coredns found in /run/containers/0/auth.json
DEBU[0000] No credentials matching k8s.alduin.net/coredns found in /root/.config/containers/auth.json
DEBU[0000] No credentials matching k8s.alduin.net/coredns found in /root/.docker/config.json
DEBU[0000] No credentials matching k8s.alduin.net/coredns found in /root/.dockercfg
DEBU[0000] No credentials for k8s.alduin.net/coredns found
DEBU[0000]  No signature storage configuration found for k8s.alduin.net/coredns:1.6.5, using built-in default file:///var/lib/containers/sigstore
DEBU[0000] Looking for TLS certificates and private keys in /etc/docker/certs.d/k8s.alduin.net
DEBU[0000] GET https://k8s.alduin.net/v2/
DEBU[0001] Ping https://k8s.alduin.net/v2/ status 200
DEBU[0001] GET https://k8s.alduin.net/v2/coredns/manifests/1.6.5
DEBU[0002] Content-Type from manifest GET is "application/vnd.docker.distribution.manifest.list.v2+json"
DEBU[0002] Using blob info cache at /var/lib/containers/cache/blob-info-cache-v1.boltdb
DEBU[0002] Source is a manifest list; copying (only) instance sha256:608ac7ccba5ce41c6941fca13bc67059c1eef927fd968b554b790e21cc92543c for current system
DEBU[0002] GET https://k8s.alduin.net/v2/coredns/manifests/sha256:608ac7ccba5ce41c6941fca13bc67059c1eef927fd968b554b790e21cc92543c
DEBU[0003] Content-Type from manifest GET is "application/vnd.docker.distribution.manifest.v2+json"
DEBU[0003] IsRunningImageAllowed for image docker:registry.k8s.io/coredns:1.6.5
DEBU[0003]  Using default policy section
DEBU[0003]  Requirement 0: allowed
DEBU[0003] Overall: allowed
DEBU[0003] Downloading /v2/coredns/blobs/sha256:70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61
DEBU[0003] GET https://k8s.alduin.net/v2/coredns/blobs/sha256:70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61
Getting image source signatures
DEBU[0004] Reading /var/lib/containers/sigstore/coredns@sha256=608ac7ccba5ce41c6941fca13bc67059c1eef927fd968b554b790e21cc92543c/signature-1
DEBU[0004] Not looking for sigstore attachments: disabled by configuration
DEBU[0004] Manifest has MIME type application/vnd.docker.distribution.manifest.v2+json, ordered candidate list [application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.v1+prettyjws, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v1+json]
DEBU[0004] ... will first try using the original manifest unmodified
DEBU[0004] Checking if we can reuse blob sha256:c6568d217a0023041ef9f729e8836b19f863bcdb612bb3a329ebc165539f5a80: general substitution = true, compression for MIME type "application/vnd.docker.image.rootfs.diff.tar.gzip" = true
DEBU[0004] Checking if we can reuse blob sha256:fc6a9081f6658509038b132fb8c66e8ed16c4511549365ea5ceb22e2c6cb905d: general substitution = true, compression for MIME type "application/vnd.docker.image.rootfs.diff.tar.gzip" = true
DEBU[0004] Failed to retrieve partial blob: blob type not supported for partial retrieval
DEBU[0004] Downloading /v2/coredns/blobs/sha256:c6568d217a0023041ef9f729e8836b19f863bcdb612bb3a329ebc165539f5a80
DEBU[0004] GET https://k8s.alduin.net/v2/coredns/blobs/sha256:c6568d217a0023041ef9f729e8836b19f863bcdb612bb3a329ebc165539f5a80
DEBU[0004] Failed to retrieve partial blob: blob type not supported for partial retrieval
DEBU[0004] Downloading /v2/coredns/blobs/sha256:fc6a9081f6658509038b132fb8c66e8ed16c4511549365ea5ceb22e2c6cb905d
DEBU[0004] GET https://k8s.alduin.net/v2/coredns/blobs/sha256:fc6a9081f6658509038b132fb8c66e8ed16c4511549365ea5ceb22e2c6cb905d
Copying blob c6568d217a00 [--------------------------------------] 0.0b / 119.4KiB
Copying blob fc6a9081f665 [--------------------------------------] 0.0b / 12.5MiB
DEBU[0006] Detected compression format gzip
DEBU[0006] Using original blob without modification
Copying blob c6568d217a00 [==========================>-----------] 83.8KiB / 119.4KiB
Copying blob fc6a9081f665 [--------------------------------------] 32.0KiB / 12.5MiB
Copying blob c6568d217a00 done
Copying blob c6568d217a00 done
Copying blob fc6a9081f665 done
DEBU[0008] No compression detected
DEBU[0008] Compression change for blob sha256:70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61 ("application/vnd.docker.container.image.v1+json") not supported
DEBU[0008] Using original blob without modification
Copying config 70f311871a done
Writing manifest to image destination
Storing signatures
DEBU[0008] setting image creation date to 2019-11-05 13:59:27.232671258 +0000 UTC
DEBU[0008] created new image ID "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61"
DEBU[0008] saved image metadata "{\"signatures-sizes\":{\"sha256:608ac7ccba5ce41c6941fca13bc67059c1eef927fd968b554b790e21cc92543c\":[]}}"
DEBU[0008] added name "registry.k8s.io/coredns:1.6.5" to image "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61"
DEBU[0008] Pulled candidate registry.k8s.io/coredns:1.6.5 successfully
DEBU[0008] Looking up image "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" in local containers storage
DEBU[0008] Trying "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" ...
DEBU[0008] parsed reference into "[overlay@/var/lib/containers/storage+/run/containers/storage]@70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61"
DEBU[0008] Found image "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" as "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" in local containers storage
DEBU[0008] Found image "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" as "70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61" in local containers storage ([overlay@/var/lib/containers/storage+/run/containers/storage]@70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61)
DEBU[0008] exporting opaque data as blob "sha256:70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61"
70f311871ae12c14bd0e02028f249f933f925e4370744e4e35f706da773a8f61
DEBU[0008] Called pull.PersistentPostRunE(podman --log-level debug pull registry.k8s.io/coredns:1.6.5)