TT Lab
はじめる
学ぶ 学習パス コース

CKA — Kubernetes管理者

CKA模擬試験A

TT Labで続きを見る

模擬試験です

実際のCKAは、120分で課題15–20個を解き、66%を超えると合格です。このセットも、課題17個・120分・合格ライン66%に合わせました。部分点制なので、すべて正解する必要はありません。17個のうち12個を通過すると、完了として扱われます。

ヒントを見ずに、まず最後まで解いてみてください。実際の試験にはヒントがありません。詰まった課題は飛ばして、時間が余ったら戻ってくるほうが、点数に有利です。ヒントと正解は、試験を一度終えたあとの復習用に使ってください。

実際の試験会場で初めて知ると時間を失うこと

ドメイン配分

ドメイン 実際の配点 このセットの課題
Cluster Architecture, Installation and Configuration 25% 課題1–4
Workloads and Scheduling 15% 課題5–7
Services and Networking 20% 課題8–10
Storage 10% 課題11–12
Troubleshooting 30% 課題13–17

課題13から17まで

実際の試験では、壊れたリソースがあらかじめ用意されています。この環境にはその仕組みがないので、各課題の指示文に、問題のマニフェストを入れておきました。まずそのまま適用してから、症状を診断して直してください。適用せずに最初から正しく作っても採点は通過しますが、そうすると診断の練習になりません。

この環境で異なる点

Pod内のクラスターは、kwokctlが起動した1人用のクラスターです。コントロールプレーンは本物なので、マニフェスト・RBAC・スケジューリング・クォータ・CRD・PVのバインド・ドレインは、すべて実際に動作します。ただし、ワークロードのコンテナは実行されないので、kubectl exec・logs・port-forwardは使えません。課題も、それを要求しません。

開始前に、kubectl get nodesでノード3つがReadyかを確認してください。まだなら、クラスターが起動している最中です(2分ほどかかります)。

採点

各課題の確認ボタンを押すと、採点ツールが稼働中のクラスターで値を再計算して照合します。ファイルに何を書いたかではなく、クラスターがどんな状態かを見ます。正解に至る経路は、複数が許容されます。

opsネームスペースのデプロイ権限

ネームスペースopsを作成し、サービスアカウントdeployerを置いてください。

Roledeployerは、appsグループのdeploymentsに対するget・list・watch・create・updateと、coreグループのpodsに対するget・listを許可します。それ以外の権限はない必要があります。RoleBindingdeployerで、そのサービスアカウントに結び付けてください。

coreグループは、apiGroupsに空文字列で書きます。権限が広がるミスは、許可されたものだけを確認しても表に出ないので、kubectl auth can-i ... --as=system:serviceaccount:ops:deployerで、許可されてはいけない動詞も一緒に尋ねてください。

集約ClusterRole

ClusterRolemonitoring-viewを作成してください。ルールを直接書かず、ラベルrbac.example.com/aggregate-to-monitoring: "true"が付いたClusterRoleを集めるように、aggregationRuleを使います。

そのラベルが付いたClusterRolemonitoring-metricsは、coreグループのpodsとnodesに対するget・list・watchを許可します。

集約はコントローラーが行います。monitoring-viewのrulesを空にして作成すると、しばらくしてルールが埋まります。埋まらないなら、セレクターのラベルと実際のラベルが、1文字でも違っています。

Backup CRDとカスタムリソース

CRDbackups.ops.example.comを作成してください。グループはops.example.com、バージョンはv1(served・storage)、スコープはNamespaced、kindはBackup、複数形はbackups、短い名前はbkです。スキーマで、spec.scheduleは必須の文字列で、spec.retentionは整数です。

続けて、ネームスペースopsにBackupnightlyを作成し、scheduleを0 2 * * *、retentionを7にしてください。

CRDが登録された直後は、まだ提供されていません。kubectl wait --for=condition=Established crd/<이름>で待ってから(プレースホルダーはCRD名です)、カスタムリソースを作成してください。スキーマに型を書かないと、どんな値でも入ってしまいます。

team-aのクォータとデフォルトのリソース値

ネームスペースteam-aにResourceQuotateam-a-quotaを置いてください。上限は、pods 10、requests.cpu 2、requests.memory 4Gi、limits.cpu 4、limits.memory 8Giです。

同じネームスペースにLimitRangeteam-a-limitsを置き、リソースを書いていないコンテナに、limits cpu 500m・memory 512Miと、requests cpu 100m・memory 128Miが補完されるようにしてください。

LimitRangeのdefaultはlimitsを、defaultRequestはrequestsを補完します。実際に補完されるかを見るには、kubectl run ... --dry-run=server -o yamlでサーバーに尋ねればよいです。

frontendのDeploymentとローリング戦略

ネームスペースwebにDeploymentfrontendを作成してください。イメージはnginx:1.27、レプリカは4個、Podラベルはapp=frontendとtier=webです。

戦略はRollingUpdateで、maxSurge 1・maxUnavailable 0とし、リビジョン履歴は3個だけ残します。

maxUnavailable 0は、「更新中も、準備のできたPod数を決して減らさない」という意味です。数値でも百分率でも書けますが、採点ツールは、数値の1と0を期待します。

バッチ専用ノードとトレラレーション

ノードlab-node-batchを新規に作成してください。kwokが管理するように、アノテーションkwok.x-k8s.io/node: fakeを付け、ラベルworkload=batchとテイントworkload=batch:NoScheduleを設定します。

続けて、ネームスペースbatchにDeploymentcruncherを作成して、busybox:1.36をレプリカ3個で動かし、3つのPodがすべて、そのノードにだけ起動するようにしてください。

トレラレーションは、「行ける」とだけ言います。「そこへ行け」は、nodeSelectorかrequiredのnodeAffinityが言います。両方があってはじめて、配置が決まります。

すべてのノードで起動するエージェント

ネームスペースwebにDaemonSetnode-agentを作成してください。イメージはbusybox:1.36で、テイントが設定されたノードを含めて、クラスターのすべてのノードで起動する必要があります。

DaemonSetもスケジューラーを経由します。テイントが設定されたノードで起動するには、そのテイントに耐えるトレラレーションが必要です。どんなテイントにも耐えさせるには、キーを書かずに、operatorだけをExistsにすればよいです。

名前付きポートを使うapiサービス

ネームスペースwebにDeploymentapiを作成してください。イメージはnginx:1.27、レプリカ2個、コンテナポートは8080で、そのポートの名前はhttpです。

Serviceapiは、ClusterIPでポート80を受けて、数値ではなく、ポートの名前httpで転送する必要があります。

Serviceは、セレクターが間違っていても問題なく作成され、エンドポイントだけが空になります。kubectl get endpointslice -n web -l kubernetes.io/service-name=apiで、アドレスが付いているかを確認してください。

shop.example.comのIngress

IngressClassnginxを作成してください。controllerはk8s.io/ingress-nginxです。

ネームスペースwebに、frontendDeploymentを指すServicefrontend(ポート80)を作成し、Ingressshopで、ホストshop.example.comの/はfrontend:80に、/apiはapi:80に送ってください。どちらのパスも、pathTypeはPrefixです。

Ingressは、バックエンドのサービスがなくても作成されます。サービス名を間違えて書いてもエラーが出ないので、自分で確認してください。v1では、バックエンドをservice.nameとservice.port.numberで書きます。

webネームスペースのネットワークポリシー

ネームスペースwebのすべてのPodに対して、入ってくるトラフィックをデフォルトで遮断するNetworkPolicydefault-deny-ingressを作成してください。

続けて、NetworkPolicyapi-allowで、app=apiのPodに限り、同じネームスペースのapp=frontendのPodと、ネームスペースmonitoringから来るTCP 8080だけを許可してください。

全面遮断は、podSelectorを空のオブジェクトにして、ingressルールを1つも書かないことです。fromのリストの項目を分けて書けばORで、1つの項目の中にpodSelectorとnamespaceSelectorを一緒に書けばANDです。この問題はORです。

静的ボリュームのバインド

StorageClasslocal-fastを作成してください。provisionerはkubernetes.io/no-provisioner、reclaimPolicyはRetain、volumeBindingModeはImmediateです。

PVpv-fast-1は、2Gi・ReadWriteOnce・local-fast・hostPath/mnt/fast1です。ネームスペースstorageのPVCdataを、1Gi・ReadWriteOnce・local-fastで作成して、そのPVにバインドされるようにしてください。

PVCがPendingから抜け出せないなら、クラス名・アクセスモード・容量の3つのうち、どれかがPVと合っていません。要求容量はPVの容量より小さくてもかまいませんが、アクセスモードは、正確に含まれている必要があります。

PVCと一時ボリュームを一緒に使うワークロード

ネームスペースstorageにDeploymentwriterを作成してください。イメージはnginx:1.27、レプリカは1個です。

PVCdataを、ボリューム名dataで/dataにマウントし、emptyDirボリュームcacheを/cacheにマウントしてください。

ボリュームは、Podのスペックのvolumesに宣言し、コンテナのvolumeMountsで、名前で持ってきて使います。どちらか一方だけだと、Podが作成されないか、マウントが抜けます。

エンドポイントが空のサービス

まず、次のマニフェストをそのまま適用してください。

apiVersion: apps/v1
kind: Deployment
metadata: {name: shop, namespace: broken}
spec:
  replicas: 3
  selector: {matchLabels: {app: shop}}
  template:
    metadata: {labels: {app: shop}}
    spec:
      containers:
        - name: shop
          image: nginx:1.27
          ports: [{containerPort: 8080}]
---
apiVersion: v1
kind: Service
metadata: {name: shop, namespace: broken}
spec:
  selector: {app: shop-svc}
  ports: [{port: 80, targetPort: 80, protocol: TCP}]

Podは3個とも起動するのに、Serviceshopにエンドポイントがまったく付きません。Deploymentには手を触れず、Serviceだけを直して、3つのPodがポート8080でつながるようにしてください。

直すべき場所は2か所です。エンドポイントがそもそも空になる理由と、ポートが見当違いの場所に行く理由は、それぞれ別のフィールドにあります。kubectl get svc shop -n broken -o yamlとPodのラベルを、並べて見てください。

Pendingから抜け出せないワークロード

まず、次のマニフェストをそのまま適用してください。

apiVersion: apps/v1
kind: Deployment
metadata: {name: report, namespace: broken}
spec:
  replicas: 2
  selector: {matchLabels: {app: report}}
  template:
    metadata: {labels: {app: report}}
    spec:
      containers:
        - name: report
          image: nginx:1.27
          resources:
            requests: {cpu: "16", memory: 64Mi}

PodがPendingから抜け出せません。レプリカ数とイメージはそのままにして、原因を取り除き、2つのPodがどちらもRunningになるようにしてください。

kubectl describe podのEventsや、PodのPodScheduled条件に、スケジューラーが理由を書いています。ノード1つが提供できる量は、kubectl describe nodeのAllocatableにあります。

広すぎる権限を絞る

まず、次のマニフェストをそのまま適用してください。

apiVersion: v1
kind: ServiceAccount
metadata: {name: ci, namespace: broken}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: {name: ci-admin}
roleRef: {apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: cluster-admin}
subjects:
  - {kind: ServiceAccount, name: ci, namespace: broken}

監査で、このバインディングが指摘されました。サービスアカウントciは削除せずに、権限だけを絞ってください。ciは、ネームスペースbroken内で、podsをget・list・watchし、deploymentsをget・list・watch・create・updateできる必要があり、それ以外は、クラスターのどこでも何もできない必要があります。

cluster-adminのバインディングを削除するだけでは終わりではありません。削除するとciは何の権限もなくなるので、必要な分を、ネームスペースの範囲で、改めて与える必要があります。確認は、kubectl auth can-i --as=system:serviceaccount:broken:ciで行います。

クォータに引っかかって起動できないワークロード

まず、次のマニフェストをそのまま適用してください。

apiVersion: v1
kind: ResourceQuota
metadata: {name: tight, namespace: quota-broken}
spec:
  hard:
    requests.cpu: 500m
    limits.memory: 512Mi
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: worker, namespace: quota-broken}
spec:
  replicas: 3
  selector: {matchLabels: {app: worker}}
  template:
    metadata: {labels: {app: worker}}
    spec:
      containers:
        - name: worker
          image: nginx:1.27

Podが1つも起動しません。クォータには手を触れず、ワークロード側だけを直して、レプリカ3個がすべてRunningになるようにしてください。

ReplicaSetの状態条件に、アドミッションが拒否した理由が、そのまま書かれています(kubectl describe rs -n quota-broken)。クォータにあるリソースが書かれていれば、そのネームスペースのすべてのPodが、そのリソースを必ず宣言する必要があります。

終わらないドレイン

まず、次のマニフェストをそのまま適用してください。

apiVersion: apps/v1
kind: Deployment
metadata: {name: edge, namespace: broken}
spec:
  replicas: 2
  selector: {matchLabels: {app: edge}}
  template:
    metadata: {labels: {app: edge}}
    spec:
      nodeSelector: {kubernetes.io/hostname: lab-node-0}
      containers: [{name: edge, image: nginx:1.27}]
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: {name: edge-pdb, namespace: broken}
spec:
  minAvailable: 2
  selector: {matchLabels: {app: edge}}

メンテナンスのために、ノードlab-node-0を空にする必要があります。ところが、ドレインが終わりません。PodDisruptionBudgetは削除せず、レプリカ2個を維持したまま、ドレインを終えてください。終わったあと、lab-node-0にはedgeのPodが1つもなく、2つのPodは別のノードでRunningである必要があります。

塞いでいるものが2つあります。1つはPodを空にできなくし、もう1つは、空にしても行き場がないようにします。kubectl get pdb -n brokenのALLOWED DISRUPTIONS列と、PodのnodeSelectorを、一緒に見てください。