【4-7】Kubernetes実践編:Namespace, Label/Annotation & 完全なアプリスタック構築
Kubernetes実践編:Namespace, Label/Annotation & 完全なアプリスタック構築
はじめに
Kubernetes入門の旅も、いよいよ最終章です。
これまで私たちは、Pod、Deployment、Service、ConfigMap、Secret、PV/PVC、StatefulSetといったKubernetesの核心的なリソースを一つずつ学び、コンテナ化されたアプリケーションを動かし、ネットワークを繋ぎ、設定を外部化し、データを永続化する方法をマスターしてきました。
しかし、実際のプロジェクトでは、開発・ステージング・本番といった複数の環境を管理したり、大量のリソースを整理したりする必要が出てきます。
この最終回では、Kubernetesクラスターを仮想的に分割する Namespace、リソースに 「付箋」 を貼って整理する Label と 「メモ」 を書き込む Annotation を学びます。
そして最後に、これまでの全ての知識を結集して、より本番に近い構成のWordPressアプリケーションスタックをゼロから構築します。
Part 1: Namespace - クラスター内の仮想的な仕切り
Namespaceは、1つの物理的なKubernetesクラスターを、複数の仮想的なクラスターに分割するための仕組みです。
なぜ必要?
-
名前の衝突回避: チームAとチームBが、どちらも
web-appという名前のDeploymentを作っても、Namespaceが違えば衝突しません(team-a/web-appとteam-b/web-appのように区別される) -
環境分離:
development,staging,productionのようにNamespaceを分けることで、環境ごとのリソースを明確に分離・管理できます - アクセス制御: Namespace単位で「誰がどのリソースを触れるか」という権限(RBAC)を設定できます
Step 1: Namespaceの作成と操作
# 作業ディレクトリ準備
cd ~/k8s-practice
mkdir namespace-practice
cd namespace-practice
# コマンドでのNamespace作成
k create namespace development
k create namespace staging
k create namespace production
# YAMLでのNamespace作成 (ラベルも付与)
cat > namespace-qa.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: qa
labels:
environment: qa
EOF
# YAMLを適用して作成
k apply -f namespace-qa.yaml
# Namespace一覧を確認
k get namespaces --show-labels
Step 2: Namespace内でのリソース管理
リソースを作成する際、metadata.namespaceを指定します。
実際にdevelopmentとproductionのNamespaceに、それぞれ異なる設定のWebアプリをデプロイしてみましょう。
# development Namespace用のアプリを作成
cat > app-development.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: development # <- Namespaceを指定
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:alpine
---
apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: development # <- Namespaceを指定
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30081
EOF
# YAMLを適用して作成
k apply -f app-development.yaml
# 特定Namespace内のリソースを確認するには `-n` オプションを使う
k get all -n development
# ブラウザでアクセス確認
http://192.168.3.101:30081
同様にproduction Namespaceにもアプリをデプロイできます(nodePortは30082に変更するなど重複を避ける)。
# developmentをproductionに、env: devをenv: prodに、
# NodePortを30081から30082に置換して別ファイルに保存
sed 's/development/production/g; s/dev/prod/g; s/30081/30082/g' app-development.yaml > app-production.yaml
# production用YAMLを適用
k apply -f app-production.yaml
# production Namespace内のリソースを確認
k get all -n production
# ブラウザでアクセス確認: http://192.168.3.101:30082
同じweb-appという名前のDeploymentでも、Namespaceが違うため衝突せずに共存できています。
Part 2: LabelとAnnotation - リソースに情報を付与する
リソースが増えてくると、「本番環境のWebサーバーだけ表示したい」「バージョンv2のPodだけ再起動したい」といった操作が必要になります。それを可能にするのがLabelです。
1. Label(ラベル):識別のための「付箋」
役割: リソース(Pod, Serviceなど)を識別・分類するためのキーと値のペアです。(例: app: web, tier: frontend, environment: production)
用途: Serviceのselectorや、kubectl -lでの検索・フィルタリングに使われます。
# ラベルを使った検索
k get pods --show-labels
k get pods -l app=web # appがwebのPod
k get pods -l environment=production # environmentがproductionのPod
k get pods -l app=web,tier=frontend # app=web かつ tier=frontend のPod
# 後からラベルを追加
k label pod web-frontend-v1 release=stable
2. Annotation(アノテーション):補足情報の「メモ書き」
役割: リソースの識別に使うのではなく、人間や外部ツール向けの補足情報(メタデータ) を付与するためのキーと値のペアです。
用途: 管理者の連絡先、ビルド番号、ドキュメントURL、監視ツール用の設定などを記述します。
# 起動中のPodにAnnotationを追加
k annotate pod web-frontend-v1 \
owner="platform-team" \
last-updated="$(date +%Y-%m-%d)"
# describeでAnnotationsセクションを確認
k describe pod web-frontend-v1 | grep -A5 Annotations
YAMLで定義する例:
apiVersion: v1
kind: Pod
metadata:
name: annotated-pod
labels:
app: web
annotations:
description: "Demo pod with extensive metadata"
contact: "devops@example.com"
monitoring.prometheus.io/scrape: "true"
spec:
# ...
Labelは「検索用」、Annotationは「メモ用」 と覚えておきましょう。
Part 3: グランドフィナーレ - 完全なWordPressスタック構築
いよいよ、これまでの学習内容(Namespace, ConfigMap, Secret, StatefulSet(DB), Deployment(Web), Service, PVC)を全て統合し、app-prodという専用Namespace内に、本番運用に近いWordPress環境を構築します。
# 作業ディレクトリ準備
cd ~/k8s-practice
mkdir full-app-stack
cd full-app-stack
Step 1: Namespace作成 (01-namespace.yaml)
cat > 01-namespace.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: app-prod
labels:
environment: production
EOF
k apply -f 01-namespace.yaml
Step 2: ConfigMap & Secret作成 (02-config-secret.yaml)
app-prod Namespace内に作成します。SecretではstringDataを使うとBase64エンコードせずに書けて便利です。
cat > 02-config-secret.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: app-prod
data:
APP_ENV: "production"
LOG_LEVEL: "info"
CACHE_ENABLED: "true"
---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: app-prod
type: Opaque
# stringDataを使うとBase64エンコードせずに平文で書ける(裏で自動エンコードされる)
stringData:
username: "produser"
password: "SecureProdP@ss123"
database: "proddb"
EOF
k apply -f 02-config-secret.yaml
Step 3: MySQL StatefulSet & Headless Service (03-mysql.yaml)
app-prod Namespace内に作成し、Secretから認証情報を注入します。tier: databaseラベルも付与します。
cat > 03-mysql.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: app-prod
spec:
ports:
- port: 3306
clusterIP: None
selector:
app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: app-prod
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
tier: database # tierラベルを追加
spec:
containers:
- name: mysql
image: mysql:8.0
env:
# SecretからパスワードとDB名を注入
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: MYSQL_DATABASE
valueFrom:
secretKeyRef:
name: db-secret
key: database
# (ユーザー名もSecretから取るのがよりセキュアだが、今回は省略)
- name: MYSQL_USER
value: "produser" # Secretから取るべき
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: local-path
resources:
requests:
storage: 2Gi # 容量を2Giに増量
EOF
k apply -f 03-mysql.yaml
Step 4: WordPress Deployment & NodePort Service (04-wordpress.yaml)
app-prod Namespace内に作成。ConfigMapとSecretから設定を注入し、tier: frontendラベルを付与。DBホスト名には完全修飾ドメイン名(FQDN) を使います。
cat > 04-wordpress.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: app-prod
spec:
replicas: 3 # レプリカ数を3に増やす
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
tier: frontend # tierラベルを追加
spec:
containers:
- name: wordpress
image: wordpress:latest
env:
# ★ NamespaceをまたいだServiceへの接続方法 ★
# Service名.Namespace名.svc.cluster.local という完全修飾ドメイン名(FQDN)を使う
- name: WORDPRESS_DB_HOST
value: mysql.app-prod.svc.cluster.local
# SecretからDB認証情報を注入
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: WORDPRESS_DB_NAME
valueFrom:
secretKeyRef:
name: db-secret
key: database
# ConfigMap全体を環境変数として注入
envFrom:
- configMapRef:
name: app-config
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: app-prod
spec:
type: NodePort
selector:
app: wordpress
ports:
- port: 80
targetPort: 80
nodePort: 30090 # NodePortを変更
EOF
k apply -f 04-wordpress.yaml
Step 5: 全体確認とブラウザアクセス
# app-prod Namespace内の全リソースとPVCを確認
k get all -n app-prod
k get pvc -n app-prod
# Labelを使った検索
k get pods -n app-prod -l tier=frontend
k get pods -n app-prod -l tier=database
# ブラウザでアクセス
# http://192.168.3.101:30090
WordPressの初期設定画面が表示されれば、全ての知識を結集したアプリケーションスタックの構築は成功です! 🎉
まとめ
Kubernetes入門の旅、お疲れ様でした!
最終回では、Namespaceによる環境分離、LabelとAnnotationによるリソース管理、そして全ての知識を統合した実践的なアプリケーション構築を経験しました。
基本リソースを一通りマスターしたあなたは、もうKubernetesの世界への扉を開けました。
ここから先は、より高度な機能(Ingress, Helm, CI/CD連携など)への探求が待っています。この入門で得た知識と経験が、あなたのこれからのクラウドネイティブな旅の確かな土台となることを願っています。
次のステップ
Kubernetesの基礎を習得した今、以下のような学習へと進むことができます:
- Ingress: より高度な外部公開とルーティング
- Helm: パッケージマネージャーによるアプリケーション管理
- CI/CD統合: GitOps、ArgoCD、Jenkins等との連携
- モニタリング: Prometheus、Grafanaによる監視
- 本番クラスター: マルチノード構成の構築
ホームラボでの学習の旅、本当にお疲れ様でした! 🎓
Discussion