7.1 リアルタイム可視化とログ集約
本節では、コンテナの挙動を可視化し、ログを効率的に集約するための実践的な手法を解説します。
7.1.1 モニタリングの基礎知識
- メトリクス取得:CPU、メモリ、ネットワークI/O、ディスクI/Oを継続的に収集し、閾値超過を検知します。
- ログパイプライン:Fluent Bit → Elasticsearch → Kibana のようなパイプラインを構築し、構造化ログを一元管理します。
- アラート設計:Prometheus Alertmanager を用いて、SLA違反やエラーレート上昇を自動通知します。
- セキュアなログ転送:mTLS で保護した Fluentd Aggregator を経由し、GDPR/PIPA 要件を満たします。
7.1.2 実践:FlaskアプリをPrometheus+Grafanaで監視
以下の手順で、Flaskアプリのメトリクスを取得し、Grafanaダッシュボードで可視化します。
- アプリケーション実装
# main.py from flask import Flask from prometheus_client import Counter, Histogram, generate_latest import time app = Flask(__name__) req_count = Counter('flask_requests_total', 'Total requests', ['method', 'endpoint']) req_latency = Histogram('flask_request_duration_seconds', 'Latency', ['method', 'endpoint']) @app.route('/') def index(): start = time.time() req_count.labels(method='GET', endpoint='/').inc() time.sleep(0.1) req_latency.labels(method='GET', endpoint='/').observe(time.time() - start) return "OK" @app.route('/metrics') def metrics(): return generate_latest() - Dockerfile
FROM python:3.11-slim WORKDIR /srv COPY requirements.txt . RUN pip install -r requirements.txt COPY main.py . CMD ["gunicorn", "-b", "0.0.0.0:5000", "main:app"] - Prometheus設定
# prometheus.yml global: scrape_interval: 10s scrape_configs: - job_name: flask static_configs: - targets: ['flask:5000'] - Compose起動
# compose.yml services: flask: build: . ports: ["5000:5000"] prometheus: image: prom/prometheus ports: ["9090:9090"] volumes: ["./prometheus.yml:/etc/prometheus/prometheus.yml"] grafana: image: grafana/grafana ports: ["3000:3000"] environment: - GF_SECURITY_ADMIN_PASSWORD=admin
7.1.3 応用:ELKスタックで構造化ログを分析
Filebeat → Logstash → Elasticsearch → Kibana のパイプラインを Docker Compose で起動し、JSONログをダッシュボード化します。
# elk-compose.yml
version: "3.9"
services:
filebeat:
image: docker.elastic.co/beats/filebeat:8.12.0
user: root
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml
logstash:
image: docker.elastic.co/logstash/logstash:8.12.0
volumes: ["./logstash.conf:/usr/share/logstash/pipeline/logstash.conf"]
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports: ["9200:9200"]
kibana:
image: docker.elastic.co/kibana/kibana:8.12.0
ports: ["5601:5601"]
7.2 リソース制限とパフォーマンス最適化
7.2.1 リソース制御の基礎
- CPU制限:--cpus 2.0 --cpuset-cpus 0-1 で2コア限定。
- メモリ制限:--memory 512m --memory-swap 1g でスワップも含めて制御。
- I/O帯域:--device-read-bps /dev/sda:10mb でディスク帯域を抑止。
- ネットワーク:macvlan や ipvlan を使い、ホストと同レベルのスループットを実現。
7.2.2 実践:Flaskアプリのリソース最適化
- マルチステージビルドで軽量化
# Dockerfile FROM python:3.11-alpine AS builder WORKDIR /build COPY requirements.txt . RUN pip install --user -r requirements.txt FROM python:3.11-alpine WORKDIR /app COPY --from=builder /root/.local /usr/local COPY app.py . EXPOSE 5000 CMD ["python", "app.py"] - cgroups v2で厳密制限
docker run -d \ --name flask-restricted \ --cpus="0.5" \ --memory="256m" \ --pids-limit 100 \ flask-optimized - ベンチマーク
wrk -t4 -c100 -d30s http://localhost:5000/
7.2.3 ネットワーク最適化:hostモード活用
# hostモードでレイテンシ削減
docker run -d --network host flask-optimized
# ベンチマーク比較
ab -n 10000 -c 100 http://127.0.0.1:5000/
7.2.4 ストレージ最適化:高速ボリュームマウント
# NVMe SSDを直接マウント
docker run -d \
--name flask-io \
--mount type=bind,source=/mnt/nvme0n1,target=/data \
--storage-opt size=10G \
flask-optimized
7.3 トラブルシューティングとリカバリー
7.3.1 基本手順
- ステータス確認:docker ps -a で Exit コードを確認。
- ログ確認:docker logs --tail 100 -f <container>
- イベントストリーム:code>docker events --filter event=die
- インスペクト:docker inspect --format='{{.State.Error}}' <container>
- デバッグコンテナ:docker run --rm -it --pid=container:<target> nicolaka/netshoot /bin/bash
7.3.2 実践:Flaskアプリの異常終了を調査
# 1. 異常終了を再現
docker run -d --name flask-crash flask-buggy
# 2. ログ確認
docker logs flask-crash
# 3. 設定確認
docker inspect flask-crash | jq '.[0].Config.Env'
# 4. コンテナ内へアタッチ
docker exec -it flask-crash sh
7.3.3 ネットワーク接続障害の診断
# 1. ネットワーク一覧
docker network ls
# 2. 接続テスト
docker run --rm -it --network mynet nicolaka/netshoot \
curl http://db:3306
# 3. DNS解決確認
docker run --rm -it --network mynet nicolaka/netshoot \
nslookup db
7.3.4 ボリューム権限エラーの解消
# 1. UID/GID確認
docker run --rm -v $(pwd)/uploads:/data alpine id
# 2. 権限修正
docker run --rm -v $(pwd)/uploads:/data alpine \
sh -c "chown -R 1000:1000 /data"
# 3. 再実行
docker run -d -v $(pwd)/uploads:/data flask-uploader
7.3.5 自動リカバリー設定
# compose.yml
services:
flask:
build: .
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s