特定の ContainerRegistry から ImagePull できない時にやったこと

ご無沙汰しております。

かれこれ形態を変えながらずっと運用してきている自宅サーバーですが、最近は OpenStack や HomeNOC を活用しながら、割と本格的なデータセンターに仕上がってきている実感があります。

現在、自宅サーバーは物理的な Kubernetes クラスタの上に OpenStack Helm を用いて、OpenStack を構成し、その上で Kubernetes を動かしています。
これにより、実際にワークロードが稼働するクラスタの管理を容易にしています。

この辺の詳細のご紹介は追々・・・

困っていたこと

さて、この上で動く VM において、特定の Image のみ Image Pull できない状況に陥っていました。

$ k get pods -o wide -n external-secrets-operator
NAME                                                              READY   STATUS             RESTARTS   AGE    IP            NODE                                       NOMINATED NODE   READINESS GATES
external-secret-operator-external-secrets-54f6f6b5cd-tf4jz        0/1     ImagePullBackOff   0          110m   10.96.8.226   bear-cluster-01-pool-large-1-c4cds-hvd4n   <none>           <none>
external-secret-operator-external-secrets-cert-controller-ct7hv   0/1     ErrImagePull       0          110m   10.96.8.108   bear-cluster-01-pool-large-1-c4cds-hvd4n   <none>           <none>
external-secret-operator-external-secrets-webhook-fc45c769w6mf9   0/1     ImagePullBackOff   0          110m   10.96.8.11    bear-cluster-01-pool-large-1-c4cds-hvd4n   <none>           <none>

さらに調べてみると、ghcr.io からの Image Pull ができていないようです。

Events:
  Type     Reason   Age                     From     Message
  ----     ------   ----                    ----     -------
  Warning  Failed   17m (x16 over 114m)     kubelet  Error: ErrImagePull
  Warning  Failed   17m                     kubelet  Failed to pull image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2": failed to pull and unpack image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2": failed to copy: httpReadSeeker: failed open: failed to do request: Get "https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090?se=2025-09-10T18%3A45%3A00Z&sig=fIL2PcnxRoGa7fwhX93D%2BUD677gyCThpjtewRNWR4cs%3D&ske=2025-09-11T04%3A41%3A31Z&skoid=fb3d2a07-ec6c-4fe4-aced-9efe0fd2fe1a&sks=b&skt=2025-09-10T04%3A41%3A31Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-01-05&sp=r&spr=https&sr=b&sv=2025-01-05&hmac=6697faa26cc20786adef5c0bfdc82a35d078947c9cf5fcf6faa407d00c82898b": net/http: TLS handshake timeout
  Warning  Failed   17m                     kubelet  Failed to pull image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2": failed to pull and unpack image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2": failed to copy: httpReadSeeker: failed open: failed to do request: Get "https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090?se=2025-09-10T18%3A45%3A00Z&sig=LNEPvMJ1S%2FQq%2FRhDG%2F3413M5Ionqk4C0%2BjTw1F7uPG0%3D&ske=2025-09-11T17%3A23%3A02Z&skoid=fb3d2a07-ec6c-4fe4-aced-9efe0fd2fe1a&sks=b&skt=2025-09-10T17%3A23%3A02Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-01-05&sp=r&spr=https&sr=b&sv=2025-01-05&hmac=6697faa26cc20786adef5c0bfdc82a35d078947c9cf5fcf6faa407d00c82898b": net/http: TLS handshake timeout
  Normal   Pulling  16m (x22 over 115m)     kubelet  Pulling image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2"
  Normal   BackOff  4m56s (x382 over 114m)  kubelet  Back-off pulling image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2"
  Warning  Failed   4m41s (x381 over 114m)  kubelet  Error: ImagePullBackOff

そこで、VM 上から直接 crictl を使い、Pull してみます。

$ sudo crictl pull oci.external-secrets.io/external-secrets/external-secrets:v0.18.2
E0910 18:59:06.345433   26838 remote_image.go:167] "PullImage from image service failed" err="rpc error: code = Unknown desc = failed to pull and unpack image \"oci.external-secrets.io/external-secrets/external-secrets:v0.18.2\": failed to copy: httpReadSeeker: failed open: failed to do request: Get \"https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090?se=2025-09-10T19%3A05%3A00Z&sig=ANj%2FXQHq4Q7RrIUytjgGJRT4VaTfs%2FWle3M1i7z45vs%3D&ske=2025-09-11T18%3A02%3A42Z&skoid=fb3d2a07-ec6c-4fe4-aced-9efe0fd2fe1a&sks=b&skt=2025-09-10T18%3A02%3A42Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-01-05&sp=r&spr=https&sr=b&sv=2025-01-05&hmac=d3393c14b73770f94a267f77aa92e5d69deda7f29af1667ef7ac97bc52b71eb2\": net/http: TLS handshake timeout" image="oci.external-secrets.io/external-secrets/external-secrets:v0.18.2"
FATA[0013] pulling image: rpc error: code = Unknown desc = failed to pull and unpack image "oci.external-secrets.io/external-secrets/external-secrets:v0.18.2": failed to copy: httpReadSeeker: failed open: failed to do request: Get "https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090?se=2025-09-10T19%3A05%3A00Z&sig=ANj%2FXQHq4Q7RrIUytjgGJRT4VaTfs%2FWle3M1i7z45vs%3D&ske=2025-09-11T18%3A02%3A42Z&skoid=fb3d2a07-ec6c-4fe4-aced-9efe0fd2fe1a&sks=b&skt=2025-09-10T18%3A02%3A42Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-01-05&sp=r&spr=https&sr=b&sv=2025-01-05&hmac=d3393c14b73770f94a267f77aa92e5d69deda7f29af1667ef7ac97bc52b71eb2": net/http: TLS handshake timeout 

まぁ、そうですよね・・・

NIC の設定を見る

TLS handshake timeout 自体は、対向先のサーバーが落ちているなどでも発生し得ますが、特にそのような status はないため、おま環を疑いつつ、チャッピーに壁打ちしたところ、ネットワーク上のどこかの mtu 設定に問題がありそうでした。

VM 側

大きめのサイズで ping を打ってみます。

$ ping -c1 -M do -s 1472 pkg-containers.githubusercontent.com
PING pkg-containers.githubusercontent.com (185.199.111.154) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1456

--- pkg-containers.githubusercontent.com ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

$ ping -c1 -M do -s 1428 pkg-containers.githubusercontent.com
PING pkg-containers.githubusercontent.com (185.199.108.154) 1428(1456) bytes of data.
1436 bytes from cdn-185-199-108-154.github.com (185.199.108.154): icmp_seq=1 ttl=59 time=7.06 ms

--- pkg-containers.githubusercontent.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 7.059/7.059/7.059/0.000 ms

どうやら 1456 bytes 以上は Fragmentation なしに送れないようで、さらにヘッダーでしょうか・・・?? 28 bytes を除いた 1428 bytes 以上は送れないようです。
ちなみに、VM 上で設定されている MTU は 1500 bytes です。

ghcr に対してのルーティング情報を取得します。

$ ip route get 185.199.111.154
185.199.111.154 via 10.3.0.1 dev ens3 src 10.3.1.16 uid 1001 
    cache expires 156sec mtu 1456  

VM より上で 1456 bytes に落とされているようです。

ルーター側

VM は収容しているホストに設定した Open vSwitch を通して直接ルーターに接続しているため、ルーター( VyOS )の設定を見てみます。

vyos@vyos:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 xxx:xxx:xxx:xxx:xxx:xxx:xxx:xxx/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.1/16 brd 10.1.255.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 xxx:xxx:xxx:xxx:xxx:xxx:xxx:xxx/64 scope link 
       valid_lft forever preferred_lft forever
8: br0.3@br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 10.3.0.1/16 brd 10.3.255.255 scope global br0.3
       valid_lft forever preferred_lft forever
    inet6 xxx:xxx:xxx:xxx:xxx:xxx:xxx:xxx/64 scope link 
       valid_lft forever preferred_lft forever
13: tun0@eth0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1476 qdisc noqueue state UNKNOWN group default qlen 1000
    link/gre6 xxx:xxx:xxx:xxx:xxx:xxx:xxx:xxx peer xxx::xxxx permaddr xxxx::
    inet xxx.xxx.xxx.xxx/31 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 xxx:xxx:xxx:xxx:xxx:xxx:xxx:xxx/64 scope link 
       valid_lft forever preferred_lft forever

経路としては、( HomeNOC 側 NIC ) → ( eth0 ) → tun0 という形で GRE tunnel を張っています。
そのため、GRE のヘッダー + IPv6 ヘッダーの分として NIC 自体の MTU から 44 bytes が引かれ、 MTU が 1456 bytes になります。

え、1456 bytes ・・・?

・・・とりあえず MSS を設定しておきます。

[edit]
vyos@vyos# set interfaces tunnel tun0 ip adjust-mss 1416
[edit]
vyos@vyos# show interfaces tunnel 
 tunnel tun0 {
     address xxx.xxx.xxx.xxx/31
     encapsulation ip6gre
+    ip {
+        adjust-mss 1416
+    }
     ipv6 {
         adjust-mss 1396
     }
     parameters {
         ipv6 {
             encaplimit none
         }
     }
     remote xx:xx:xx:xx:xx:xx
     source-address xx:xx:xx:xx:xx:xx
     source-interface eth0
 }

その後

試しに、VM 側の NIC で MTU を 1456 bytes に設定した上で Image Pull してみます。

$ sudo ip link set dev ens3 mtu 1456

$ sudo crictl pull oci.external-secrets.io/external-secrets/external-secrets:v0.18.2
Image is up to date for sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090

おや、いつの間にか勝手に Image Pull してしまってますね。
一度 VM を削除して、再作成してみます。

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc prio state UP group default qlen 1000
    link/ether fa:16:3e:8e:a3:21 brd ff:ff:ff:ff:ff:ff
    altname enp0s3
    inet 10.3.1.119/16 metric 100 brd 10.3.255.255 scope global dynamic ens3
       valid_lft 86260sec preferred_lft 86260sec
    inet6 fe80::f816:3eff:fe8e:a321/64 scope link 
       valid_lft forever preferred_lft forever

$ sudo crictl pull oci.external-secrets.io/external-secrets/external-secrets:v0.18.2
Image is up to date for sha256:a25b2b207fcfc16426e89e1a0f3f373535565c7c645e79785dec51c661fb7090

なんと、NIC 側の MTU はいじらずに Image Pull できてしまいました。
ルーター側で MSS を設定してあげれば、良い感じに Segmentation して GRE tunnel に流してくれるので、LAN 側の IP の世界の MTU はいじらずに投げられるのでしょうか??

ネットワークの世界はよくわかりません・・・

タイトルとURLをコピーしました