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

CKAD — Kubernetesアプリケーション開発者

CKAD模擬試験A

TT Labで続きを見る

模擬試験です

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

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

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

ドメイン配分

ドメイン 実際の配点 このセットの課題
Application Design and Build 20% 課題1–3
Application Deployment 20% 課題4–7
Application Observability and Maintenance 15% 課題8–10
Application Environment, Configuration and Security 25% 課題11–14
Services and Networking 20% 課題15–17

時間配分について

課題3(CronJob)は、コントローラーが実際に1回動くまで、最大1分かかります。先に作っておいて、他の課題を解いたあとで確認してください。課題4と課題5は、ロールアウトが終わるまで待つ必要があるので、kubectl rollout statusを使うほうが速いです。

この環境での違い

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

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

採点

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

Initコンテナとサイドカー

ネームスペースappにPodloggerを作成してください。

Initコンテナは、spec.initContainersに別に書きます。ボリュームはPodに一度だけ宣言し、3つのコンテナがそれぞれvolumeMountsで使います。

完了回数を指定したJob

ネームスペースappにJobmigrateを作成してください。イメージはbusybox:1.36で、echo doneを実行します。

完了回数4、並列度2、backoffLimit 2、activeDeadlineSeconds 120、restartPolicyはNeverです。JobはCompleteで終わる必要があります。

Jobのcompletionsは、作成したあとで変更できません。値を間違えたなら、削除して作り直してください。restartPolicyはPodテンプレート側に書きます。

CronJob

ネームスペースappにCronJobreportを作成してください。イメージはbusybox:1.36でdateを実行し、restartPolicyはOnFailureです。

スケジュールは*/1 * * * *、concurrencyPolicyはForbid、startingDeadlineSecondsは30、成功の履歴は2つ、失敗の履歴は1つだけ残します。実際に1回以上実行される必要があります。

周期が1分なので、作成した直後はまだ実行の記録がありません。kubectl get cronjob report -n appのLAST SCHEDULE列に時刻が表示されるまで待ってから、採点してください。

ローリングアップデートでイメージを上げる

ネームスペースdeployに、Deploymentapiをnginx:1.27、レプリカ3つで作成してください。戦略はRollingUpdateで、maxSurge 2・maxUnavailable 0です。

そのあと、イメージをnginx:1.28に上げてください。削除して作り直さず、更新する必要があります。

kubectl set image deploy/api <컨테이너>=nginx:1.28(プレースホルダーはコンテナ名です)で更新すると、以前のReplicaSetが履歴として残ります。kubectl rollout statusで、終わるまで待ってください。

ロールバック

ネームスペースdeployに、Deploymentwebをnginx:1.27、レプリカ2つで作成してください。

そのあと、イメージをnginx:1.99-brokenに上げ、誤ったデプロイであることを確認してから、最初のリビジョンに戻してください。戻したあとも、問題のリビジョンは履歴に残っている必要があります。

kubectl rollout history deploy/webでリビジョン番号を確認してから、kubectl rollout undo deploy/web --to-revision=1を使います。削除して作り直すと、履歴が消えます。

ラベルで分けるカナリア

ネームスペースdeployに、Deploymentshop-stable(レプリカ4、Podラベルapp=shop・version=stable、イメージnginx:1.27)とshop-canary(レプリカ1、Podラベルapp=shop・version=canary、イメージnginx:1.28)を作成してください。2つのPodとも、コンテナポートは8080です。

Serviceshopは、ポート80で受けてポート8080に渡し、2つのDeploymentのPodを両方とも指す必要があります。

Serviceのセレクターにversionを入れると、片方しか選ばれません。2つのDeploymentが共通で持つラベル1つだけを、セレクターに使ってください。エンドポイントが5つあるかを確認すれば十分です。

kustomizeのオーバーレイ

/root/exam/kustomize/baseに、Deploymentcart(レプリカ1、イメージnginx:1.27、Podラベルapp=cart)とkustomizationを置いてください。

/root/exam/kustomize/overlayにオーバーレイを作成し、名前の前にprod-を付け、ネームスペースをdeploy-prodに、レプリカを3に、イメージタグを1.28に変更し、ラベルenv=prodを追加してください(セレクターには入れません)。

そのオーバーレイを、クラスターに適用してください。

kubectl kustomize <디렉터리>(プレースホルダーはディレクトリです)で結果をまず目で確認してから、kubectl apply -kで適用してください。セレクターは作成したあとで変更できないので、共通ラベルをセレクターに入れると、次の適用が拒否されます。

3種類のプローブ

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

3つのプローブは、コンテナスペックの中に並べて書きます。値を1つでも落とすと既定値が入りますが、採点ツールは、問題に書かれた値をそのまま期待します。

Pod一覧をファイルに抽出する

ネームスペースobsで、ラベルapp=checkoutのPodを名前順に並べ替え、1行に<파드이름> <노드이름> <상태>(プレースホルダーはPod名、ノード名、状態です)の形式で、/root/exam/09-pods.txtに保存してください。ヘッダーは入れません。

採点ツールは、このファイルを採点時点のクラスターと照合します。あとでPodを作り直したなら、ファイルも作り直してください。

kubectl get pods -o jsonpathのrangeで必要なフィールドだけを取り出し、sortで並べ替えれば十分です。ノード名は.spec.nodeName、状態は.status.phaseです。

なくなったAPIバージョンへの移行

次のマニフェストは、現在のクラスターが提供していないAPIバージョンで書かれています。現在のバージョンに移行して、ネームスペースobsに適用してください。必要なフィールドが増えているなら、埋める必要があります。

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata: {name: obs-pdb}
spec:
  minAvailable: 1
---
apiVersion: batch/v1beta1
kind: CronJob
metadata: {name: obs-cron}
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers: [{name: obs, image: busybox:1.36, command: ["sh","-c","date"]}]
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata: {name: obs-ing}
spec:
  rules:
    - host: obs.example.com
      http:
        paths:
          - path: /
            backend:
              serviceName: checkout
              servicePort: 80

Ingressが指すServicecheckout(ポート80 → コンテナポートhttp)と、IngressClassnginx(controller k8s.io/ingress-nginx)も一緒に作成し、Ingressにそのクラスを指定してください。PDBのセレクターはapp=checkoutです。

kubectl explain <리소스> --recursive(プレースホルダーはリソース名です)で、現在のバージョンのフィールド名を確認できます。policy/v1のPDBはselectorが必須で、networking.k8s.io/v1のIngressはpathTypeとbackend.service構造を要求します。

設定とシークレット値の注入

ネームスペースcfgにConfigMapapp-configを作成してください。キーはAPP_MODE=production、LOG_LEVEL=info、そしてファイル用のキーapp.properties(内容は自由)です。

Secretapp-secret(Opaque)に、キーAPI_TOKENを置いてください。値は自分で決めてください。

Deploymentsvc(イメージnginx:1.27、レプリカ1)は、3つの方式をすべて使います。

subPathを使うと、ディレクトリではなくファイル1つだけがそのパスに置かれます。mountPathにファイルパスを書き、subPathにキー名を書きます。値を--from-literalで作成すると、base64エンコードはkubectlが自動で行います。

securityContextで絞る

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

Podレベルは、runAsUser 10001、runAsGroup 10001、fsGroup 10001、runAsNonRoot true、seccompProfileはRuntimeDefaultにします。

コンテナレベルは、allowPrivilegeEscalation false、readOnlyRootFilesystem true、capabilitiesはすべてdropして、NET_BIND_SERVICEだけをaddします。

Podレベルとコンテナレベルは、別の場所にあります。capabilitiesとallowPrivilegeEscalation・readOnlyRootFilesystemは、コンテナ側にだけあります。

アプリケーション専用のサービスアカウント

ネームスペースcfgにサービスアカウントapp-saを作成してください。ただし、トークンが自動でマウントされないようにしてください。

Rolecm-readerは、coreグループのconfigmapsに対してget・listだけを許可します。RoleBindingcm-readerでバインドしてください。

Deploymentreader(イメージnginx:1.27、レプリカ1)が、そのサービスアカウントで動くようにしてください。

automountServiceAccountTokenは、ServiceAccountオブジェクトの最上位のフィールドです(specの中ではありません)。Deploymentでは、PodスペックのserviceAccountNameで指定します。

制限の中で動くワークロード

ネームスペースcfg-quotaにLimitRangecfg-limitsを置いてください。コンテナ基準で、max cpu 500m・memory 512Mi、min cpu 50m・memory 64Mi、default cpu 250m・memory 256Mi、defaultRequest cpu 100m・memory 128Miです。

ResourceQuotacfg-quotaの上限は、pods 10、requests.cpu 1、requests.memory 1Gi、limits.cpu 2、limits.memory 2Giです。

Deploymentsized(イメージnginx:1.27、レプリカ2)は、requests cpu 100m・memory 128Mi、limits cpu 250m・memory 256Miで、2つのPodがどちらも起動する必要があります。

LimitRangeのmaxを超える値は、アドミッションで拒否されます。クォータが実際にカウントしているかは、kubectl describe quota cfg-quota -n cfg-quotaのUsed列で確認してください。

ClusterIPとNodePort

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

Servicewebは、ClusterIPでポート80を受け、ポート名httpに渡します。Serviceweb-nodeportは、NodePortで同じPodを指し、ポート80を受け、ノードポートは30080です。

2つのServiceとも、targetPortには数字ではなく名前を書く必要があります。nodePortは、30000–32767の範囲でのみ直接指定できます。

2つのパスを分けるIngress

ネームスペースnetにDeploymentadmin(イメージnginx:1.27、レプリカ1、コンテナポート8080で名前はhttp)とServiceadmin(ポート80 → http)を作成してください。

IngressClassnginx(controller k8s.io/ingress-nginx)を作成し、Ingressnet-ingで、ホストapp.example.comの/はweb:80に、/adminはadmin:80に送ってください。2つのパスとも、pathTypeはPrefixです。

パスが重なるときは、より具体的なものが先にマッチしますが、採点は2つのルールが正確に書かれているかだけを見ます。バックエンドのServiceが実際にあるかも確認してください。

遮断と許可の3つのポリシー

ネームスペースnetに、NetworkPolicyを3つ作成してください。

egressをすべて遮断すると、DNSも遮断されて、Podがどんな名前も解決できなくなります。DNSはUDPだけを使うのではなく、応答が大きいとTCPに切り替わるので、両方を開ける必要があります。ネームスペースセレクターは、kubernetes.io/metadata.nameラベルで選べば十分です。