【k8s】containerd を使った Kubernetes 環境で Docker Registry からイメージを pull できなくて困った話

こんにちは。お久しぶりです。
私事で恐縮ですが、12 月より新しい会社様にお世話になることとなりました。
学生の頃からずっと憧れていた企業様ですので、精一杯頑張ろうと思います。

さて、本題ですが、ローカルの VM に構築した Kubernetes ( CR: containerd ) 環境にて、同じくローカルに用意した Docker Registry に保存されているイメージから Pod を起動しようとしたところ、下記のようなエラーが発生しました。

Failed to pull image "xxx.xxx.xxx.xxx:5000/hoge": failed to pull and unpack image "xxx.xxx.xxx.xxx:5000/hoge:latest": failed to resolve reference "xxx.xxx.xxx.xxx:5000/hoge:latest:latest": failed to do request: Head "xxx.xxx.xxx.xxx:5000/hoge:latest:5000/v2/hoge/manifests/latest": http: server gave HTTP response to HTTPS client
Error: ErrImagePull

どうも、TLS 通信周りの問題から、イメージの pull に失敗しているようです。
コンテナランタイムに containerd を使っているのもあり、中々参照できる情報がなかったため、ココに備忘録を残しておきます。

TL;DR

単純に Docker Registry が HTTPS での通信に対応していないだけ。
containerd の設定ファイルを下記のように書き換えて、containerd を再起動すれば OK。
※ xxx.xxx.xxx.xxx は Docker Registry の IP に差し替える。

/etc/containerd/config.toml

[plugins."io.containerd.grpc.v1.cri".registry.configs]
  [plugins."io.containerd.grpc.v1.cri".registry.configs."xxx.xxx.xxx.xxx:5000".tls]
    insecure_skip_verify = true

[plugins."io.containerd.grpc.v1.cri".registry.headers]

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."xxx.xxx.xxx.xxx:5000"]
    endpoint = ["http://xxx.xxx.xxx.xxx:5000"]

/etc/containerd/config.toml 差分

[root@verienv ~]# diff /etc/containerd/config.toml /etc/containerd/config.toml.org
150,151d149
<         [plugins."io.containerd.grpc.v1.cri".registry.configs."xxx.xxx.xxx.xxx:5000".tls]
<           insecure_skip_verify = true
156,157d153
<         [plugins."io.containerd.grpc.v1.cri".registry.mirrors."xxx.xxx.xxx.xxx:5000"]
<           endpoint = ["http://xxx.xxx.xxx.xxx:5000"]

やってみる ( 構築 )

・環境

RoleIP addressOSsupplement
k8s Control192.168.33.11AlmaLinux 9Name: verienv01
Docker Registry
k8s Node192.168.33.12AlmaLinux 9Name: verienv02

k8s Control と Docker Registry は同じ VM に同居させるとします。

・構築 ( k8s )

k8s の主要な導入は Ansible Playbook の Role にまとめました。
Playbook を流し終えた後は、README の Memo.Initialization ( Commands after provisioning ) と Node での kubeadm join を実行すれば完了するかと思います。

[root@verienv01 ~]# kubectl get nodes
NAME        STATUS   ROLES           AGE    VERSION
verienv01   Ready    control-plane   162m   v1.28.4
verienv02   Ready    <none>          159m   v1.28.4

・構築 ( Docker Registry )

Docker Registry はコンテナが用意されているので、公式の通りに導入。
※ nerdctl で入れてしまってもいいかもしれません。

dnf -y install docker-ce docker-ce-cli
systemctl enable --now docker
docker run -d -p 5000:5000 --name registry registry:2

やってみる ( 検証 )

※ verienv01 で実施します。
※ TL;DR に記載の containerd の設定を全 Node で実施済みとします。

・検証用のコンテナイメージを作成

簡単な HTTP レスポンスを返すコンテナイメージを hello_k8s という名称でビルドします。

cat > ./Dockerfile << EOF
FROM python:slim

WORKDIR /app
EXPOSE 8000
COPY index.html .

CMD ["python", "-m", "http.server", "8000"]
EOF

cat > ./index.html << EOF
"Hello from k8s!"
EOF

docker build -t hello_k8s .

・コンテナイメージを Docker Registry に登録

localhost:5000 のタグを付与してイメージを push します。
※ 他 PC 等から Docker Registry の IP を指定して push する場合は、Docker に insecure-registries の設定が必要です。

docker tag hello_k8s:latest localhost:5000/hello_k8s
docker push localhost:5000/hello_k8s

・マニフェスト作成 & apply

Pod を起動する Deployment と NodePort 30080 で接続を受け付ける Service を定義して apply します。

cat > ./deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-k8s
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-k8s
  template:
    metadata:
      labels:
        app: hello-k8s
    spec:
      containers:
      - name: hello-k8s
        image: 192.168.33.11:5000/hello_k8s
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8000
EOF

cat > ./service.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: hello-k8s-service
spec:
  selector:
    app: hello-k8s
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
      nodePort: 30080  
EOF
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

・確認

Pod が正常に起動し、レスポンスが返ってくれば成功です!

[root@verienv01 ~]# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
hello-k8s-77b86d6c8-4mbm2   1/1     Running   0          6m52s
[root@verienv01 ~]# curl http://192.168.33.11:30080/
"Hello from k8s!"