Docker単体運用の限界:Kubernetes(k8s)によるオートスケーリングと自己修復の実装

「自分のPCでは動くのに、本番サーバーではアクセス集中で落ちた」。これは開発者が最初に直面する壁です。Dockerの導入により、アプリケーションと依存関係(ライブラリ、ランタイム)をコンテナとしてパッケージ化し、環境差異をなくすことには成功しました。しかし、サービスが拡大し、コンテナが10個、100個と増えたとき、手動でのdocker runや単純なスクリプト管理では、障害時の復旧やスケーリングに対応できません。金槌(Docker)だけで高層ビルを建てようとしているようなものです。本記事では、なぜ私たちがDocker単体の運用を諦め、Kubernetes(以下k8s)という重厚な電動ドリルを選ばざるを得なかったのか、その技術的根拠と解決策を共有します。

深層分析:なぜDockerだけでは不十分なのか

根本的な誤解として「DockerとKubernetesはどちらかを選ぶもの」という認識がありますが、これは間違いです。Dockerは「コンテナを作る・動かす」技術であり、Kubernetesは「大量のコンテナを指揮・管理する」技術です。

Docker単体(あるいはDocker Compose)での運用時に発生する致命的な課題は以下の通りです。

  • 自己修復(Self-healing)の欠如: プロセスがクラッシュした際、監視ツールがアラートを飛ばすだけで、人間がSSHで入って再起動するまでダウンタイムが続きます。
  • ダウンタイムなしのデプロイ: docker stop して新しいイメージで docker run する瞬間、必ずサービス停止が発生します。Blue/Greenデプロイを自前スクリプトで組むのは悪夢です。
  • リソース管理の限界: 特定のノードにコンテナが偏り、メモリ溢れ(OOM)で連鎖的にサーバーがダウンするリスクがあります。
本番環境での警告:
Docker Composeは開発環境や小規模な単一サーバー構成には最適ですが、複数のサーバーにまたがる冗長構成やオートスケーリングを管理する機能は持っていません。「プロダクション環境でのシェルスクリプトによるコンテナ管理」は、技術的負債の最大の要因となります。

The Solution: 宣言的構成による自己修復

解決策は、コンテナの管理を「命令的(Imperative)」から「宣言的(Declarative)」に切り替えることです。「コンテナを起動しろ」と命令するのではなく、「常にコンテナが3つ起動している状態であれ」と定義します。これを実現するのがKubernetesのDeploymentリソースです。

以下は、Dockerコンテナをk8sで管理し、自動再起動と負荷分散を実現するための本番用マニフェスト(YAML)です。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: production-api
  labels:
    app: backend-service
spec:
  # 【重要】常に3つのレプリカ(コピー)を維持するようk8sに指示
  # 1つがクラッシュしても、即座に新しいポッドが立ち上がり3に戻る
  replicas: 3
  selector:
    matchLabels:
      app: backend-service
  strategy:
    type: RollingUpdate
    rollingUpdate:
      # 更新時に許容する最大超過数と最大不足数を制御し、ダウンタイムを防ぐ
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: backend-service
    spec:
      containers:
      - name: api-container
        # Docker Hubなどのレジストリにあるイメージを指定
        image: my-registry/backend:v1.2.0
        ports:
        - containerPort: 8080
        resources:
          # リソース制限を設け、OOM Killerによるノード全体の道連れを防ぐ
          limits:
            memory: "512Mi"
            cpu: "500m"
          requests:
            memory: "256Mi"
            cpu: "250m"
        # 【死活監視】アプリケーションが応答しない場合、k8sが自動で再起動を行う
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 20
        # 【準備確認】起動完了するまでトラフィックを流さない(エラー応答を防ぐ)
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10

Docker単体 vs Kubernetes 比較検証

実際に高負荷環境下で障害テストを行った際の違いは以下の通りです。

機能 Docker単体 (Compose) Kubernetes (k8s)
コンテナのクラッシュ時 プロセス停止(手動再起動が必要) 即座に自動再起動(LivenessProbe)
デプロイ時の挙動 一時的なサービス断が発生 ローリングアップデートにより無停止
スケーリング 手動でコマンド実行が必要 CPU負荷に応じて自動増減(HPA)
設定の複雑さ 低い(学習コスト小) 高い(学習コスト大)
Note: Kubernetesの複雑さは「運用コストを下げるための投資」です。初期設定は大変ですが、夜中や休日に障害対応で呼び出されるリスクを劇的に減らしてくれます。

Conclusion

Dockerはアプリケーションを「運べる」ように革命を起こしましたが、それを大規模に「運用し続ける」ための解がKubernetesです。小規模なツールや個人のプロジェクトであればDockerだけで十分ですが、サービスの可用性(SLA)を保証し、ビジネスを止めないインフラを構築するためには、k8sへの移行は避けて通れない道です。学習コストを恐れず、まずはシンプルなDeploymentから導入し、自己修復システムの恩恵を体験してください。

Post a Comment