はじめに
昨今の流れとして、システム開発においてローカル環境ではDocker、開発・本番環境は、ECS、EKS等を触る開発者は多いんじゃないでしょうか!
そんな自分がこんなことを思いました。
-
k8s
ディレクトリにパッと見てわからないyamlファイルによってKubernetesの環境がセットアップされているな - 開発環境のメモリがひっ迫してる!とか言ってるけどなんでそんなことが起きるのかわからんけど、とりあえず
kubectl delete deployment {deploymentName}
って言われてるからしてみたけど結局何したかったんだっけ
のように、Kubernetesを使っているというのはわかっているが、
- そもそもKubernetesってなんだっけ
- コマンドは理解しているけど、それって結局何を表示してるんだっけ
そんな自分の疑問を解消するために今回は記事を作成しました!
電車の中で次の駅にいくまでに軽く読んでもらえるとうれしいです!
Kubernetesは、略称としてはk8sとも呼ばれており、由来としては、頭文字Kと末尾のsの間に8文字
あるため。
(本記事でも下記よりk8sと略します。)
簡単な自己紹介
- エンジニア2年目
- Go / TypeScriptをメイン
- Dockerの概要は把握済み
- k8sは開発中にコマンドを叩いて、実行とログの見方は把握済み
- AWSとかのインフラ系はなんとなくくらいしかわからない
ゴール
「k8sとは」 を説明できること
対象読者
- コンテナ・イメージという言葉がある程度頭の中に思い浮かぶ方
- k8sについての概要を喋れるようになりたい方
実行環境
- Ubuntu 22.04.5 LTS
- kind v0.22.0 go1.20.13 linux/amd64
- Docker version 28.1.1, build 4eba377
- Kubectl
- Client Version: v1.29.15
- Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
- Server Version: v1.29.2
1. k8sってそもそも何?何がしたいの?
k8sの目的は、
「理想の状態を宣言するだけで、システムを自動で保ち続けること」
上記の目的を達成するために、k8sでは、以下のような機能が提供されています。
課題 | 機能提供 |
---|---|
サービスが落ちたらどうする? | 自動復旧するよ(再スケジュール、再起動) |
リクエストが増えたら? | 自動スケーリングでPodを増やすよ |
アップデートしたいけど止めたくない | ローリングアップデート、ロールバック |
チームで環境を統一したい | 全構成をyamlで宣言(IaC) |
サーバー台数が増えた | スケジューラーが自動で分散配置するよ |
マルチ環境(開発・本番)で差異が出ちゃう! | 再現性のある構成管理でどこでも同じ動作に! |
また、目的を達成する手段としてコンテナ技術との相性がよかったため、k8sではコンテナ技術を用いることになりました。
下記がコンテナ技術の得意なことをまとめた表となります。
ゴール | コンテナが得意なこと |
---|---|
環境を再現可能にしたい | コンテナは常に同じ環境を再構成できる |
瞬時に起動・停止したい | VMよりはるかに高速に扱える |
小さな構成単位で分けたい | アプリ単位に細かくデプロイできる |
分散運用したい | ネットワーク越しでも一貫して管理できる |
そのため、k8sを一言で表すと、
- コンテナの管理を行うソフトウェア
- コンテナのオーケストレーションソフトウェア
と言われる理由となっています。
2. 用語解説編
これから紹介する単語の意味を下記の表にまとめました。
用語 | 解説(一言) |
---|---|
クラスタ | コンテナ(ノード)のまとまり |
コントロールプレーン | 司令塔。クラスタ全体を管理する |
ワーカーノード | 作業者。アプリケーションの実行場所 |
ポッド - Pod | 最小の実行単位。複数コンテナを中に入れられる |
ネームスペース - Namespace | クラスタ内部の空間わけ |
デプロイメント - Deployment | Podの理想状態を宣言する |
サービス - Service | Podへの通信経路を提供する |
クラスタ
複数ノードをまとめて管理するための単位のこと。
目的
「コンテナ化されたアプリケーションを、安定して自動的に動かし続けるための土台を提供すること」
コントロールプレーンやワーカーノードは、このクラスタという“くくり”の中で役割分担しながら協調動作する。
関係性は下記のとおり。
クラスタ
|
├── コントロールプレーン
└── ワーカーノード
コントロールプレーンとワーカーノード
コントロールプレーン(司令塔)
k8sクラスタ全体を管理・制御すること
ワーカーノード(作業者)
実際にアプリケーションを動作させること
このように役割を2つに分けることによって
- 役割分担による責務の明確化
- 安定性・可用性の確保
- スケーラビリティの確保
を確保するようにしているそうです。
結局何がいいかは、
- アプリケーション側に問題があったとしても、制御側が守られる
-
ワーカーノードを簡単に増減させることも容易
ということが言えます。
コントロールプレーンとワーカーノードの構成要素
[コントロールプレーン]
構成要素 | 役割 |
---|---|
kube-apiserver | すべての操作を受け付けるKubernetesのフロントAPI。CLIや他コンポーネントはここにアクセスする。 |
etcd | Kubernetesの全設定情報・状態情報を保存する分散キーバリューストア。超重要なデータベース。 |
kube-scheduler | 新しく作られたPodを「どのノードに配置するか」自動で決定。 |
kube-controller-manager | 状態を維持する各種コントローラー(例:NodeController, ReplicationController)を統合して動かす。 |
cloud-controller-manager(任意) | クラウド特有の処理(例:LB設定、ボリューム作成)を切り離して制御。クラウド連携に使う。 |
[ワーカーノード]
構成要素 | 役割 |
---|---|
kubelet | 各ノード上でPodを管理するエージェント。APIServerから指示を受けてコンテナを起動・監視。各ノードで常駐する「システムプロセス」 |
kube-proxy | サービス(Service)への通信を各Podにルーティング。iptablesやIPVSで制御。 |
Container Runtime | 実際にコンテナを起動・停止するソフト。Kubernetesはこれを通じてコンテナを実行。 |
となります。
実際にこれらの構成要素が構築されているかは、コマンドで見ることができます。(下のログは加工したもの)
user@user:~$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
-- コントロールプレーン
kube-system kube-apiserver-kind-control-plane 1/1 Running 0 6d4h
kube-system kube-scheduler-kind-control-plane 1/1 Running 15 (8h ago) 6d4h
kube-system kube-controller-manager-kind-control-plane 1/1 Running 13 (18h ago) 6d4h
kube-system etcd-kind-control-plane 1/1 Running 0 6d4h
-- ワーカーノード
kube-system kube-proxy-n9h7d 1/1 Running 0 6d4h
kube-system coredns-76f75df574-d2qxw 1/1 Running 0 6d4h
kube-system coredns-76f75df574-fjnnm 1/1 Running 0 6d4h
-- kind特有のpod
kube-system kindnet-nqgtx 1/1 Running 0 6d4h
local-path-storage local-path-provisioner-7577fdbbfb-l8hvz 1/1 Running 0 6d4h
クラスタの説明の際に出した関係性の詳細が下記のようになります。
クラスタ
│
├── コントロールプレーン(クラスタ全体の制御を行う司令塔)
│ ├─ kube-apiserver
│ ├─ etcd
│ ├─ kube-scheduler
│ └─ kube-controller-manager
│
└── ワーカーノード(実際にコンテナを実行する場所)
├─ kubelet
├─ kube-proxy
└─ container runtime
ポッド - Pod
k8sでアプリケーションを動かす最小の実行単位のこと。
目的
「複数のコンテナを"一緒に動かすべき1単位"としてまとめて、それを扱えるようにすること」
ここで大事なのが、1つのPod内に複数のコンテナを入れられるというところ。
通常のコンテナ運用(Dockerなど)では、1サービス=1コンテナであり、
それぞれのコンテナが独立して動作するのが一般的だと思います。
Docker単体の場合
システム
├── api-service
│ └── コンテナ: api-service:latest
├── logger-service
│ └── コンテナ: logger:latest
├── db
└── コンテナ: mysql:8.0
一方Podの場合は、
クラスタ
├── api-pod
│ ├── コンテナ: api-service:latest
│ └── コンテナ: logger:latest
├── db-pod
└── コンテナ: mysql:8.0
上記の差分は、api-service
とlogger
がそれぞれ独立しているかapi-pod
というpodの中に属しているかの差になります。
api-service
を増やしたい!ってなったとき
api-service
へのトラフィックが高負荷になった。などが原因で、もう一つコンテナを増やしたいとなった場合、
Docker単体の場合では、
-
api-service
自体をもう一つ増やす - (
logger
をもう一つ増やす) - 増やした
api-service
の向き先を指定する
のような手順が必要になりますが、Podの構成を取っている場合、
-
api-pod
のpod数を増やす
だけで終了します。
Podという単位を用いることによって、スケーリングの際の手間が削減されます。
また、Pod内部では、localhostで通信ができるため、通信トラフィックがPod内部限定に限定されるのもメリットとなります。
ネームスペース - Namespace
k8sにおける「名前空間」を指します。
目的
「名前空間で論理的に区切って管理すること」
例えば、同一クラスタ内で同名のPodやServiceを環境ごとに使いたい場合、利用されます。
1つのクラスタ内部でのNamespaceの切り方
開発用のクラスタ
├── namespace: developer-1
│ ├── pod: api-server
│ └── pod: frontend
├── namespace: developer-2
│ ├── pod: api-server
│ └── pod: frontend
│ └── pod: cli
├── namespace: developer-3
│ ├── pod: api-server
...
上記の例のように、Namespaceでクラスタ内部を区切ることで、
- 同一のPodだとしても複数立てることができる
- 開発者ごとに独立した環境を用意することができる
などがメリットとして享受することができます。
デプロイメント - Deployment
Podの数と状態を自動で管理してくれる仕組みのこと。
目的
「アプリケーションを常に望ましい数・構成・状態で動かし続けること」
ユーザーが定義した理想状態に沿って、Podの数と状態を自動管理してくれます。
どうやって定義するかは下記に示します。
deployment.yamlの例
下記の内容のyamlをkubectl apply -f deployment.yaml
というコマンドを打つことで、選択されているクラスタ内部にDeploymentを作成することができます。
下記は、api-service
のDeploymentを作成する際のサンプルファイルとなります。
apiVersion: apps/v1 # Deploymentリソースを作成するためのAPIバージョン(apps/v1)
kind: Deployment # リソースの種類を宣言 ほかにもPod/Service/ConfigMapなどがある
metadata:
name: api-service # Deploymentの名前(kubectlするときの識別名)
labels:
app: api-service # ラベル。PodやServiceとの紐づけで用いる
spec:
replicas: 3 # Podは3つ起動してねという宣言
selector:
matchLabels: # metadata.labelで指定したものがここに入る。このラベルに一致するPodをこのDeploymentが管理する。
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers: # Podに含めるコンテナ定義
- name: api # コンテナ名
image: my-api:1.0 # イメージ
ports:
- containerPort: 8080 # コンテナ内部でapiが待ち受けているポート。Serviceと連携する際に指定されることが多い
env: # 環境変数として渡す(例:開発or本番など)
- name: ENVIRONMENT # 環境変数名
value: "dev" # 環境変数の値
サービス - Service
Podへの安定した通信経路を提供する仕組みのこと。
目的
「Podの数やIPが変わっても、安定したアクセス経路を提供すること」
k8sでは、Podが再起動されたりスケーリングされるとIPが変わるため、
そのままだと接続先が不安定になります。
Serviceを使えば、一貫した名前・ポートでPodにアクセスできるようになります。
service.yamlの例
下記の内容のyamlをkubectl apply -f service.yaml
というコマンドで適用することで、
Deploymentによって作られた複数のPodに対するエンドポイントを作成できます。
下記は、api-service Pod 群にアクセスするためのService定義ファイルです。
apiVersion: v1 # Serviceリソースを作成するためのAPIバージョン(apps/v1)
kind: Service # リソースの種類を宣言 ほかにもPod/Service/ConfigMapなどがある
metadata:
name: api-service # Serviceの名前。DNS名としても使える
spec:
selector: # どのPodとつなぐかをラベルで指定。ここでは先ほど作成したapi-serviceに接続
app: api-service
ports:
- port: 80 # Serviceが外部から受け付けるポート
targetPort: 8080 # 実際にPodの中で待ち受けているポート番号
type: ClusterIP # 通常の内部通信向け。クラスタ外もしくはインターネット上からアクセスするならNodePortやLoadBalancerを使う
3. k8sの全体像
ここまで用語を理解してきたら、k8sの全体像がぼんやりとわかるようになったのではないでしょうか。
以下は、クラスタ内の構成をNamespaceごとに整理したものです。
kubectl get pods --A
の出力をイメージしながら見ると、わかりやすいかもしれません。
クラスタ
├── namespace: kube-system/
│ ├── pod: kube-apiserver-control-plane
│ ├── pod: kube-scheduler-control-plane
│ ├── pod: kube-controller-manager-control-plane
│ ├── pod: etcd-control-plane
│ ├── pod: kube-proxy
│ ├── pod: coredns
│ └── pod: kindnet
│
├── namespace: dev/
│ ├── pod: api-service
│ └── pod: logger
│
├── namespace: prod/
│ ├── pod: api-service
│ └── pod: logger
4. k8s環境でよく使うコマンド
コマンドの目的 / 説明 | コマンド例 |
---|---|
現在のクラスタ情報を表示 | kubectl cluster-info |
ノード一覧の確認 | kubectl get nodes |
全NamespaceのPodを一覧表示 | kubectl get pods --all-namespaces |
現在のコンテキスト(クラスタ)を確認 | kubectl config current-context |
DeploymentやServiceなどを適用 | kubectl apply -f <ファイル名> |
リソースを削除 |
kubectl delete -f <ファイル名> , kubectl delete <リソースの種類> <リソース名>
|
Deployment、Service、Podの一覧 |
kubectl get deployments , kubectl get services , kubectl get pods
|
詳細な情報を確認(イベントやエラーなど) | kubectl describe <リソースの種類> <リソース名> |
Podのログを確認 | kubectl logs -f <Pod名> |
Pod内部に入るコマンド | kubectl exec -it <Pod名> -- <シェルコマンド> |
Podの数を変更(Deployment単位) | kubectl scale deployment <Deployment名> --replicas=<数> |
Namespaceの一覧を取得 | kubectl get namespaces |
特定NamespaceのPod一覧 | kubectl get pods -n <Namespace名> |
現在のクラスタ情報を表示
kubectl cluster-info
user@user:~$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:46603
CoreDNS is running at https://127.0.0.1:46603/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
user@user:~$
ノード一覧の確認
kubectl get nodes
user@user:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 7d2h v1.29.2
user@user:~$
全NamespaceのPodを一覧表示
kubectl get pods --all-namespaces
user@user:~$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default api-7649b9df7c-sfqdf 1/1 Running 0 7d2h
default cli-6bc58b99f5-km86s 1/1 Running 0 7d2h
default frontend-5c499498dd-vc5r2 1/1 Running 0 7d2h
kube-system coredns-76f75df574-d2qxw 1/1 Running 0 7d2h
kube-system coredns-76f75df574-fjnnm 1/1 Running 0 7d2h
kube-system etcd-kind-control-plane 1/1 Running 0 7d2h
kube-system kindnet-nqgtx 1/1 Running 0 7d2h
kube-system kube-apiserver-kind-control-plane 1/1 Running 0 7d2h
kube-system kube-controller-manager-kind-control-plane 1/1 Running 16 (91m ago) 7d2h
kube-system kube-proxy-n9h7d 1/1 Running 0 7d2h
kube-system kube-scheduler-kind-control-plane 1/1 Running 18 (91m ago) 7d2h
local-path-storage local-path-provisioner-7577fdbbfb-l8hvz 1/1 Running 0 7d2h
user@user:~$
現在のコンテキスト(クラスタ)を確認
kubectl config current-context
user@user:~$ kubectl config current-context
kind-kind
user@user:~$
DeploymentやServiceなどを適用
kubectl apply -f deployment.yaml
user@user:~/Documents/workspace/k8s$ kubectl apply -f deployment.yaml
deployment.apps/api-service created
user@user:~/Documents/workspace/k8s$
kubectl apply -f service.yaml
user@user:~/Documents/workspace/k8s$ kubectl apply -f service.yaml
service/api-service created
user@user:~/Documents/workspace/k8s$
リソースを削除
kubectl delete -f deployment.yaml
user@user:~/Documents/workspace/k8s$ kubectl delete -f deployment.yaml
deployment.apps "api-service" deleted
user@user:~/Documents/workspace/k8s$
kubectl delete pod <pod-name>
user@user:~/Documents/workspace/k8s$ kubectl delete pod api-service-6d57cc4f85-fgz5x
pod "api-service-6d57cc4f85-fgz5x" deleted
user@user:~/Documents/workspace/k8s$
Deployment、Service、Podの一覧
kubectl get deployments
user@user:~/Documents/workspace/k8s$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
api 1/1 1 1 7d2h
cli 1/1 1 1 7d2h
frontend 1/1 1 1 7d2h
user@user:~/Documents/workspace/k8s$
kubectl get services
user@user:~/Documents/workspace/k8s$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api ClusterIP 10.244.1.15 <none> 443/TCP 7d2h
cli ClusterIP 10.244.1.16 <none> 4401/TCP 7d2h
frontend ClusterIP 10.244.1.17 <none> 3000:32000/TCP 7d2h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d2h
user@user:~/Documents/workspace/k8s$
kubectl get pods
user@user:~/Documents/workspace/k8s$ kubectl get pods
NAME READY STATUS RESTARTS AGE
api-7649b9df7c-sfqdf 1/1 Running 0 7d2h
cli-6bc58b99f5-km86s 1/1 Running 0 7d2h
frontend-5c499498dd-vc5r2 1/1 Running 0 7d2h
user@user:~/Documents/workspace/k8s$
詳細な情報を確認(イベントやエラーなど)
kubectl describe pod <pod-name>
user@user:~/Documents/workspace/k8s$ kubectl describe pod api-service-5d9b6c7b77-abcde
Name: api-service-5d9b6c7b77-abcde
Namespace: dev
Priority: 0
Node: worker-node-1/10.1.2.3
Start Time: Mon, 13 May 2025 10:05:00 +0900
Labels: app=api-service
Status: Running
IP: 10.244.1.15
Containers:
api:
Container ID: docker://a1b2c3...
Image: my-api:1.0
Port: 8080/TCP
State: Running
Started: Mon, 13 May 2025 10:05:02 +0900
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Events: <none>
user@user:~/Documents/workspace/k8s$
kubectl describe deployment <deployment-name>
user@user:~/Documents/workspace/k8s$ kubectl describe deployment api-service
Name: api-service
Namespace: dev
CreationTimestamp: Mon, 13 May 2025 10:00:00 +0900
Labels: app=api-service
Selector: app=api-service
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
Containers:
api:
Image: my-api:1.0
Port: 8080/TCP
Environment:
ENVIRONMENT: dev
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Events: <none>
user@user:~/Documents/workspace/k8s$
Podのログを確認
-f
は--follow
の略であり、ログをリアルタイムで追いかけるオプション。
-f
を入れない場合は、現在までのログを一回分だけ出力するようになる。
kubectl logs -f <pod-name>
Pod内部に入るコマンド
/bin/sh
の部分はそれぞれのイメージ事に設定してください。
kubectl exec -it <pod-name> -- /bin/sh
Podの数を変更(Deployment単位)
kubectl scale deployment api-service --replicas=5
user@user:~/Documents/workspace/k8s$ kubectl scale deployment api-service --replicas=5
deployment.apps/api-service scaled
user@user:~/Documents/workspace/k8s$
Namespaceの一覧を取得
kubectl get namespaces
user@user:~/Documents/workspace/k8s$ kubectl get namespaces
NAME STATUS AGE
default Active 7d2h
kube-node-lease Active 7d2h
kube-public Active 7d2h
kube-system Active 7d2h
local-path-storage Active 7d2h
user@user:~/Documents/workspace/k8s$
特定NamespaceのPod一覧
-A
→ --all-namespaces
のオプションとなり、全てのNamespaceのPodを出力できる。
kubectl get pods -n <<namespace名>>
user@user:~/Documents/workspace/k8s$ kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
api-7649b9df7c-sfqdf 1/1 Running 0 7d2h
cli-6bc58b99f5-km86s 1/1 Running 0 7d2h
frontend-5c499498dd-vc5r2 1/1 Running 0 7d2h
user@user:~/Documents/workspace/k8s$
5. k8sのメリット・デメリット
k8sを利用する際のメリット・デメリットは以下のようになります。
項目 | 内容 |
---|---|
メリット | - 自動化・可用性・拡張性が高い - コンテナを理想の数・状態で維持してくれる - 開発から本番まで同じ構成が使える |
デメリット | - 学習コストが高い - 構成に柔軟性があるため、リソース設定を誤るとAWS,GCPなどのクラウドサービスではコストが爆増する危険がある |
メリットに関しては、本記事内部で多数紹介しましたが、デメリットに関しては、ここまで記事を読んだ方であれば、k8sを使うのにも前提知識として用語や思想を知らないと使えはするが、知っているとはならないと感じたはずです。
また、deployment.yaml
, service.yaml
で記述したように、Pod内部での通信や、Pod外からの通信のポート解放、それ以上のネットワークの知識を求められることも多いため、デメリットとして上げさせていただきました。
6. まとめ
ここまで読んできてk8sとは何か。 を説明する材料になったでしょうか!
電車の中で読みきれるほどの文章ではなかった気がする。
簡単にまとめると、
- 理想の状態を示すと、システムを自動でその状態に保ち続けてくれる
- その目的を達成するためにk8sはスケーリングや、Podの再起動などの機能が搭載されている
- 理想状態は、yamlで記述する
- k8sがコンテナを使っている理由は、起動・停止が高速で、環境再現性が高いなどの理由
参考になっていれば幸いです!