Kubernetesは、コンテナ化されたアプリケーションのデプロイ、スケーリング、管理を自動化するオープンソースプラットフォームです。本記事では、Kubernetesの基本から実践的な運用までを解説します。
Kubernetesアーキテクチャ
クラスタ構成
flowchart TB
subgraph ControlPlane["Control Plane"]
API["API Server"]
Sched["Scheduler"]
CM["Controller Manager"]
etcd["etcd<br/>(データストア)"]
end
subgraph WorkerNodes["Worker Nodes"]
subgraph Node1["Node 1"]
kubelet1["kubelet"]
proxy1["kube-proxy"]
runtime1["Container Runtime<br/>(containerd)"]
Pod1["Pod"]
Pod2["Pod"]
end
subgraph Node2["Node 2"]
kubelet2["kubelet"]
proxy2["kube-proxy"]
runtime2["Container Runtime<br/>(containerd)"]
Pod3["Pod"]
Pod4["Pod"]
end
end
ControlPlane -->|kubelet通信| WorkerNodes
主要コンポーネント
| コンポーネント | 役割 |
|---|---|
| API Server | クラスタへのすべてのAPIリクエストを処理 |
| etcd | クラスタの状態を保存する分散KVストア |
| Scheduler | Podを適切なノードに配置 |
| Controller Manager | 各種コントローラを実行(ReplicaSet, Deployment等) |
| kubelet | ノード上でPodを管理 |
| kube-proxy | ネットワークプロキシ、サービスの負荷分散 |
ローカル環境のセットアップ
minikubeのインストール
# macOS (Homebrew)
brew install minikube
# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Windows (winget)
winget install Kubernetes.minikube
# クラスタの起動
minikube start --driver=docker --cpus=4 --memory=8192
# ステータス確認
minikube status
# Kubernetesダッシュボードの起動
minikube dashboard
kindのインストール(代替)
# Kubernetes IN Docker - より軽量な選択肢
# macOS/Linux
brew install kind
# クラスタ作成(マルチノード)
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# クラスタ一覧
kind get clusters
# クラスタ削除
kind delete cluster
kubectlの設定
# インストール
brew install kubectl
# コンテキスト確認
kubectl config get-contexts
# コンテキスト切り替え
kubectl config use-context minikube
# クラスタ情報確認
kubectl cluster-info
kubectl get nodes
基本的なリソース
Pod
# pod.yaml - 最小デプロイ単位
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
environment: development
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
# Podの操作
kubectl apply -f pod.yaml
kubectl get pods
kubectl describe pod nginx-pod
kubectl logs nginx-pod
kubectl exec -it nginx-pod -- /bin/bash
kubectl delete pod nginx-pod
Deployment
# deployment.yaml - アプリケーションのデプロイメント
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: myapp:1.0.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: web-app
topologyKey: kubernetes.io/hostname
# Deploymentの操作
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods -l app=web-app
# スケーリング
kubectl scale deployment web-app --replicas=5
# ローリングアップデート
kubectl set image deployment/web-app web-app=myapp:2.0.0
# ロールバック
kubectl rollout undo deployment/web-app
kubectl rollout history deployment/web-app
kubectl rollout status deployment/web-app
Service
# service.yaml - サービス公開
apiVersion: v1
kind: Service
metadata:
name: web-app-service
spec:
type: ClusterIP # ClusterIP, NodePort, LoadBalancer
selector:
app: web-app
ports:
- name: http
port: 80
targetPort: 3000
protocol: TCP
---
# NodePortサービス(外部アクセス用)
apiVersion: v1
kind: Service
metadata:
name: web-app-nodeport
spec:
type: NodePort
selector:
app: web-app
ports:
- port: 80
targetPort: 3000
nodePort: 30080
---
# LoadBalancerサービス(クラウド環境用)
apiVersion: v1
kind: Service
metadata:
name: web-app-lb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
type: LoadBalancer
selector:
app: web-app
ports:
- port: 80
targetPort: 3000
Ingress
# ingress.yaml - HTTPルーティング
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
# Ingress Controllerのインストール(minikube)
minikube addons enable ingress
# Ingress確認
kubectl get ingress
kubectl describe ingress web-app-ingress
設定管理
ConfigMap
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# 単純なキー・バリュー
LOG_LEVEL: "info"
API_TIMEOUT: "30s"
# ファイルとしてマウント
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# JSON設定
config.json: |
{
"database": {
"host": "postgres",
"port": 5432
},
"cache": {
"enabled": true,
"ttl": 3600
}
}
# ConfigMapの使用例
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-config
spec:
template:
spec:
containers:
- name: app
image: myapp:1.0
# 環境変数として注入
envFrom:
- configMapRef:
name: app-config
# 個別の環境変数
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# ボリュームとしてマウント
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: nginx.conf
- key: config.json
path: config.json
Secret
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
# Base64エンコード
database-url: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0Bsb2NhbGhvc3Q6NTQzMi9teWRi
api-key: c3VwZXJzZWNyZXRhcGlrZXk=
stringData:
# プレーンテキスト(自動でBase64エンコード)
jwt-secret: my-super-secret-jwt-key
---
# Docker Registry認証用Secret
apiVersion: v1
kind: Secret
metadata:
name: docker-registry-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6ey...
# Secretの作成(コマンドライン)
kubectl create secret generic app-secrets \
--from-literal=database-url='postgresql://user:pass@localhost:5432/mydb' \
--from-literal=api-key='supersecretapikey'
# ファイルからSecret作成
kubectl create secret generic tls-secret \
--from-file=tls.crt=./server.crt \
--from-file=tls.key=./server.key
# Secret確認(値はマスク)
kubectl get secrets
kubectl describe secret app-secrets
永続化ストレージ
PersistentVolume と PersistentVolumeClaim
# storage.yaml
# PersistentVolume(クラスタ管理者が作成)
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: standard
hostPath: # ローカル開発用
path: /data/postgres
---
# PersistentVolumeClaim(開発者が要求)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
---
# StorageClass(動的プロビジョニング)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
StatefulSet(データベース用)
# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secrets
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: password
- name: POSTGRES_DB
value: myapp
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 20Gi
---
# Headless Service for StatefulSet
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
実践的な構成例
完全なWebアプリケーション構成
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
name: production
---
# resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
---
# limitrange.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
- default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
type: Container
# complete-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: myapp/frontend:1.0
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
serviceAccountName: backend-sa
containers:
- name: backend
image: myapp/backend:1.0
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
- name: REDIS_URL
value: "redis://redis:6379"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
---
# Services
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: production
spec:
selector:
app: frontend
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: production
spec:
selector:
app: backend
ports:
- port: 3000
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: production
spec:
selector:
app: redis
ports:
- port: 6379
---
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
number: 3000
監視とデバッグ
kubectl デバッグコマンド
# Pod一覧(詳細)
kubectl get pods -o wide -n production
# リソース使用状況
kubectl top nodes
kubectl top pods -n production
# Pod詳細
kubectl describe pod <pod-name> -n production
# ログ確認
kubectl logs <pod-name> -n production
kubectl logs <pod-name> -c <container-name> # マルチコンテナ
kubectl logs -f <pod-name> # リアルタイム
kubectl logs --previous <pod-name> # 前回のコンテナ
# Pod内でコマンド実行
kubectl exec -it <pod-name> -- /bin/sh
kubectl exec -it <pod-name> -c <container-name> -- /bin/sh
# ポートフォワード
kubectl port-forward <pod-name> 8080:80
kubectl port-forward svc/<service-name> 8080:80
# イベント確認
kubectl get events -n production --sort-by='.lastTimestamp'
# リソースのYAML出力
kubectl get deployment <name> -o yaml
Horizontal Pod Autoscaler
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
# HPA確認
kubectl get hpa -n production
kubectl describe hpa backend-hpa -n production
Helmによるパッケージ管理
Helmの基本
# Helmインストール
brew install helm
# リポジトリ追加
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# チャート検索
helm search repo nginx
# チャートインストール
helm install my-nginx bitnami/nginx
# カスタム値でインストール
helm install my-nginx bitnami/nginx \
--set service.type=ClusterIP \
--set replicaCount=3
# values.yamlを使用
helm install my-nginx bitnami/nginx -f values.yaml
# アップグレード
helm upgrade my-nginx bitnami/nginx -f values.yaml
# ロールバック
helm rollback my-nginx 1
# アンインストール
helm uninstall my-nginx
# リリース一覧
helm list
カスタムChartの作成
# チャートの雛形作成
helm create myapp
myapp/
├── Chart.yaml # チャートメタデータ
├── values.yaml # デフォルト値
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── hpa.yaml
│ ├── _helpers.tpl # テンプレートヘルパー
│ └── NOTES.txt # インストール後のメッセージ
└── charts/ # 依存チャート
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if .Values.env }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
# values.yaml
replicaCount: 3
image:
repository: myapp/backend
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 3000
ingress:
enabled: true
className: nginx
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1000m"
env:
NODE_ENV: production
LOG_LEVEL: info
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
まとめ
Kubernetesは、コンテナオーケストレーションの標準となっています。
学習ステップ
| ステップ | 内容 |
|---|---|
| 1. 基礎 | Pod, Deployment, Service |
| 2. 設定 | ConfigMap, Secret |
| 3. ストレージ | PV, PVC, StatefulSet |
| 4. ネットワーク | Ingress, NetworkPolicy |
| 5. 運用 | HPA, Helm, 監視 |
ベストプラクティス
- リソース制限の設定: requests/limitsを必ず設定
- ヘルスチェック: liveness/readinessProbeの実装
- ラベル活用: 一貫したラベリング戦略
- Namespace分離: 環境やチームごとに分離
- GitOps: マニフェストのバージョン管理
Kubernetesを習得することで、スケーラブルで信頼性の高いアプリケーション運用が可能になります。