Kubernetes学習メモ(3)

KCNA講座のSection 4に基づき、Docker Compose上のk3s環境を使ってPod・Deployment・Serviceなどの基本リソースをハンズオン形式で学習しました。 kubectlによるリソース作成やロールアウト管理に加え、ConfigMapやSecretsといった設定周りまで、Kubernetesの基礎的な操作手順を網羅的にまとめました。
目次
これまでのもの
教材
- Kubernetes Certified (KCNA) + Hands On Labs + Practice Exams
- 内容はしっかりしてるけど、日本語字幕がない
- Kubernetesの概念は結構端折ってるので、学習メモ(1,2)でやったExtreme Beginnersを最初にやったほうが良い
今回はSection 4の内容
事前準備
Docker composeベースで動くハンズオンのラボがある。これを適当なLinux環境で実行しておく(ローカルでもEC2でもOK)
https://github.com/spurin/diveintokcna/tree/compose
※Docker Desktopなど様々な環境での実行に対応しているが、Staleされたブランチから切り替えるためどこにあるのか少しわかりづらいかも
クローン
git clone --single-branch -b compose https://github.com/spurin/diveintokcna.git
cd diveintokcna
環境立ち上げ
./start.sh
環境終了
./stop.sh
localhost:32535で、GUIベースのコンソールが出てくる。EC2の場合は、VSCodeが自動的にポートフォワードしてくれる。
コントロールプレーンで、ユーザー名root、パスワードrootでログインできる。

ただし、Kubectlのインストールが必要(Dockerなので毎回実行必要)
curl -sfLk https://get.k3s.io | INSTALL_K3S_VERSION=v1.31.0+k3s1 K3S_TOKEN=KCNA INSTALL_K3S_EXEC="--disable traefik --kubelet-arg=eviction-hard=imagefs.available<1%,nodefs.available<1%" sh -
mkdir -p ~/.kube; mv /etc/rancher/k3s/k3s.yaml ~/.kube/config
以下のコマンドが出ればKubectlが利用できる。
kubectl get nodes
worker1, 2のノードを追加する。全てコントロールプレーンで操作する
ssh worker-1 'curl -sfLk https://get.k3s.io | INSTALL_K3S_VERSION=v1.31.0+k3s1 K3S_URL=https://control-plane:6443 K3S_TOKEN=KCNA INSTALL_K3S_EXEC="--kubelet-arg=eviction-hard=imagefs.available<1%,nodefs.available<1%" sh -'
ssh worker-2 'curl -sfLk https://get.k3s.io | INSTALL_K3S_VERSION=v1.31.0+k3s1 K3S_URL=https://control-plane:6443 K3S_TOKEN=KCNA INSTALL_K3S_EXEC="--kubelet-arg=eviction-hard=imagefs.available<1%,nodefs.available<1%" sh -'
kubectl get nodesが以下のようになればOK
root@control-plane:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 5m18s v1.31.0+k3s1
worker-1 Ready <none> 92s v1.31.0+k3s1
worker-2 Ready <none> 77s v1.31.0+k3s1
Kubernetes Pod
nginxのPodを作成
kubectl run nginx --image=nginx
Podの一覧
kubectl get pods
Podのログ
kubectl logs pod/nginx
PodのIPを取得
kubectl get pods -o wide
接続テスト(IPが10.42.0.5と仮定)
ping 10.42.0.5
# 他のノードから
ssh worker-1 ping 10.42.0.5
ssh worker-2 ping 10.42.0.5
ポートフォワーディング
kubectl port-forward pod/nginx 8080:80
もう一個コントロールプレーンのシェルを開いて
curl 127.0.0.1:8080
# Welcome to nginxと表示される
Podの作成
kubectl run --image=ubuntu ubuntu sleep infinity
Ubuntu Podに接続(UbuntuのPod内に入れる)
kubectl exec -it ubuntu -- bash
Ubuntuからnginxへのアクセス
root@ubuntu:/# apt update
root@ubuntu:/# apt install curl
root@ubuntu:/# curl 10.42.0.5
Podの削除
kubectl delete pod/nginx pod/ubuntu --now
YAMLの自動作成
kubectl run nginx --image=nginx --dry-run=client -o yaml | tee nginx.yaml
命令型コマンド(Imperative):create, replace, delete
宣言型アプローチ(Declarative):apply
restartPolicyの列挙
kubectl explain pod.spec.restartPolicy
YAMLベースからのPodの作成
kubectl apply -f nginx.yaml
Ubuntuコンテナの作成
kubectl run --image=ubuntu --dry-run=client -o yaml ubuntu sleep infinity | tee ubuntu.yaml
kubectl apply -f ubuntu.yaml
2つのYAMLの結合(上のPodをDelete後)
{ cat nginx.yaml; echo "---"; cat ubuntu.yaml; } | tee combined.yaml
kubectl apply -f combined.yaml
YAMLベースのPodの削除
kubectl delete -f combined.yaml --now
サイドカー化(combined.yamlを編集)
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mypod
name: mypod
spec:
containers:
- name: webserver
image: nginx
resources: {}
- name: sidecar
image: ubuntu
args:
- /bin/sh
- -c
- while true; do echo "$(date +'%T') - Hello from the sidecar"; sleep 5; if [ -f /tmp/crash ]; then exit 1; fi; done
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
curlのimagesを使ってnginxにリクエスト
kubectl apply -f combined.yaml
kubectl describe pod/mypod
# IPを確認する
kubectl run -it --rm --image=curlimages/curl --restart=Never curl -- http://<nginxのIP>
サイドカーのログを表示
kubectl logs pod/mypod -c sidecar
サイドカーコンテナをクラッシュさせる。kubectl get podsで再起動し、サイドカーのログを表示したときに新しくなっている。
kubectl exec -it mypod -c sidecar -- touch /tmp/crash
クラッシュ前のログの表示
kubectl logs pod/mypod -p -c sidecar
片付け
kubectl delete pod/mypod --now
Kubernetes Namespaces
全リソースの表示
kubectl get all -A
Namespaceの一覧(default, kube-system, kube-public, kube-node-leaseがある)
kubectl get namespaces
# または短縮形
kubectl get ns
短縮形のリスト
kubectl api-resources | more
Namespaceの作成
kubectl create namespace mynamespace
作成したNamespaceにPodを作成
kubectl -n mynamespace run nginx --image=nginx
指定したNamespaceのPod一覧
kubectl -n mynamespace get pods
デフォルトのNamespaceの確認(デフォルト:defaultのNS)
kubectl config view
デフォルトのNamespaceの切り替え(get podsなどでNamespaceを指定しなくてよくなる)
kubectl config set-context --current --namespace=mynamespace
デフォルトのNamespaceを戻す
kubectl config set-context --current --namespace=default
Namespaceの削除
kubectl delete namespace/mynamespace --now
Kubernetes Deployments and Replica sets
デプロイの作成(YAMLを仲介させる)
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml | tee nginx-deployment.yaml | kubectl apply -f -
デプロイ一覧の取得
kubectl get deployment
ReplicaSetの一覧の取得
kubectl get replicasets
Podの確認
kubectl get pods -o wide
ロールアウトの履歴の取得
kubectl rollout history deployment/nginx
ロールアウトのメッセージを追加(rollout historyのメッセージが変わる)
kubectl annotate deployment/nginx kubernetes.io/change-cause="initial deployment"
デプロイの確認(Wideオプション)
kubectl get deployment -o wide
デプロイのスケールアウト
kubectl scale deployment/nginx --replicas=10; watch kubectl get pods -o wide
YAMLでReplica数を変更後反映する
kubectl apply -f nginx-deployment.yaml; watch kubectl get pods -o wide
デプロイの戦略をYAMLで見る
kubectl get deployment/nginx -o yaml | more
YAMLのimageをnginx:stableに変更したのち、ロールアウトを表示。ロールアウト後にkubectl get replicasetで古いReplicasetが0/0になっている。
kubectl apply -f nginx-deployment.yaml && kubectl rollout status deployment/nginx
ロールアウトのコメントをつける
kubectl annotate deployment/nginx kubernetes.io/change-cause="change imgae to nginx:stable"
kubectl rollout history deployment/nginx
コマンドラインからロールアウト
kubectl set image deployment/nginx nginx=nginx:alpine && kubectl rollout status deployment/nginx
kubectl annotate deployment/nginx kubernetes.io/change-cause="change imgae to nginx:alpine"
kubectl rollout history deployment/nginx
ロールアウト時のPodの様子
kubectl set image deployment/nginx nginx=nginx:perl && watch kubectl get pods -o wide
kubectl annotate deployment/nginx kubernetes.io/change-cause="change imgae to nginx:perl"
ロールアウト失敗時(存在しないタグを設定)。describe deploymentで古いReplicasetのIDが参照されているのがわかる。
kubectl set image deployment/nginx nginx=nginx:bananas && watch kubectl get pods -o wide
kubectl annotate deployment/nginx kubernetes.io/change-cause="change imgae to nginx:bananas - failed"
kubectl describe deployment/nginx
ロールアウトの巻き戻し(上のはImagePullBackOffをずっとやっている)。巻き戻し後はRevision 4がRevision 6になる。
kubectl rollout undo deployment/nginx && kubectl rollout status deployment/nginx
特定のリビジョンへの巻き戻し(rollout historyでは、リビジョンが2,3,5,6,7になっているはず)
kubectl rollout undo deployment/nginx --to-revision=1 && kubectl rollout status deployment/nginx
デプロイの削除
kubectl delete deployment/nginx --now
Kubernetes Services
デプロイの作成(nginxのデバッグ用のイメージ)
# YAML確認
kubectl create deployment nginx --image=spurin/nginx-debug --port 80 --replicas=3 -o yaml --dry-run=client
# 本番
kubectl create deployment nginx --image=spurin/nginx-debug --port 80 --replicas=3
ClusterIPとして公開
# YAML確認
kubectl expose deployment/nginx --dry-run=client -o yaml
# 本番
kubectl expose deployment/nginx
サービスの確認
kubectl get services
エンドポイントの一覧(get servicesと異なり複数IPが出る)
kubectl get endpoints
# 以下に対応
kubectl get pods -o wide
サービスの詳細。エンドポイントに対してcurl可能
kubectl describe service/nginx
curlimagesを使い、KubernetesのサービスのDNS経由でアクセスする
kubectl run --rm -it curl --image=curlimages/curl --restart=Never -- sh
# -- 以下コンテナ内のシェル操作--
curl nginx.default.svc.cluster.local
# デフォルトの検索パス(名前解決)の確認
cat /etc/resolv.conf
# サービス名でnginxでもアクセス可能
curl nginx
exit
NodePortとして公開する(いったんClusterIPは削除する)
kubectl delete service/nginx
kubectl expose deployment/nginx --type=NodePort
ClusterIPの場合、NodeのIPでアクセス可能(最初のコントロールプレーンのNodeのIPが172.19.0.4として)
# ポートの確認(80:30671でフォワードしているのを確認)
kubectl get services
# ノードのIPの確認(例:172.19.0.4)
kubectl get nodes -o wide
# ノードのIP+ポートでアクセス
curl 172.19.0.4:30671
ロードバランサーとして公開する(NodePortは削除)
kubectl delete service/nginx
kubectl expose deployment/nginx --type=LoadBalancer --port 8080 --target-port 80
以下のように出ていたと仮定
root@control-plane:~# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 103m
nginx LoadBalancer 10.43.225.134 172.19.0.2,172.19.0.3,172.19.0.4 8080:31868/TCP 7s
アクセス先の確認(ロードバランサーなので異なるPodに負荷分散されている)
watch --differences "curl 172.19.0.2:31868 2>/dev/null"
Podを1にスケールダウンした場合(worker-1,2がいる場合はバラけてしまうかも)
kubectl scale deployment/nginx --relicas=1; watch --differences "curl 172.19.0.2:31868 2>/dev/null"
スケールアップした場合
kubectl scale deployment/nginx --relicas=3; watch --differences "curl 172.19.0.2:31868 2>/dev/null"
クリーンアップ
kubectl delete deployment/nginx service/nginx
red blueの例の準備
kubectl create deployment nginx-red --image=spurin/nginx-red --port 80
kubectl create deployment nginx-blue --image=spurin/nginx-blue --port 80
kubectl get deployment
kubectl expose deployment/nginx-red
kubectl expose deployment/nginx-blue
DNSレコードの作成
kubectl create service externalname my-service --external-name nginx-red.default.svc.cluster.local
kubectl get service
curlのイメージで確認
kubectl run --rm -it curl --image=curlimages/curl --restart=Never -- sh
# 以下curlのコンテナ内
curl nginx-red
curl nginx-blue
curl my-service # red側になる
# my-service.default.svc.cluster.localが登録されている
nslookup my-service
サービスを編集し、DNSレコードをblue側に変える(別タブなど)
kubectl edit service/my-service
先程のcurl my-serviceを再実行すると、Blue側に変更されている(再起動必要なし)
クリーンアップ
kubectl delete deployment/nginx-blue deployment/nginx-red service/nginx-red service/nginx-blue service/my-service
ヘッドレス(ClusterIPを持たない)Podの作成。YAMLで書き出してspec以下にclusetrIP: Noneを追加する
kubectl create deployment nginx --image=spurin/nginx-debug --replicas=3 --port 80
kubectl expose deployment/nginx --dry-run=client -o yaml --type=ClusterIP | tee headless.yaml
vi headless.yaml
kubectl apply -f headless.yaml
# Cluster-IPがIPを持たない(None)になっている
kubectl get service
ヘッドレスの場合はIPが変わる
kubectl run --rm -it curl --image=curlimages/curl --restart=Never -- sh
# 以下curlコンテナ内の操作
# 実行のたびに変わる
watch nslookup nginx
curl nginx
クリーンアップ
rm headless.yaml
kubectl delete deployment/nginx service/nginx
Kubernetes Jobs
円周率を5000桁計算するジョブ
kubectl create job calculatepi --image=perl:5.34.0 -- "perl" "-Mbignum=bpi" "-wle" "print bpi(5000)"
ジョブの実行を完了するのをリアルタイムで見る
watch kubectl get jobs
ジョブの詳細を取得。完了時刻とか書いてある
kubectl describe job/calculatepi
実際に動いているPodの詳細
kubectl get pods -o wide
Podのログで計算された円周率を確認できる(実際のPod名に合わせる)
kubectl logs calculatepi-bmfzt
ジョブの削除
kubectl delete job/calculatepi
YAMLに吐き出し
kubectl create job calculatepi --image=perl:5.34.0 --dry-run=client -o yaml -- "perl" "-Mbignum=bpi" "-wle" "print bpi(5000)" | tee calculatepi.yaml
KubernetesのJobの設定値を確認
kubectl explain job.spec | more
YAMLのSpecを編集する(completions=20とparallelism=5を追加)
apiVersion: batch/v1
kind: Job
metadata:
creationTimestamp: null
name: calculatepi
spec:
completions: 20
parallelism: 5
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- perl
- -Mbignum=bpi
- -wle
- print bpi(5000)
image: perl:5.34.0
name: calculatepi
resources: {}
restartPolicy: Never
status: {}
並列化して実行してPodの様子を見る(同時には5しか実行されない)
kubectl apply -f calculatepi.yaml && sleep 1 && watch kubectl get pods -o wide
同様にログを見れる
kubectl delete job/calculatepi
cronjobに変えて毎分実行
kubectl create cronjob calculatepi --image=perl:5.34.0 --schedule="* * * * *" -- "perl" "-Mbignum=bpi" "-wle" "print bpi(2000)"
cronjobの一覧
kubectl get cronjob
毎分Podが立ち上がるのを確認
watch kubectl get pods
既存のCronjobのYAMLのSpecを編集する(同様にcompletions=20とparallelism=5を追加)
kubectl edit cronjob/calculatepi
リアルタイム確認
watch kubectl get jobs
クリーンアップ
kubectl delete cronjob/calculatepi
rm calculatepi.yaml
Kubernetes ConfigMaps
ConfigMapの作成
kubectl create configmap colour-configmap --from-literal=COLOUR=red --from-literal=KEY=value
ConfigMapの詳細(Key-Valueで出力される)
kubectl describe configmap/colour-configmap
ConfigMapの削除
kubectl delete configmap/colour-configmap
ファイルからのConfigMapの作成
cat <<EOF > configmap-colour.properties
> COLOUR=green
> KEY=value
> EOF
cat configmap-colour.properties
kubectl create configmap colour-configmap --from-env-file=configmap-colour.properties
ダンプ用のPodの作成
kubectl run --image=ubuntu --dry-run=client --restart=Never -o yaml ubuntu --command bash -- -c 'env; sleep infinity' | tee env-dump-pod.yaml
kubectl apply -f env-dump-pod.yaml
Pod内の環境変数のダンプ
kubectl get pods
kubectl logs ubuntu
これだと先ほど作成したConfigMapが含まれないので、YAMLを編集する(envFrom以下を追加)
vi env-dump-pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
name: ubuntu
spec:
containers:
- command:
- bash
- -c
- env; sleep infinity
image: ubuntu
name: ubuntu
resources: {}
envFrom:
- configMapRef:
name: colour-configmap
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
ConfigMapの適用はPodの再作成が必要。これを実行するとCOLOUR=greenとKEY=valueが登録されている。
kubectl delete -f env-dump-pod.yaml --now; kubectl apply -f env-dump-pod.yaml
kubectl logs ubuntu
値の変更(COLOUR=purple)に変えてみる(Podの再作成が必要)
kubectl edit configmap/colour-configmap
kubectl delete -f env-dump-pod.yaml --now; kubectl apply -f env-dump-pod.yaml
kubectl logs ubuntu
immutable:trueを追加すると値の変更ができなくなる(値を変更しようとするとエラーになる)。Kubernetes 1.21から。
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
COLOUR: purple
KEY: value
immutable: true
kind: ConfigMap
metadata:
creationTimestamp: "2026-01-12T16:21:19Z"
name: colour-configmap
namespace: default
resourceVersion: "2175"
uid: f98413d9-bc22-4b7e-8a9a-4fa5aef357d3
クリーンアップ
kubectl delete pod/ubuntu configmap/colour-configmap --now
rm configmap-colour.properties env-dump-pod.yaml
Kubernetes Secrets
シークレットの作成(YAMLで確認)
kubectl create secret generic colour-secret --from-literal=COLOUR=red --from-literal=KEY=value --dry-run=client -o yaml
シークレットがBase64エンコード値で記録されていることを確認(value=dmFsdWU=)として記録
# dmFsdWU=と表示される
echo -n value | base64
# valueとデコードされる
echo dmFsdWU= | base64 -d
シークレットの作成
kubectl create secret generic colour-secret --from-literal=COLOUR=red --from-literal=KEY=value
シークレットの一覧
kubectl get secrets
特定のシークレットの詳細をYAMLで確認
kubectl get secret/colour-secret -o yaml
ダンプ用のPodを起動するためのYAMLを作成
kubectl run --image=ubuntu --dry-run=client --restart=Never -o yaml ubuntu --command bash -- -c 'env; sleep infinity' | tee env-dump-pod.yaml
env-dum-pod.yamlを編集し、ConfigMapと同様にSecretsを登録
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
name: ubuntu
spec:
containers:
- command:
- bash
- -c
- env; sleep infinity
image: ubuntu
name: ubuntu
resources: {}
envFrom:
- secretRef:
name: colour-secret
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
環境変数のダンプ(base64ではなく、平文で記録されている)
kubectl logs ubuntu
クリーンアップ
kubectl delete pod/ubuntu secret/colour-secret --now
rm env-dump-pod.yaml
Kubernetes Labels
例えばPodを作るためのYAML
# labelsはnginxになることを確認
kubectl run nginx --image=nginx --port 80 -o yaml --dry-run=client
kubectl run nginx --image=nginx --port 80
Portを公開
# labelがnginxになっていることを確認
kubectl expose pod/nginx -o yaml --dry-run=client
kubectl expose pod/nginx
ラベルがnginxのものを選択
kubectl get all --selector run=nginx
3つの異なるラベルのPodを作成
YAML=$(kubectl run --image=ubuntu ubuntu -o yaml --dry-run=client --command sleep infinity)
echo -e "${YAML}\n---\n${YAML}\n---\n${YAML}" | tee coloured_pods.yaml
YAMLのcolourラベルを追加し、名前を変える
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
colour: red
name: ubuntu-red
spec:
containers:
- command:
- sleep
- infinity
image: ubuntu
name: ubuntu
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
---
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
colour: green
name: ubuntu-green
spec:
containers:
- command:
- sleep
- infinity
image: ubuntu
name: ubuntu
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
---
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
colour: pink
name: ubuntu-pink
spec:
containers:
- command:
- sleep
- infinity
image: ubuntu
name: ubuntu
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
Podの作成
kubectl apply -f coloured_pods.yaml
全Podの確認
kubectl get pods -o wide
色でセレクト
kubectl get all --selector colour=green
kubectl get all --selector colour=red
クリーンアップ
kubectl delete -f coloured_pods.yaml --now
kubectl delete pod/nginx --now
rm coloured_pods.yaml
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー
