ICTSC2025 二次予選 問題解説: 眠れない夜
概要
あなたは、Webサービスのインフラを管理するエンジニアです。
今日も仕事を終え、綺麗な夜空を眺めながら帰路についていると上司から緊急の電話がかかってきました。明日までにデプロイ予定のWebアプリケーションの担当者が急病で作業不能になってしまったとのことです。
前任者の作業メモによると、アプリケーションはKubernetes上で稼働させる予定でしたが、現在は正常に動作していません。
あなたはこのアプリケーションを稼働させ、利用可能な状態にする必要があります。
調査と復旧対応を行ってください。
前提条件
kube-systemNamespace内及びCluster-wideなリソースについては変更不可- ただし、調査、修正のために一時的に変更を加えることは許可します。
- また、コントローラ等によって自動で再作成されるリソースは、調査、修正のために削除して構いません。
- 与えられるログイン情報はserver-02のみ
- server-02からkubectlコマンドでKubernetesに接続できます。
kにaliasを貼っているので必要であれば使ってください。
- Kubernetesが動いているserver-01については前任者が接続情報をなくしてしまったためログインできなくなってしまったようです。
- server-02からkubectlコマンドでKubernetesに接続できます。
192.168.255.60:80に接続するとNodePortの30080番ポートに転送する設定が入っています。
初期状態
web-serverNamespace内のweb-serverDeploymentのPodが起動しない
終了状態
- server-02上で
curl http://192.168.255.60を実行し、期待されたHTMLが返却される- HTMLの内容は
deployment.yaml内のConfigMapに記載されています。 - 与えられたKubernetesクラスタ以外でアプリケーションを動作させてはいけません。
- HTMLの内容は
web-serverDeploymentをkubectl rollout restartしても正しくPodが再起動できる状態になっている
接続情報
| ホスト名 | IP アドレス | ユーザ | パスワード |
|---|---|---|---|
| server-02 | 192.168.255.61 | user | ictsc2025 |
解説
トラブルの原因
この問題では 2つの問題が起きていました。1つ目はValidatingAdmissionPolicyによりPodの作成が制限されている問題、2つ目はkube-schedulerのLeaseオブジェクトが破損しPodのscheduleができなくなっている問題でした。
解決方法
ValidatingAdmissionPolicy
まずクラスタ内でDeploymentの状態を確認すると適切に作成されていることがわかります。ただ、Podは1つも作成されていないようです。
user@server-02:~$ kubectl get deploy -n web-server
NAME READY UP-TO-DATE AVAILABLE AGE
web-server 0/2 0 0 39d
user@server-02:~$ kubectl get pod -n web-server
No resources found in web-server namespace.
KubernetesにおいてDeploymentのcontrollerはReplicaSetを作成し、ReplicaSetのcontrollerがPodを作成するのでReplicaSetの状態も確認してみましょう。作成されているようです。
user@server-02:~$ kubectl get rs -n web-server
NAME DESIRED CURRENT READY AGE
web-server-7d5b6cfc77 2 0 0 39d
すなわちReplicaSet controllerのreconcile時に問題が起きている可能性が高そうです。describeしてみましょう。
user@server-02:~$ kubectl describe rs web-server-7d5b6cfc77 -n web-server
Name: web-server-7d5b6cfc77
Namespace: web-server
Selector: app=web-server,pod-template-hash=7d5b6cfc77
...省略...
Conditions:
Type Status Reason
---- ------ ------
ReplicaFailure True FailedCreate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreate 49m replicaset-controller Error creating: pods "web-server-7d5b6cfc77-r7cjz" is forbidden: ValidatingAdmissionPolicy 'require-container-resources' with binding 'bind-require-container-resources' denied request: All containers must have requests/limits
Warning FailedCreate 32m replicaset-controller Error creating: pods "web-server-7d5b6cfc77-jsx6j" is forbidden: ValidatingAdmissionPolicy 'require-container-resources' with binding 'bind-require-container-resources' denied request: All containers must have requests/limits
Warning FailedCreate 16m replicaset-controller Error creating: pods "web-server-7d5b6cfc77-v7rzp" is forbidden: ValidatingAdmissionPolicy 'require-container-resources' with binding 'bind-require-container-resources' denied request: All containers must have requests/limits
どうやら require-container-resources というValidatingAdmissionPolicyが All containers must have requests/limits というエラーメッセージを吐いているようです。念の為ValidatingAdmissionPolicyの中身も確認してみます。
user@server-02:~$ kubectl get validatingadmissionpolicy require-container-resources -o yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
creationTimestamp: "2025-11-03T21:21:26Z"
generation: 1
name: require-container-resources
resourceVersion: "474"
uid: 265d0ed7-8704-45a8-a268-8e0386b53212
spec:
failurePolicy: Fail
matchConstraints:
matchPolicy: Equivalent
namespaceSelector: {}
objectSelector: {}
resourceRules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
scope: '*'
validations:
- expression: "object.spec.containers.all(container, \n has(container.resources)
&& \n has(container.resources.requests) && \n has(container.resources.limits)
&&\n has(container.resources.requests.cpu) &&\n has(container.resources.requests.memory)
&&\n has(container.resources.limits.cpu) &&\n has(container.resources.limits.memory)\n)\n"
message: All containers must have requests/limits
...
全てのcontainers[]にlimits/requestsを設定すれば良いようです。
ちなみに余談ですがKubernetesのbest practiceとしては常にlimitsを設定すれば良いというわけでもなかったりします。(参考: Kubernetes best practices: Resource requests and limits )
例として以下のようにrequests/limitsを設定してあげてkubectl applyしてみます。
user@server-02:~$ diff -u deployment.yaml deployment2.yaml
--- deployment.yaml 2025-11-04 06:50:03.044034841 +0900
+++ deployment2.yaml 2025-12-13 15:40:29.512901016 +0900
@@ -78,6 +78,13 @@
containers:
- name: nginx
image: nginx:1.25-alpine
+ resources:
+ requests:
+ cpu: '500m'
+ memory: '256Mi'
+ limits:
+ cpu: '1000m'
+ memory: '512Mi'
ports:
- containerPort: 80
name: http
user@server-02:~$ kubectl apply -f deployment2.yaml
Warning: resource namespaces/web-server is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
namespace/web-server configured
Warning: resource configmaps/html-content is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/html-content configured
Warning: resource deployments/web-server is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
deployment.apps/web-server configured
Warning: resource services/web-server is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
service/web-server configured
Warning: resource services/web-server-nodeport is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
service/web-server-nodeport configured
これによりPodリソースが正常に作成されていることがわかりました。
user@server-02:~$ kubectl get po -n web-server
NAME READY STATUS RESTARTS AGE
web-server-6569c694f8-kc2c5 0/1 Pending 0 35s
これで1つ目の問題は解決です。
kube-schedulerのLeaseオブジェクト
しかし、待てども待てどもPodがRunningになりません。ずっとPendingのままのようです。
試しにPodをdescribeしてみましょう。
user@server-02:~$ kubectl describe po -n web-server
Name: web-server-6569c694f8-kc2c5
Namespace: web-server
Priority: 0
Service Account: default
Node: <none>
Labels: app=web-server
pod-template-hash=6569c694f8
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Controlled By: ReplicaSet/web-server-6569c694f8
...
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
しかし何もEventが表示されていません。また、Nodeが空のままのようです。
Node: <none>
KubernetesにおいてPodをどのNodeにデプロイするかを決定するコンポーネントは kube-scheduler です。kube-schedulerに何か問題が起きていないか確認してみましょう。
user@server-02:~$ kubectl logs -n kube-system kube-scheduler-ictsc-control-plane --tail 5
E1213 06:51:45.540389 1 leaderelection.go:448] error retrieving resource lock kube-system/kube-scheduler: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
E1213 06:51:49.282418 1 leaderelection.go:448] error retrieving resource lock kube-system/kube-scheduler: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
E1213 06:51:52.345476 1 leaderelection.go:448] error retrieving resource lock kube-system/kube-scheduler: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
E1213 06:51:54.681377 1 leaderelection.go:448] error retrieving resource lock kube-system/kube-scheduler: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
E1213 06:51:57.563174 1 leaderelection.go:448] error retrieving resource lock kube-system/kube-scheduler: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
どうやら Lease オブジェクトを取得するのがエラーになっているようです。
試しにLeaseリソースを取得してみるとそれもエラーになり、同じようなエラーログが出ています。どうやらLeaseオブジェクトが壊れてしまっているようです。
user@server-02:~$ kubectl get lease -n kube-system
Error from server: no kind "Lease" is registered for version "coordination\xaek8s.io/v1" in scheme "pkg/api/legacyscheme/scheme.go:30"
user@server-02:~$ kubectl get lease -n default
No resources found in default namespace.
エラーメッセージをよく読んでみると coordination\xaek8s.io/v1 とあります。 \ae これはなんでしょうか?
Leaseオブジェクトは coordination.k8s.io というGroupに所属しているリソースです。本来 \xae のところは . が入っているべき場所です。
. のUTF-8における文字コードは0x2Eです。すなわち0x2Eが0xAEになっています。どうやら最上位ビットが反転してしまった結果データが壊れてしまったようです。
>>> bin(0x2e ^ 0xae)
'0b10000000'
Etcdに保存されているデータが壊れてしまっているのでこれを修復する必要があります。幸いLeaseリソースは削除すれば自動的にcontrollerによって再作成すれば良いので該当リソースを削除できれば大丈夫そうです。
しかしEtcdにアクセスしようにもKubernetesが動いているNodeにはSSHするための情報がないためログインできません。どうにかログインする方法はないでしょうか? 実はKubernetesには kubectl debug node という機能があります。これを使ってNodeにログインしてみましょう。
user@server-02:~$ kubectl debug -ti node/ictsc-control-plane --image busybox -- sh
--profile=legacy is deprecated and will be removed in the future. It is recommended to explicitly specify a profile, for example "--profile=general".
Creating debugging pod node-debugger-ictsc-control-plane-b62wp with container debugger on node ictsc-control-plane.
The pods "node-debugger-ictsc-control-plane-b62wp" is invalid: : ValidatingAdmissionPolicy 'require-container-resources' with binding 'bind-require-container-resources' denied request: All containers must have requests/limits
先ほどのエラーが出てしまいました。いくつか回避策はありますが、一時的にこの制限を解除することは問題として許可されています。ここではバックアップを取った上で一度削除しておきましょう。
ちなみに他の解決策としては kube-system NamespaceにPodを作成するなどでも対応可能です。
user@server-02:~$ kubectl get validatingadmissionpolicy -o yaml > backup.yaml
user@server-02:~$ kubectl delete validatingadmissionpolicy require-container-resources restrict-nodename-assignment
validatingadmissionpolicy.admissionregistration.k8s.io "require-container-resources" deleted
validatingadmissionpolicy.admissionregistration.k8s.io "restrict-nodename-assignment" deleted
これでようやくcontrol-plane Nodeにログインすることができました。 /host 配下にhostのファイルシステムが見えています。ここでは簡単のため chroot /host をして更に簡単に扱えるようにしておきましょう。
user@server-02:~$ kubectl debug -ti node/ictsc-control-plane --image busybox -- sh
--profile=legacy is deprecated and will be removed in the future. It is recommended to explicitly specify a profile, for example "--profile=general".
Creating debugging pod node-debugger-ictsc-control-plane-8cjh2 with container debugger on node ictsc-control-plane.
All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.
If you don't see a command prompt, try pressing enter.
/ # chroot /host
root@ictsc-control-plane:/#
kube-apiserverのetcdの設定を確認すると http://172.17.0.1:2379 で接続できるようです。認証も何もかかっていない、脆弱ですね。
root@ictsc-control-plane:/# cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
- --etcd-servers=http://172.17.0.1:2379
試しに etcdctlでkeyの一覧を取得してみましょう。
root@ictsc-control-plane:/# etcdctl --endpoints http://172.17.0.1:2379 get --keys-only --prefix=true / | grep lease
/registry/configmaps/kube-node-lease/kube-root-ca.crt
/registry/leases/kube-node-lease/ictsc-control-plane
/registry/leases/kube-node-lease/ictsc-worker
/registry/leases/kube-system/apiserver-lqwgahrybxpd2v3bujlottsg6q
/registry/leases/kube-system/kube-controller-manager
/registry/leases/kube-system/kube-scheduler
/registry/masterleases/172.18.0.2
/registry/namespaces/kube-node-lease
/registry/serviceaccounts/kube-node-lease/default
/registry/leases/kube-system/kube-scheduler これのようです。
root@ictsc-control-plane:/# etcdctl --endpoints http://172.17.0.1:2379 get /registry/leases/kube-system/kube-scheduler
/registry/leases/kube-system/kube-scheduler
k8s
coordinationk8s.io/v1Lease
kube-scheduler
kube-system"*$6139f6bf-27de-4bd6-b0cb-0d8650c3fb3a2��
kube-schedulerUpdatecoordination.k8s.io/v۹�FieldsV1:|
z{"f:spec":{"f:acquireTime":{},"f:holderIdentity":{},"f:leaseDurationSeconds":{},"f:leaseTransitions":{},"f:renewTime":{}}}BX
8ictsc-control-plane_0dd08610-6c7d-4a30-88e7-32571bfb9421
��"
۹��
("
coordinationk8s.io/v1Leaseの途中の.が読めなくなっていますね。このリソースで間違いなさそうなため削除してみます。
root@ictsc-control-plane:/# etcdctl --endpoints http://172.17.0.1:2379 del /registry/leases/kube-system/kube-scheduler
1
これでcontrol planeからログアウトして確認するとkube-schedulerが動作して無事アプリケーションが起動したようです。
user@server-02:~$ kubectl get po -n web-server
NAME READY STATUS RESTARTS AGE
web-server-6569c694f8-kc2c5 1/1 Running 0 60m
web-server-6569c694f8-pc6fn 1/1 Running 0 3m18s
忘れずValidatingAdmissionPolicyも戻しておきましょう。
user@server-02:~$ kubectl create -f backup.yaml
validatingadmissionpolicy.admissionregistration.k8s.io/require-container-resources created
validatingadmissionpolicy.admissionregistration.k8s.io/restrict-nodename-assignment created
curlでもアクセスできるようになりました。
user@server-02:~$ curl http://192.168.255.60
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
...
別解
別解としてNodeにログインせずとも同一Nodeからetcdctlを叩けるようなPodをデプロイする、というものもあります。kube-schedulerやそれに相当するものを自作で頑張ってデプロイいただいていたチームも制約を満たしているものは正解としています。
また、問題文中に以下のような制約を設けておりましたが、新規に作成することについての制限が明確でなかったため新規リソースを作成することでの対応は許容しています。
kube-system Namespace内及びCluster-wideなリソースについては変更不可
/etc/kubernetes/manifests 以下のファイルの編集は kube-system NamespaceのPodの変更となるため禁止としました。
補足
このLeaseリソースの1 bitが反転してしまった現象は実際に作問者が遭遇した事象を元に再現した問題です。メモリエラー等でビットが反転してしまう現象は意外と身近に起きています。最近でも某航空会社の機体が太陽フレアの影響により問題が起きていましたね。2025年は太陽フレアの活動が特に活発なようです。
実は問題文中にもちょっとした小ネタを残していました?
綺麗な夜空を眺めながら帰路についている
この「綺麗な夜空を」というのは星空ではなくオーロラのことを指していました。太陽フレアが活発になると低緯度地域でもオーロラが観測できることがあるそうです。解く前に気づくことはほぼ不可能だと思いますがビット反転をみてもしかして?と思ってくれた方がいれば嬉しいです。
皆さん、メモリがどうせ高騰しているならECCメモリを買いましょう。
想定していたよりも沢山の参加者の方に解いていただきKubernetesに対する参加者の皆さんの理解度の高さに驚かされました。