【実践Kubernetes】簡単なアプリケーションのデプロイからスケーリングまで
はじめに
Kubernetesの概念を理解したら、次は実際にアプリケーションをデプロイして動作を確認してみましょう。本記事では、Kubernetes公式のゲストブックチュートリアルを参考にしつつ、最小限の機能で構成されたシンプルなアプリケーションをデプロイし、スケーリングを確認する実践的な手順を紹介します。
本記事で学べること:
- DeploymentとServiceの基本的な使い方
- 外部IPアドレスでのアクセス方法
- 負荷テストによるスケーリングの確認
- 実践的なトラブルシューティング
前提条件
以下の環境が準備されていることを前提とします:
- Kubernetesクラスター(Rancher Desktop、minikube、kindなど)
-
kubectlコマンドがインストールされ、クラスターに接続可能 - 基本的なKubernetesの概念(Pod、Deployment、Service)の理解
- ローカルマシンに
k6がインストールされていること(負荷テスト用)
k6のインストール
Macの場合、Homebrewでインストールできます:
# Homebrewでk6をインストール
brew install k6
# バージョン確認
k6 version
環境確認
まず、クラスターが正常に動作しているか確認しましょう:
# クラスターの状態確認
kubectl cluster-info
# ノードの確認
kubectl get nodes
# 現在のリソース確認
kubectl get all
Rancher Desktop特有の注意点
Rancher Desktopを使用する場合、以下の点に注意してください:
- NodePort範囲: デフォルトで30000-32767のポート範囲が使用可能
-
ノードIPアドレス: Rancher Desktopでは通常
127.0.0.1(localhost)でアクセス可能 - ポートフォワーディング: Rancher Desktopは自動的にNodePortをローカルホストにマッピング
1. シンプルなWebアプリケーションのデプロイ
1.1 アプリケーションの構成
本記事では、以下のシンプルな構成でアプリケーションをデプロイします:
- フロントエンド: Nginxを使用したシンプルなWebサーバー
- 負荷テスト: k6を使用したHTTP負荷テスト
1.2 フロントエンドDeploymentの作成
まず、Nginxを使用したフロントエンドのDeploymentを作成します:
# Deploymentの作成
kubectl create deployment frontend --image=nginx:latest --replicas=2
# Deploymentの確認
kubectl get deployment frontend
# Podの確認
kubectl get pods -l app=frontend
作成されたDeploymentの詳細を確認:
kubectl describe deployment frontend
Deploymentの特徴:
-
replicas: 2により、2つのPodが作成されます - Podが障害で停止した場合、自動的に新しいPodが作成されます
- ローリングアップデートが可能です
この図は、DeploymentがReplicaSetを管理し、ReplicaSetがPodを管理する階層構造を示しています。
1.3 外部アクセス用Serviceの作成(NodePort)
次に、フロントエンドに外部(ローカルのMac)からアクセスするためのServiceを作成します。Rancher Desktopで外部からアクセスするには、NodePortタイプのServiceを使用します:
# NodePortタイプのServiceを作成
kubectl expose deployment frontend --port=80 --target-port=80 --type=NodePort --name=frontend-service
# Serviceの確認
kubectl get service frontend-service
# Serviceの詳細確認
kubectl describe service frontend-service
出力例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend-service NodePort 10.96.123.45 <none> 80:31234/TCP 10s
31234がNodePortとして割り当てられたポート番号です。Rancher Desktopでは、localhost:31234でアクセス可能になります。
Serviceの役割:
- Podの集合に安定したネットワークエンドポイントを提供
- ロードバランシング機能
- サービスディスカバリー(DNS名でのアクセス)
- NodePortタイプにより外部からのアクセスが可能
Serviceは、ラベルセレクターに一致するPodを自動的に検出し、Endpointsとして登録します。NodePortによりクラスター外部からアクセスでき、Serviceがロードバランシングを行います。
2. 外部アクセスの確認とトラブルシューティング
2.1 NodePortの確認
作成したServiceのNodePortを確認します:
# Serviceの詳細確認
kubectl get service frontend-service
# NodePortを取得(後で使用)
export NODE_PORT=$(kubectl get service frontend-service -o jsonpath='{.spec.ports[0].nodePort}')
echo "NodePort: $NODE_PORT"
出力例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend-service NodePort 10.96.123.45 <none> 80:31234/TCP 10s
NodePort: 31234
2.2 Rancher Desktopでの外部アクセス確認
Rancher Desktopでは、localhost経由でNodePortにアクセスできます:
# ブラウザでアクセス
open http://localhost:${NODE_PORT}
# または、curlでアクセス確認
curl http://localhost:${NODE_PORT}
正常に動作している場合、Nginxのデフォルトページが表示されます:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
2.3 疎通確認のトラブルシューティング
外部からアクセスできない場合、以下の手順で確認します:
ステップ1: Podの状態確認
# Podが正常に起動しているか確認
kubectl get pods -l app=frontend
# すべてのPodがRunning状態であることを確認
# 期待される出力:
# NAME READY STATUS RESTARTS AGE
# frontend-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# frontend-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
Podが起動していない場合:
# Podの詳細確認
kubectl describe pod <pod-name>
# Podのログ確認
kubectl logs <pod-name>
ステップ2: Serviceの確認
# Serviceが正しく作成されているか確認
kubectl get service frontend-service
# Serviceの詳細確認
kubectl describe service frontend-service
# Endpointsの確認(重要!)
kubectl get endpoints frontend-service
正常な場合のEndpoints:
NAME ENDPOINTS AGE
frontend-service 10.244.1.10:80,10.244.1.11:80 5m
Endpointsが空の場合、PodとServiceのラベルセレクターが一致していません:
# Podのラベル確認
kubectl get pods -l app=frontend --show-labels
# Serviceのラベルセレクター確認
kubectl get service frontend-service -o jsonpath='{.spec.selector}'
ステップ3: クラスター内からのアクセステスト
Podレベルでアクセスできるか確認:
# テスト用のPodを作成してクラスター内からアクセス
kubectl run test-pod --image=curlimages/curl:latest --rm -it --restart=Never -- sh
# Pod内で実行(Service名でアクセス)
curl http://frontend-service:80
# 正常な場合、Nginxのデフォルトページが表示される
ステップ4: NodePortへの直接アクセステスト
# localhostからNodePortへアクセス
curl -v http://localhost:${NODE_PORT}
# 詳細な接続情報を確認
curl -v http://localhost:${NODE_PORT} 2>&1 | grep -E "Connected|HTTP"
ステップ5: Rancher Desktopの設定確認
Rancher Desktopの設定で、Kubernetesが有効になっているか確認:
- Rancher Desktopを開く
- Preferences → Kubernetes
- "Enable Kubernetes"が有効になっているか確認
- 必要に応じてRancher Desktopを再起動
ステップ6: ポートの競合確認
NodePortが他のプロセスで使用されていないか確認:
# Macでポートの使用状況を確認
lsof -i :${NODE_PORT}
# 何も表示されない場合、ポートは使用可能
2.4 よくあるトラブルと解決方法
| 問題 | 原因 | 解決方法 |
|---|---|---|
curl: (7) Failed to connect |
NodePortが開いていない | Serviceが正しく作成されているか確認 |
curl: (52) Empty reply from server |
Podが起動していない |
kubectl get podsでPodの状態確認 |
| Endpointsが空 | ラベルセレクターの不一致 | PodとServiceのラベル確認 |
Connection refused |
ポートが間違っている | NodePort番号を再確認 |
| ブラウザでアクセスできない | Rancher Desktopの設定問題 | Rancher Desktopを再起動 |
3. スケーリングと負荷テスト
3.1 手動スケーリング
Deploymentのレプリカ数を変更してスケーリングを確認します:
スケーリングにより、新しいPodが作成され、トラフィックが分散されます。
# レプリカ数を3に増やす
kubectl scale deployment frontend --replicas=3
# Podの確認
kubectl get pods -l app=frontend
# レプリカ数を1に減らす
kubectl scale deployment frontend --replicas=1
# Podの確認
kubectl get pods -l app=frontend
3.2 k6を使用した負荷テスト
k6は、高性能な負荷テストツールです。ローカルのMacからk6を実行してHTTPリクエストを送信し、スケーリングの動作を確認します。
k6スクリプトの作成
プロジェクトディレクトリにloadtest.jsを作成します:
// loadtest.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '10s', target: 100 }, // 10秒で100 VUsまで一気に増加
{ duration: '30s', target: 100 }, // 30秒間100 VUsを維持(高負荷)
{ duration: '10s', target: 0 }, // 10秒で0 VUsまで減少
],
thresholds: {
http_req_duration: ['p(95)<1000'], // 95%のリクエストが1秒以内
http_req_failed: ['rate<0.1'], // エラー率が10%未満
},
};
export default function () {
const SERVICE_URL = __ENV.SERVICE_URL || 'http://localhost:30000';
const res = http.get(SERVICE_URL);
check(res, {
'status is 200': (r) => r.status === 200,
'response has content': (r) => r.body.length > 0,
});
// sleep時間を短くして、より多くのリクエストを送信
sleep(0.01);
}
ローカルのMacからk6を実行
Rancher Desktopの場合、localhost経由でNodePortにアクセスします:
# NodePort番号を取得
export NODE_PORT=$(kubectl get service frontend-service -o jsonpath='{.spec.ports[0].nodePort}')
echo "NodePort: $NODE_PORT"
# まず、アクセス可能か確認
curl http://localhost:${NODE_PORT}
# k6を実行(ローカルのMacから)
k6 run --env SERVICE_URL=http://localhost:${NODE_PORT} loadtest.js
k6実行中の出力例
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: loadtest.js
output: -
scenarios: (100.00%) 1 scenario, 100 max VUs, 4m30s max duration (incl. graceful stop):
* default: Up to 100 looping VUs for 4m0s over 4 stages (gracefulRampDown: 30s, gracefulStop: 30s)
running (4m00.5s), 000/100 VUs, 24000 complete and 0 interrupted iterations
default ✓ [======================================] 000/100 VUs 4m0s
✓ status is 200
✓ response has content
checks.........................: 100.00% ✓ 48000 ✗ 0
data_received..................: 12 MB 50 kB/s
data_sent......................: 2.1 MB 8.8 kB/s
http_req_blocked...............: avg=1.2ms min=1µs med=3µs max=100ms p(90)=5µs p(95)=7µs
http_req_connecting............: avg=1.1ms min=0s med=0s max=99ms p(90)=0s p(95)=0s
http_req_duration..............: avg=150ms min=10ms med=140ms max=500ms p(90)=250ms p(95)=300ms
{ expected_response:true }...: avg=150ms min=10ms med=140ms max=500ms p(90)=250ms p(95)=300ms
http_req_failed................: 0.00% ✓ 0 ✗ 24000
http_req_receiving.............: avg=50µs min=10µs med=40µs max=5ms p(90)=80µs p(95)=100µs
http_req_sending...............: avg=20µs min=5µs med=15µs max=2ms p(90)=30µs p(95)=40µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=149.9ms min=10ms med=139.9ms max=499.9ms p(90)=249.9ms p(95)=299.9ms
http_reqs......................: 24000 100/s
iteration_duration.............: avg=250ms min=110ms med=240ms max=600ms p(90)=350ms p(95)=400ms
iterations.....................: 24000 100/s
vus............................: 1 min=1 max=100
vus_max........................: 100 min=100 max=100
k6実行時のトラブルシューティング
問題: WARN[0000] Request Failed error="Get \"http://localhost:xxxxx\": dial tcp [::1]:xxxxx: connect: connection refused"
# 1. Serviceが正しく作成されているか確認
kubectl get service frontend-service
# 2. Podが起動しているか確認
kubectl get pods -l app=frontend
# 3. Endpointsが設定されているか確認
kubectl get endpoints frontend-service
# 4. localhostでアクセスできるか確認
curl http://localhost:${NODE_PORT}
問題: すべてのリクエストがタイムアウトする
# 1. Podのログを確認
kubectl logs -l app=frontend --tail=50
# 2. Serviceの詳細を確認
kubectl describe service frontend-service
# 3. ファイアウォールやネットワーク設定を確認
# (Rancher Desktopの場合、通常は問題なし)
3.3 自動スケーリング(HPA)の設定
Horizontal Pod Autoscaler(HPA)を設定して、負荷に応じて自動的にスケーリングされるようにします。
重要: HPAを動作させるには、Podにリソース制限を設定する必要があります。リソース制限がない場合、HPAはCPU使用率を計測できません。
ステップ1: Podにリソース制限を設定
重要: CPU limitsを低く設定することで、スケーリングが発生しやすくなります。また、HPAが動作するにはrequestsが必須です。
# Deploymentにリソース制限を設定(CPU limitsを低く設定)
kubectl set resources deployment frontend \
--limits=cpu=50m,memory=128Mi \
--requests=cpu=10m,memory=64Mi
# 設定を確認
kubectl describe deployment frontend | grep -A 5 "Limits\|Requests"
リソース制限の説明:
-
limits: Podが使用できる最大リソース(CPU: 50m = 0.05コア、メモリ: 128Mi) -
requests: Podに保証される最小リソース(CPU: 10m = 0.01コア、メモリ: 64Mi)-
重要: HPAは
requestsを基準にCPU使用率を計算します。requestsがないとHPAは動作しません。
-
重要: HPAは
なぜCPU limitsを低く設定するのか:
- CPU limitsが低いと、同じ負荷でもCPU使用率が高くなりやすい
- HPAの閾値(70%)に到達しやすくなり、スケーリングが発生しやすくなる
- デモンストレーション目的で、実際の本番環境では適切な値を設定してください
ステップ1.5: Podを再作成してリソース制限を適用
重要: リソース制限を設定した後、既存のPodは自動的に再作成されません。手動で再作成する必要があります。
# Podを再作成してリソース制限を適用
kubectl rollout restart deployment frontend
# Podが再作成されるまで待機
kubectl rollout status deployment frontend
# 新しいPodにリソース制限が適用されているか確認
kubectl get pods -l app=frontend
kubectl describe pod <pod-name> | grep -A 5 "Limits\|Requests"
# 確認ポイント:
# - Limits: cpu=50m, memory=128Mi
# - Requests: cpu=10m, memory=64Mi
# 両方が設定されていることを確認してください
ステップ2: metrics-serverの確認とインストール
# metrics-serverがインストールされているか確認
kubectl get deployment metrics-server -n kube-system
# metrics-serverがインストールされていない場合、インストール
# Rancher Desktopの場合:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# metrics-serverのPodが起動するまで待機
kubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=60s
# メトリクスが取得できるか確認
kubectl top pods
ステップ3: HPAの作成
基本設定:
# HPAの作成(CPU使用率が70%を超えたらスケール)
kubectl autoscale deployment frontend --cpu-percent=70 --min=1 --max=5
# HPAの確認
kubectl get hpa
# HPAの詳細確認
kubectl describe hpa frontend
HPAの設定説明:
-
--cpu-percent=70: CPU使用率が70%を超えたらスケールアップ -
--min=1: 最小Pod数は1個 -
--max=5: 最大Pod数は5個
注意: デフォルトでは、HPAはスケールアウト(増やす)は積極的に行いますが、スケールイン(減らす)は慎重に行います。負荷が下がっても、すぐにはPod数が減らない場合があります。
ステップ3.5: スケールインを促進する設定(オプション)
負荷テスト完了後にスケールインを確認したい場合、HPAのbehaviorフィールドでスケールダウンポリシーを設定できます。
# 既存のHPAを削除
kubectl delete hpa frontend
# スケールインを促進するHPAを作成(YAMLファイルを使用)
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 30 # スケールダウンの安定化期間を30秒に短縮
policies:
- type: Percent
value: 50 # 一度に50%まで減らせる
periodSeconds: 15 # 15秒ごとに評価
- type: Pods
value: 2 # 一度に最大2個まで減らせる
periodSeconds: 15
selectPolicy: Min # より控えめな方(Min)を選択
EOF
# HPAの確認
kubectl get hpa frontend
# HPAの詳細確認
kubectl describe hpa frontend
スケールダウンポリシーの説明:
-
stabilizationWindowSeconds: 30: スケールダウンの安定化期間を30秒に短縮(デフォルトは5分) -
policies: スケールダウンのポリシー-
type: Percent, value: 50: 一度に50%まで減らせる -
type: Pods, value: 2: 一度に最大2個まで減らせる -
periodSeconds: 15: 15秒ごとに評価
-
-
selectPolicy: Min: より控えめな方(Min)を選択
デフォルトの動作との違い:
- デフォルト: スケールダウンの安定化期間が5分のため、負荷が下がってもすぐには減らない
- 設定後: 安定化期間が30秒に短縮され、より早くスケールインする
HPAの動作確認:
重要: HPAが設定されていないと、自動スケーリングは発生しません。必ずHPAが作成されているか確認してください。
# HPAが作成されているか確認
kubectl get hpa
# HPAが存在しない場合、作成する
kubectl autoscale deployment frontend --cpu-percent=70 --min=1 --max=5
# HPAの詳細を確認
kubectl describe hpa frontend
別ターミナルでの監視方法:
Rancher Desktopでは、別のターミナルを開いて以下のコマンドで監視します:
# ターミナル1: HPAとPodの状態を監視(1秒ごとに更新)
watch -n 1 'kubectl get hpa frontend && echo "" && kubectl get pods -l app=frontend && echo "" && kubectl top pods -l app=frontend'
# または、個別に確認する場合:
# HPAの状態を確認
kubectl get hpa frontend
# Podの数を確認
kubectl get pods -l app=frontend
# CPU使用率を確認(重要!)
kubectl top pods -l app=frontend
負荷テストの実行:
# ターミナル2: 負荷テストを実行
# NodePort番号を取得
export NODE_PORT=$(kubectl get service frontend-service -o jsonpath='{.spec.ports[0].nodePort}')
# k6で負荷テストを実行(短時間で高負荷をかける)
k6 run --env SERVICE_URL=http://localhost:${NODE_PORT} loadtest.js
監視のポイント:
-
ターミナル1で確認すべきこと:
-
kubectl get hpa frontendのTARGETS列でCPU使用率を確認(例:85%/70%) -
kubectl get pods -l app=frontendでPod数が増加しているか確認 -
kubectl top pods -l app=frontendで各PodのCPU使用率を確認(70%を超えているか)
-
期待される動作:
- 負荷テスト開始後10秒: 100 VUsまで増加し、CPU使用率が上昇
- CPU使用率が70%を超える: HPAが検知し、Pod数を増やす
- 30秒間: 高負荷が維持され、Pod数が最大5個まで増加
- 負荷テスト終了後: CPU使用率が下がり、Pod数が徐々に減少
注意: デフォルトのHPA設定では、スケールイン(Pod数を減らす)は慎重に行われます。負荷テスト完了後、すぐにはPod数が減らない場合があります。スケールインを確認したい場合は、上記の「ステップ3.5: スケールインを促進する設定」を適用してください。
確認ポイント(別ターミナルで実行):
# 1. HPAが存在するか確認(重要!)
kubectl get hpa frontend
# 出力例:
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# frontend Deployment/frontend 85%/70% 1 5 3 2m
#
# TARGETS列: 現在のCPU使用率 / 目標CPU使用率(70%)
# REPLICAS列: 現在のPod数
# 2. HPAの詳細を確認(Eventsセクションでスケーリングイベントを確認)
kubectl describe hpa frontend
# 3. Podの数を確認
kubectl get pods -l app=frontend
# 4. Deploymentの状態を確認(REPLICAS列でスケーリングを確認)
kubectl get deployment frontend
# 5. CPU使用率を確認(重要!負荷がかかっているか確認)
kubectl top pods -l app=frontend
# 出力例(負荷がかかっている場合):
# NAME CPU(cores) MEMORY(bytes)
# frontend-xxxxxxxxxx-xxxxx 45m 30Mi
# frontend-xxxxxxxxxx-yyyyy 48m 28Mi
# frontend-xxxxxxxxxx-zzzzz 42m 32Mi
#
# CPU(cores)列: 各PodのCPU使用率(50m = 0.05コア = limitsの100%)
# limitsが50mの場合、50m = 100%のCPU使用率
正常な場合の出力例:
# HPAの状態
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
frontend Deployment/frontend 85%/70% 1 5 3 2m
# Deploymentの状態
NAME READY UP-TO-DATE AVAILABLE AGE
frontend 3/3 3 3 5m
# Podの状態
NAME READY STATUS RESTARTS AGE
frontend-xxxxxxxxxx-xxxxx 1/1 Running 0 5m
frontend-xxxxxxxxxx-yyyyy 1/1 Running 0 1m
frontend-xxxxxxxxxx-zzzzz 1/1 Running 0 30s
# CPU使用率
NAME CPU(cores) MEMORY(bytes)
frontend-xxxxxxxxxx-xxxxx 150m 50Mi
frontend-xxxxxxxxxx-yyyyy 180m 48Mi
frontend-xxxxxxxxxx-zzzzz 160m 52Mi
負荷が増加すると、Podの数が自動的に増加し、最大5個までスケールすることを確認できます。
HPAは、メトリクスサーバーから取得したCPU使用率に基づいて、自動的にPodの数を調整します。
3.5 リソース使用状況の確認
負荷テスト中のリソース使用状況を確認:
# Podのリソース使用状況
kubectl top pods
# ノードのリソース使用状況
kubectl top nodes
# 詳細なメトリクス確認
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods | jq
4. 実践的なトラブルシューティング(まとめ)
4.1 接続のフローチャート
外部からアクセスできない場合、以下の順序で確認します:
1. Podが起動しているか?
↓ No → kubectl describe pod <pod-name> でエラー確認
↓ Yes
2. Serviceが作成されているか?
↓ No → kubectl expose deployment frontend --type=NodePort ...
↓ Yes
3. Endpointsが設定されているか?
↓ No → ラベルセレクターを確認
↓ Yes
4. クラスター内からアクセスできるか?
↓ No → Serviceの設定を確認
↓ Yes
5. localhostからNodePortにアクセスできるか?
↓ No → Rancher Desktopの設定を確認
↓ Yes
6. k6でアクセスできるか?
↓ No → k6スクリプトのURLを確認
↓ Yes
✓ 成功!
4.2 Podが起動しない場合
# Podの状態確認
kubectl get pods -l app=frontend
# Podが起動していない場合の詳細確認
kubectl describe pod <pod-name>
# よくあるエラー:
# - ImagePullBackOff: イメージが見つからない
# - CrashLoopBackOff: コンテナが起動後すぐにクラッシュ
# - Pending: リソース不足またはスケジューリング問題
# Podのログ確認
kubectl logs <pod-name>
# 前回クラッシュしたコンテナのログ
kubectl logs <pod-name> --previous
4.3 Serviceに接続できない場合
# Serviceの確認
kubectl get service frontend-service
# Serviceの詳細確認(Eventsを確認)
kubectl describe service frontend-service
# Endpointsの確認(重要!)
kubectl get endpoints frontend-service
# Endpointsが空の場合
kubectl get pods -l app=frontend --show-labels
kubectl get service frontend-service -o jsonpath='{.spec.selector}'
# DNS解決の確認(クラスター内のPodから)
kubectl run dns-test --image=busybox:latest --rm -it --restart=Never -- nslookup frontend-service
4.4 スケーリングが動作しない場合
ステップ1: HPAの確認
重要: HPAが設定されていないと、自動スケーリングは発生しません。
# HPAが作成されているか確認
kubectl get hpa
# HPAが存在しない場合、作成する
kubectl autoscale deployment frontend --cpu-percent=70 --min=1 --max=5
# HPAの詳細を確認
kubectl describe hpa frontend
よくあるエラー: missing request for cpu
HPAの詳細を確認した際に、以下のようなエラーが表示される場合があります:
Warning FailedGetObjectMetric HPA was unable to compute the replica count:
failed to get cpu utilization: missing request for cpu in container nginx of Pod frontend-xxx-xxx
原因: PodのコンテナにCPUのrequestsが設定されていません。
対処法:
# 1. Podにリソース制限が設定されているか確認
kubectl describe pod <pod-name> | grep -A 5 "Limits\|Requests"
# 2. Requestsが設定されていない場合、Deploymentに設定する
kubectl set resources deployment frontend \
--limits=cpu=50m,memory=128Mi \
--requests=cpu=10m,memory=64Mi
# 3. Podを再作成してリソース制限を適用(重要!)
kubectl rollout restart deployment frontend
# 4. Podが再作成されるまで待機
kubectl rollout status deployment frontend
# 5. 新しいPodにリソース制限が適用されているか確認
kubectl describe pod <new-pod-name> | grep -A 5 "Limits\|Requests"
# 6. HPAの状態を再確認(エラーが解消されているか確認)
kubectl describe hpa frontend
ステップ2: リソース制限の確認
重要: Podにリソース制限が設定されていない場合、HPAは動作しません。特に**requestsが設定されていないと、HPAはCPU使用率を計算できません**。
# Deploymentのリソース制限を確認
kubectl describe deployment frontend | grep -A 5 "Limits\|Requests"
# 実際のPodにリソース制限が適用されているか確認(重要!)
kubectl get pods -l app=frontend
kubectl describe pod <pod-name> | grep -A 5 "Limits\|Requests"
# 確認ポイント:
# - Limits: cpu=50m, memory=128Mi が設定されているか
# - Requests: cpu=10m, memory=64Mi が設定されているか(重要!)
# Requestsが設定されていない場合、HPAは動作しません
リソース制限が設定されていない場合:
# リソース制限を設定(CPU limitsを低く設定)
kubectl set resources deployment frontend \
--limits=cpu=50m,memory=128Mi \
--requests=cpu=10m,memory=64Mi
# Podを再作成してリソース制限を適用(重要!)
kubectl rollout restart deployment frontend
# Podが再作成されるまで待機
kubectl rollout status deployment frontend
# 新しいPodにリソース制限が適用されているか再確認
kubectl describe pod <new-pod-name> | grep -A 5 "Limits\|Requests"
ステップ2: metrics-serverの確認
# metrics-serverの状態確認
kubectl get deployment metrics-server -n kube-system
# metrics-serverが存在しない場合、インストールが必要
# Rancher Desktopの場合:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# metrics-serverのPodが起動するまで待機
kubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=60s
# メトリクスが取得できているか確認
kubectl top pods
# メトリクスが取得できない場合、metrics-serverのログを確認
kubectl logs -n kube-system -l k8s-app=metrics-server
ステップ3: HPAの状態確認
# HPAの状態確認
kubectl describe hpa frontend
# HPAのイベントを確認(Eventsセクション)
# よくある問題:
# - "unable to get metrics": metrics-serverが動作していない
# - "missing request for cpu": リソース制限が設定されていない
ステップ4: 負荷がかかっているか確認(別ターミナルで実行)
重要: 負荷テスト実行中に、別のターミナルでCPU使用率を確認します。
# CPU使用率を確認(負荷テスト実行中)
kubectl top pods -l app=frontend
# 期待される出力(負荷がかかっている場合、limits=50mの場合):
# NAME CPU(cores) MEMORY(bytes)
# frontend-xxxxxxxxxx-xxxxx 45m 30Mi
# frontend-xxxxxxxxxx-yyyyy 48m 28Mi
#
# CPU(cores)列の値:
# - limitsが50mの場合、50m = 100%のCPU使用率
# - 70%を超えるとHPAがスケールアップ(50m × 0.7 = 35m以上)
# - 実際の値が35m以上なら、HPAがスケールアップするはず
# CPU使用率が低い場合(例: 10m以下):
# - 負荷テストが正しく実行されていない可能性
# - k6スクリプトの設定を確認
# - リクエストがServiceに到達しているか確認
# - HPAが作成されているか確認(kubectl get hpa)
CPU使用率の計算方法:
-
limits=cpu=50mの場合:- 50m = 100%のCPU使用率
- 35m = 70%のCPU使用率(HPAの閾値)
-
kubectl top podsで35m以上なら、HPAがスケールアップするはず
ステップ5: 負荷テストの確認
# k6の実行状況を確認
# 別のターミナルで実行中に以下を確認:
# 1. リクエスト数が増加しているか確認
kubectl logs -l app=frontend --tail=20 -f
# 2. Serviceへのアクセスログを確認
# (Nginxの場合、アクセスログが出力される)
# 3. k6の出力でリクエストレートを確認
# http_reqs が 100/s 以上になっているか確認
4.5 k6負荷テストが失敗する場合
# 1. 基本的な接続確認
curl -v http://localhost:${NODE_PORT}
# 2. NodePort番号の再確認
kubectl get service frontend-service -o jsonpath='{.spec.ports[0].nodePort}'
# 3. k6スクリプトのURLを確認
# loadtest.js内のデフォルトURLが正しいか確認
# 4. k6のバージョン確認
k6 version
# 5. 詳細なデバッグモードでk6を実行
k6 run --http-debug --env SERVICE_URL=http://localhost:${NODE_PORT} loadtest.js
4.6 よくある質問(FAQ)
Q1: Rancher Desktopでkubectl get nodesが失敗する
# Kubernetesが有効になっているか確認
# Rancher Desktop → Preferences → Kubernetes → Enable Kubernetes
# kubectlのコンテキストを確認
kubectl config get-contexts
# Rancher Desktopのコンテキストに切り替え
kubectl config use-context rancher-desktop
Q2: NodePortが割り当てられない
# Serviceのイベントを確認
kubectl describe service frontend-service
# ポート範囲を指定してServiceを作成
kubectl delete service frontend-service
kubectl expose deployment frontend --port=80 --target-port=80 --type=NodePort --name=frontend-service
Q3: 負荷テスト中にPodが増えない
# 1. HPAが作成されているか確認(重要!)
kubectl get hpa
# HPAが存在しない場合、作成する:
kubectl autoscale deployment frontend --cpu-percent=70 --min=1 --max=5
# 2. HPAの状態を確認(エラーメッセージを確認)
kubectl describe hpa frontend
# Eventsセクションでスケーリングイベントを確認
# エラー例: "missing request for cpu" が表示される場合、ステップ3へ
# 3. リソース制限が設定されているか確認(重要!)
# Deploymentの設定を確認
kubectl describe deployment frontend | grep -A 5 "Limits\|Requests"
# 実際のPodにリソース制限が適用されているか確認(重要!)
kubectl get pods -l app=frontend
kubectl describe pod <pod-name> | grep -A 5 "Limits\|Requests"
# Requestsが設定されていない場合、HPAは動作しません
# 確認ポイント:
# - Limits: cpu=50m, memory=128Mi が設定されているか
# - Requests: cpu=10m, memory=64Mi が設定されているか(重要!)
# 4. リソース制限が設定されていない、または適用されていない場合:
kubectl set resources deployment frontend \
--limits=cpu=50m,memory=128Mi \
--requests=cpu=10m,memory=64Mi
# Podを再作成してリソース制限を適用(重要!)
kubectl rollout restart deployment frontend
# Podが再作成されるまで待機
kubectl rollout status deployment frontend
# 新しいPodにリソース制限が適用されているか再確認
kubectl describe pod <new-pod-name> | grep -A 5 "Limits\|Requests"
# 5. HPAの状態を再確認(エラーが解消されているか確認)
kubectl describe hpa frontend
# 6. CPU使用率を確認(別ターミナルで負荷テスト実行中に確認)
kubectl top pods -l app=frontend
# 7. CPU使用率の計算
# limits=50mの場合:
# - 50m = 100%のCPU使用率
# - 35m = 70%のCPU使用率(HPAの閾値)
# - kubectl top podsで35m以上なら、HPAがスケールアップするはず
# 8. CPU使用率が低い場合(35m未満):
# - CPU limitsを下げる(例: 50m → 30m)
kubectl set resources deployment frontend \
--limits=cpu=30m,memory=128Mi \
--requests=cpu=10m,memory=64Mi
kubectl rollout restart deployment frontend
# 9. 再度負荷テストを実行
export NODE_PORT=$(kubectl get service frontend-service -o jsonpath='{.spec.ports[0].nodePort}')
k6 run --env SERVICE_URL=http://localhost:${NODE_PORT} loadtest.js
Q4: 負荷テスト完了後、Pod数が減らない(スケールインしない)
原因: HPAのデフォルト設定では、スケールイン(Pod数を減らす)は慎重に行われます。スケールダウンの安定化期間が5分のため、負荷が下がってもすぐには減りません。
対処法: HPAのbehaviorフィールドでスケールダウンポリシーを設定します。
# 1. 現在のHPAの状態を確認
kubectl get hpa frontend
kubectl describe hpa frontend
# 2. CPU使用率を確認(負荷テスト完了後)
kubectl top pods -l app=frontend
# CPU使用率が0%または低い場合、スケールインするはずですが、デフォルトでは時間がかかります
# 3. スケールインを促進する設定を適用
# 既存のHPAを削除
kubectl delete hpa frontend
# スケールインを促進するHPAを作成
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 30 # スケールダウンの安定化期間を30秒に短縮
policies:
- type: Percent
value: 50 # 一度に50%まで減らせる
periodSeconds: 15 # 15秒ごとに評価
- type: Pods
value: 2 # 一度に最大2個まで減らせる
periodSeconds: 15
selectPolicy: Min # より控えめな方(Min)を選択
EOF
# 4. HPAの状態を確認
kubectl get hpa frontend
kubectl describe hpa frontend
# 5. 負荷テストを再実行して、スケールインを確認
# 負荷テスト完了後、30秒〜1分程度でPod数が減ることを確認できます
設定の説明:
-
stabilizationWindowSeconds: 30: スケールダウンの安定化期間を30秒に短縮(デフォルトは5分) - これにより、負荷が下がってから30秒後にはスケールインが開始されます
注意: 本番環境では、スケールインが早すぎると、一時的な負荷増加に対応できなくなる可能性があります。デフォルトの5分の安定化期間は、このような問題を防ぐための設定です。
5. クリーンアップ
作成したリソースを削除:
# DeploymentとServiceの削除
kubectl delete deployment frontend
kubectl delete service frontend-service
# HPAの削除
kubectl delete hpa frontend
# すべてのリソースの確認
kubectl get all
まとめ
本記事では、Rancher Desktopを使用したKubernetesの実践的な手順を紹介しました。特に、外部からのアクセス設定とトラブルシューティングに重点を置いています。
学んだこと:
- DeploymentとServiceの基本: アプリケーションのデプロイとネットワークアクセスの設定
- 外部アクセス: NodePortを使用したRancher Desktopからの外部アクセス方法
- 疎通確認: 各レイヤーでの接続確認とトラブルシューティング手順
- スケーリング: 手動スケーリングと自動スケーリング(HPA)の設定
- 負荷テスト: k6を使用したローカルMacからの負荷テスト実行
- トラブルシューティング: よくある問題の体系的な確認方法
重要なポイント:
- Rancher Desktopでは
localhost経由でNodePortにアクセス可能 - 外部アクセスには必ずNodePortタイプのServiceを使用
- 疎通確認は段階的に実施(Pod → Service → Endpoints → 外部アクセス)
- k6はローカルのMacから実行(クラスター内部ではない)
次のステップ:
- Kubernetes公式のゲストブックチュートリアルでより複雑なアプリケーションをデプロイ
- Ingressを使用した高度なルーティング
- StatefulSetを使用したステートフルアプリケーションのデプロイ
- ConfigMapとSecretを使用した設定管理
補足: その他のServiceタイプ
本記事ではNodePortを中心に説明しましたが、環境に応じて他のServiceタイプも利用できます。
ClusterIP(デフォルト)
クラスター内部からのみアクセス可能なService。マイクロサービス間の通信に使用します。
# ClusterIPタイプのServiceを作成
kubectl expose deployment frontend --port=80 --target-port=80 --type=ClusterIP --name=frontend-internal
# クラスター内からのみアクセス可能
kubectl run test-pod --image=curlimages/curl:latest --rm -it --restart=Never -- curl http://frontend-internal:80
使用ケース:
- バックエンドAPIサーバー
- データベース
- 内部専用サービス
LoadBalancer(クラウド環境)
クラウドプロバイダー(GKE、EKS、AKSなど)が提供するロードバランサーを使用します。
# LoadBalancerタイプでServiceを作成
kubectl expose deployment frontend --port=80 --target-port=80 --type=LoadBalancer --name=frontend-lb
# EXTERNAL-IPが割り当てられるまで待機
kubectl get service frontend-lb -w
# EXTERNAL-IPが表示されたら、そのIPでアクセス可能
# 例: http://35.xxx.xxx.xxx
使用ケース:
- 本番環境での外部公開
- インターネットからの直接アクセスが必要なサービス
- GKE、EKS、AKSなどのクラウド環境
注意: Rancher Desktopでは、LoadBalancerタイプは<pending>状態のままで外部IPは割り当てられません。
ExternalName
外部サービスへのエイリアスを提供します。
# ExternalNameタイプのServiceを作成
kubectl create service externalname my-database --external-name=database.example.com
# クラスター内から external-name で外部サービスにアクセス可能
使用ケース:
- 外部データベースへの接続
- 外部APIサーバーへのアクセス
- DNSエイリアスの作成
Discussion