本記事は https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests の講座と https://kodekloud.com/ の内容を学習しながら記録したものです。
- 11 Cluster Architecture
- 12 Docker-vs-ContainerD
- 13 ETCD for Beginners
- 14 ETCD in Kubernetes
- 16 Kube API Server
- 17 Kube Controller Manager
- 18 Kube Scheduler
- 19 Kubelet
- 20 Kube Proxy
- 21 Recap - Pods
- 22 Pods with YAML
- 29 Replica Sets
- 32 Deployments
- 36 Services
- 41 Namespaces
- Imperative vs Declarative
11 Cluster Architecture
Master NodeとWorker Nodeが存在します。 どのコンテナが存在し、どのように実行されているかは、ETCDというデータストアに保存されます。
Master NodeとWorker Nodeの関係は以下の図のように表現できます。

Kube API Serverはすべての操作をオーケストレーションし、すべてを監視します。
アプリケーションはコンテナ形式です。DNSもコンテナです。Dockerは最も有名なコンテナランタイムエンジンですが、ランタイムエンジンが必ずしもDockerである必要はありません。
KubeletはWorker Nodeの船長のような存在です。
Kube Proxy Serverは内部サービス間の通信を支援します。

12 Docker-vs-ContainerD
バージョン1でサポートされていたdockershimをバージョン2で廃止することが決定されました。 containerdがインストールされるとctlツールもインストールされます(ユーザーフレンドリーではなく、機能も限定的)。
ctr images pull docker.io/library/redis:alpine
ctr run ...
nerdctlはctrと異なり、DockerライクなCLIツールを提供します。
nerdctl run --name redis redis:alpine
crictlも存在し、Kubernetesプロジェクトで開発されています。 直接使用することはほとんどなく、主にデバッグツールとして使用されます。 kubeletは自身が作成していないコンテナを強制削除できるため、単独で使用する場合は注意が必要です。
13 ETCD for Beginners
etcdctl --version でバージョンを確認できます。通常バージョン2または3です。
Key-Valueストアです。
14 ETCD in Kubernetes
Nodes、Pods、Configs、Secrets、Accounts、Roles、Bindings、Othersに関するすべての情報がETCDに保存されます。
Kubernetesを手動インストールする場合、etcdも手動でインストールする必要があります。
advertise-client-urls のデフォルトポートは2379で、kube-apiserverがetcdに接続するために必要です。
kubeadmでインストールした場合、etcdデーモンがコンテナとして動作していることを確認できます。
sudo kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5d78c9869d-2f2qt 1/1 Running 0 38s
coredns-5d78c9869d-dn7b6 1/1 Running 0 38s
etcd-docker-desktop 1/1 Running 0 38s
kube-apiserver-docker-desktop 1/1 Running 0 38s
kube-controller-manager-docker-desktop 1/1 Running 0 39s
kube-proxy-24tjf 1/1 Running 0 39s
kube-scheduler-docker-desktop 1/1 Running 0 42s
storage-provisioner 1/1 Running 0 37s
vpnkit-controller 1/1 Running 0 37s
高可用性(H/A)構成にすることで、複数のマスターetcdインスタンスを持つことができます。
バージョン2で提供されるコマンド:
etcdctl backup
etcdctl cluster-health
etcdctl mk
etcdctl mkdir
etcdctl set
16 Kube API Server


kube-apiserverはさまざまなパラメータで実行されます。

kubeadmでインストールした場合、/etc/kubernetes/manifests/kube-apiserver.yaml でAPIサーバーのオプションを確認できます。
17 Kube Controller Manager
Controller Managerはノードのステータスを継続的に監視し、問題を解決します。5秒ごとにハートビートを送信します。

Kube-Controller-Managerにはさまざまなマネージャーが含まれています。
kubeadmでインストールした場合、/etc/kubernetes/manifests/kube-controller-manager.yaml でKube-Controller-Managerの設定値を確認できます。
18 Kube Scheduler
- Filter Nodes
- Rank Nodes
スケジューラを独自に作成することも可能です。

/etc/kubernetes/manifests/kube-scheduler.yaml で設定値を確認できます。
19 Kubelet
KubeletはWorker Nodeの船長のような存在です。

20 Kube Proxy
各ノードに1つずつDaemonSetとして実行されます。サービス名からIPアドレスを解決します。

kubectl get daemonset -n kube-system
21 Recap - Pods
アプリケーションはコンテナとして直接デプロイされるのではなく、Podという抽象化された単位でデプロイされます。
Dockerで以下のようにpython-appとhelperを管理するのは非常に手間がかかります。

以下のコマンドでDocker Hubからイメージを取得できます。
$ kubectl run nginx --image nginx
$ kubectl run custom-nginx --image nginx --port=8080
22 Pods with YAML
KubernetesはYAMLファイルを通じてアプリケーションをデプロイします。
apiVersion: v1 | v1 | apps/v1 | apps/v1
kind: POD | Service | ReplicaSet | Deployment
metadata:
name: myapp-pods
labels:
app: myapp
spec:
29 Replica Sets
Podの高可用性を確保するために、Replication Controllerを活用できます。Replication Controllerは常に指定された数以上のPodが動作していることを保証します。また、ユーザー増加に伴うリクエスト増加に対応するため、Pod数をスケールアップする際にも使用されます。

Replication ControllerとReplica Setの2種類があり、区別する必要があります。Replication Controllerは古い技術であり、Replica Setに置き換えられつつあります。
Replication Controller
spec配下の replicas に起動したいPodの数を指定します。
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
kubectl create -f rc-definition.yml コマンドでReplication Controllerを実行すると、以下のような結果が得られます。
$ kubectl create -f replication.yaml
replicationcontroller/nginx created
$ kubectl get replicationcontroller
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 77s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-77b4fdf86c-vhbhl 1/1 Running 0 69d
nginx-9tq9x 1/1 Running 0 92s
nginx-s6p44 1/1 Running 0 92s
nginx-znx2w 1/1 Running 0 92s
Replica Set
ReplicaSet はReplication Controllerと似ていますが、selector フィールドがある点が異なります。apiVersionが apps/v1 であることも違いです。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google-samples/hello-app:2.0
$ kubectl create -f replicaset-definition.yml
replicaset.apps/frontend created
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 24s
nginx-77b4fdf86c 1 1 1 69d
ReplicaSetはPodを監視し、数が指定された数と一致しない場合、自動的にPod数を調整します。複数のPodがある場合、管理対象のPodを識別するためにラベルを付けて管理します。そのため、YAMLファイルで定義する際、ReplicaSetのselectorのラベルとtemplate内のラベルの名前を一致させる必要があります。同じラベル名のPodが既に存在し、Pod数も満たされている場合は新しいPodは作成されないため、ラベル名を指定する際には既に使用されているラベルかどうかを確認する必要があります。

3つのレプリカを持つReplicaSet(上で作成した「frontend」)を6つにスケールアップしたい場合は、以下のようにします。
kubectl get replicaset frontend -o yaml で現在のfrontend ReplicaSetのYAML設定ファイルを取得し、replicasの部分を6に変更して保存した後、kubectl replace -f filename で適用できます。
2つ目の方法はscaleコマンドを使用する方法です。
$ kubectl scale --replicas=6 -f replicaset-definition.yml
replicaset.apps/frontend scaled
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
frontend 6 6 6 14m
nginx-77b4fdf86c 1 1 1 69d
再び3に減らすには、ファイルではなくReplicaSet名を直接指定して以下のように実行できます。
$ kubectl scale --replicas=3 replicaset frontend
replicaset.apps/frontend scaled
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 15m
nginx-77b4fdf86c 1 1 1 69d
32 Deployments
Deployments はReplicaSetと似ています。違いはkindフィールドに ReplicaSet ではなく Deployment を指定する点です。
Podを作成するたびにYAMLを記述するのは面倒です。こういった場合、kubectl runを使うと便利です。 例えば、nginxを実行するDeploymentを作成するYAMLファイルを生成するには、以下のように入力します。
$ kubectl create deployment --image=nginx nginx-deployment --dry-run=client -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
Create a deployment named webapp using the image kodekloud/webapp-color with 3 replicas.
$ kubectl create deployment webapp --image=kodekloud/webapp-color --replicas=3
$ kubectl create deployment redis-deploy --image=redis --replicas=2 --namespace=dev-ns
36 Services
外部ユーザーがPodで実行されているWebサービスにアクセスするにはどうすればよいでしょうか? 基本的に外部ネットワークから内部ネットワークに直接アクセスすることはできません。 ここで必要になるのがServiceです。KubernetesのServiceという概念は、Pods、ReplicaSet、Deploymentsと大きく異なるものではありません。Serviceの特徴は、外部からのリクエストを特定リソースのポートにフォワードする機能を提供することです(NodePort Service)。


Node Ports
NodePortは30000〜32767番のポートのみ使用可能です。

apiVersion: v1
kind: Service
metadata:
name: nodeport-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
nodePort: 30008
selector:
app: guestbook
tier: frontend
$ kubectl create -f node-port-definition.yml
service/nodeport-service created
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 127d
nginx NodePort 10.110.82.18 <none> 80:32381/TCP 70d
nodeport-service NodePort 10.98.44.253 <none> 80:30008/TCP 40s
$ get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
frontend-759fr 1/1 Running 0 39h 10.244.0.5 cubi04 <none> <none>
frontend-98dvd 1/1 Running 0 39h 10.244.0.5 cubi02 <none> <none>
frontend-xpwc5 1/1 Running 0 39h 10.244.0.6 cubi03 <none> <none>
nginx-77b4fdf86c-wwbrb 1/1 Running 0 39h 10.244.0.3 cubi04 <none> <none>
$ curl http://192.168.219.114:32381
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
Services Cluster IP
Kubernetesでは、Podはいつでも別の場所に移動したり再作成されたりする可能性があるため、PodのIPアドレスに依存することはできません。サービス間の通信には、サービスごとに1つ割り当てられるCluster IP(ClusterIPと呼ばれる)を使用する必要があります。

単一のPodに対するClusterIP Serviceの作成方法:
$ kubectl expose pod redis --type=ClusterIP --port=6379 --name=redis-service
Create a pod called httpd using the image httpd:alpine in the default namespace. Next, create a service of type ClusterIP by the same name (httpd). The target port for the service should be 80.
$ kubectl run httpd --image httpd:alpine --port=80 --expose=true
service/httpd created
pod/httpd created
Service LoadBalancer
NodePort Serviceを使用すると、外部から特定のポートを通じてPodにアクセスできますが、Podが10台のノードにまたがって作成されている場合、10個のIP:portの組み合わせが生じます。この場合、どれにアクセスすればよいのでしょうか?
Load Balancerを使用すれば、この問題を解決できます。
41 Namespaces
Kubernetesはkube-system、default、kube-publicの3つのNamespaceを自動的に作成します。本番環境で多くの人が使用する環境では、複数のNamespaceを使用することが推奨されます。
同じNamespace内ではサービス名で検索が可能ですが、異なるNamespaceのサービスにアクセスするには追加のポストフィックスが必要です。

これは、Namespaceが追加されるとDNSエントリが追加されるためです。

$ kubects get pods --namespace=kube-system
# Pod作成時に --namespace=dev を指定してNamespaceを指定できます。
$ kubectl create -f pod-definition.yml --namespace=dev
# または
# YAMLファイル内のmetadata:の下にnamespace: devを追加する方法もあります。
Namespaceの作成
apiVersion: v1
kind: Namespace
metadata:
mame: dev
$ kubectl create -f namespace-dev.yml
$ kubectl create namespace dev
Namespaceの永続的な切り替え
kubectlはデフォルトでdefault Namespaceを使用し、毎回 --namespace=dev を付けるのは面倒です。
以下のようにコンテキストを目的のNamespaceに設定すれば、永続的に変更できます。
$ kubectl config set-context $(kubectl config current-context) --namespace=dev
$ kubectl get pods
# 他のNamespace(例:default)のPodを表示したい場合は、以下のようにします。
$ kubectl get pods --namespace=default
# すべてのNamespaceのPodを表示するには以下のようにします。
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default frontend-759fr 1/1 Running 0 37h
default frontend-98dvd 1/1 Running 0 37h
default frontend-xpwc5 1/1 Running 0 37h
default nginx-77b4fdf86c-wwbrb 1/1 Running 0 37h
kube-flannel kube-flannel-ds-fg8lc 0/1 CrashLoopBackOff 20310 (2m2s ago) 126d
kube-flannel kube-flannel-ds-fvlfs 0/1 CrashLoopBackOff 20310 (66s ago) 126d
kube-flannel kube-flannel-ds-q72cc 0/1 CrashLoopBackOff 20308 (4m29s ago) 126d
kube-flannel kube-flannel-ds-smwgc 0/1 CrashLoopBackOff 20310 (98s ago) 126d
kube-system coredns-5d78c9869d-fd4rg 1/1 Running 1 (125d ago) 126d
kube-system coredns-5d78c9869d-zl7kh 1/1 Running 1 (125d ago) 126d
kube-system etcd-cubi01 1/1 Running 1 (125d ago) 126d
kube-system kube-apiserver-cubi01 1/1 Running 1 (125d ago) 126d
kube-system kube-controller-manager-cubi01 1/1 Running 1 (125d ago) 126d
kube-system kube-proxy-f852g 1/1 Running 1 (125d ago) 126d
kube-system kube-proxy-ngt5z 1/1 Running 1 (125d ago) 126d
kube-system kube-proxy-tjtm6 1/1 Running 1 (125d ago) 126d
kube-system kube-proxy-wfldv 1/1 Running 1 (125d ago) 126d
kube-system kube-scheduler-cubi01 1/1 Running 1 (125d ago) 126d
Namespaceにリソースクォータを設定することもできます。
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 5Gi
limits.cpu: "10"
limits.memory: 10Gi
Imperative vs Declarative
目標に向かって一段階ずつ手続き的(Imperative)に定義する方法と、結果を宣言的(Declarative)に定義する方法があります。Kubernetesは両方をサポートしていますが、後者の方がはるかに便利で、履歴管理が容易なためミスが減ります。Imperativeな方法では、運用者が常に現在の状態を把握している必要があります。

ただし、CKA試験ではImperativeな方法の方が速くて直感的な場合もあります。

クイズ
Q1: 「CKA_2_core_concepts」の主なトピックは何ですか?
CKA_2_core_concepts
Q2: Replication Controllerとは何ですか?
spec配下の replicas に起動したいPodの数を指定します。 kubectl create -f rc-definition.yml
コマンドでReplication Controllerを実行すると、以下のような結果が得られます。
Q3: Replica Setの核心的な概念を説明してください。
ReplicaSet はReplication Controllerと似ていますが、selector
フィールドがある点が異なります。apiVersionが apps/v1 であることも違いです。
ReplicaSetはPodを監視し、数が指定された数と一致しない場合、自動的にPod数を調整します。複数のPodがある場合、管理対象のPodを識別するためにラベルを付けて管理します。そのため、YAMLファイルで定義する際、ReplicaSetのselectorのラベルとtemplate内のラベルの名前を一致させる必要があります。
Q4: Node Portsの主な特徴は何ですか?
NodePortは30000〜32767番のポートのみ使用可能です。
Q5: Services Cluster IPはどのように機能しますか?
Kubernetesでは、Podはいつでも別の場所に移動したり再作成されたりする可能性があるため、PodのIPアドレスに依存することはできません。サービス間の通信には、サービスごとに1つ割り当てられるCluster
IP(ClusterIPと呼ばれる)を使用する必要があります。 単一のPodに対するClusterIP Serviceの作成方法:
Create a pod called httpd using the image httpd:alpine in the default namespace.