Kamal 2でコンテナ化アプリをVPSにデプロイする:K8sのコストをかけずにゼロダウンタイムを実現

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Kubernetesの「複雑さ」という税金

Kubernetesは強力なツールですが、多くの中規模アプリにとっては、膨大な時間を浪費する原因になりがちです。実際の機能開発よりも、YAMLマニフェストやイングレスコントローラーとの格闘に多くの時間を費やすことになります。サービスが3〜4つしかないクラスターの維持だけで、チームの週間開発リソースの20%が失われるのを私は見てきました。

Kamal 2は別の道を示してくれます。BasecampやHEYをクラウドから移行させるために37signalsによって作成されたこのツールは、HerokuのようなPaaSの滑らかさを、あらゆるベーシックなVPSにもたらします。月額500ドルのマネージドサービス料金やベンダーロックインなしに、コンテナ化の恩恵を享受できます。私はいくつかの本番環境のワークロードをこのモデルに移行しましたが、安定性は素晴らしく、インフラはついにコードの二の次(補完的な存在)であると感じられるようになりました。

内部的な仕組みとして、Kamal 2はSSH経由でコマンドを送信することで動作します. レジストリからDockerイメージをプルし、軽量なプロキシを管理して、バージョンを瞬時に切り替えます。サーバー側に重いエージェントを必要としません。マシンにSSH接続でき、Dockerがインストールされていれば、デプロイの準備は完了です。

環境の準備

設定を始める前に、ローカルマシンにいくつかツールが必要です。従来のオーケストレーションとは異なり、KamalはローカルまたはCI/CDランナー上で動作し、リモートサーバーに命令をプッシュします。

1. ローカル要件

KamalはRubyのgemとして配布されています。Rubyのエキスパートである必要はありませんが、マシンに実行環境が必要です。

# Kamal 2をインストール
gem install kamal

# バージョンを確認
kamal version

2. サーバーの準備

クリーンなVPSから始めましょう。Ubuntu 24.04が最適です。Dockerが未インストールの場合はKamalが代わりにインストールしてくれますが、まずSSHキーによるアクセスを設定する必要があります。自動化フローを妨げるため、パスワードベースの認証は避けてください。快適に使用するために、SSHユーザーにパスワードなしのsudo権限があることを確認してください。

# VPS上で実行してください
echo "youruser ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/youruser

3. コンテナレジストリ

Kamalはイメージをローカルでビルドし、Docker Hub、GitHub Packages、AWS ECRなどのコンテナレジストリにプッシュします。その後、VPSがそこからイメージをプルします。次のステップに進む前に、レジストリの認証情報を用意しておいてください。

デプロイの設定

Kamalが行うすべての操作は、単一のファイル config/deploy.yml によって制御されます。このファイルでサーバー、レジストリ、環境変数を定義します。プロジェクトのルートで kamal init を実行して、スターターテンプレートを生成しましょう。

以下は、標準的なWebアプリケーション向けの本番用設定例です:

service: my-awesome-app
image: username/my-awesome-app

servers:
  web:
    - 123.45.67.89

registry:
  username: my-docker-user
  password:
    - KAMAL_REGISTRY_PASSWORD # ローカルの環境変数(ENV)から取得されます

env:
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL
  clear:
    - PORT: 3000

proxy:
  ssl: true
  host: app.example.com
  # Kamal 2はゼロダウンタイムでの切り替えのために内蔵プロキシを使用します

asset_path: /assets

branches:
  master: main

Kamal Proxy의 威力

Kamal 2では kamal-proxy が導入され、以前のTraefik統合に取って代わりました。この新しいプロキシは「起動して切り替える(boot-and-switch)」ワークフロー専用に設計されています。新しいコンテナがヘルスチェックをパスするのを待ってから、トラフィックをリダイレクトします。新しいバージョンの正常な動作が確認されると、古いバージョンを停止します。このプロセスにより、リリース中にユーザーが502エラーを目にすることはありません。

シークレットの安全な管理

上記YAMLの secret セクションに注目してください。Kamalはデプロイ時にこれらの値を埋めるために、ローカルマシンの .env ファイルを探します。その後、それらをリモートコンテナに安全に注入します。設定ファイルにパスワードをハードコードしないでください。

デプロイのワークフロー

最初のセットアップは一度限りのコマンドです。KamalがVPSに接続し、Dockerをインストールし、レジストリを設定し、プロキシをセットアップします。これには通常、サーバーのインターネット速度にもよりますが、約2〜3分かかります。

kamal setup

このコマンド一つで、かつては丸午後かかっていた手動のBashスクリプト作業が不要になります。セットアップが完了すれば、最初のライブリリースの準備は万端です。

アップデートのデプロイ

新しいコードのプッシュは簡単です。それ以降のすべてのアップデートは、一つのコマンドで処理されます:

kamal deploy

これにより一連の自動化ステップが実行されます。まず、Dockerイメージをビルドします。次に、イメージをレジストリにプッシュし、本番サーバーへプルします。システムは新しいポートで新しいコンテナを起動し、200 OKのヘルスチェックを待ちます。チェックに失敗した場合、Kamalは即座に停止します。このセーフティネットにより、古いバージョンが実行され続け、壊れたリリースがサイトをダウンさせるのを防ぎます。

監視と緊急ロールバック

コードをリリースするのは仕事の半分に過ぎません。PID番号を探し回ることなく、コンテナ内部で何が起きているかを確認する必要があります。Kamalは、退屈な手動のDockerチェックに代わるユーティリティコマンドを提供しています。

ステータスとログの確認

すべてのサーバーでどのバージョンがアクティブかを確認するには、以下を実行します:

kamal details

ライブの問題をデバッグする必要がある場合は、すべてのサーバーから同時にログをストリーミングできます:

kamal app logs -f

10秒ロールバック

バグはつきものです。もし不具合のあるリリースが紛れ込んでしまった場合、CI/CDのフルリビルドを待つ必要はありません。Kamalは即座に復旧できるよう、サーバー上に古いイメージを保持しています。

kamal rollback [VERSION]

このコマンドは、以前のコンテナイメージを即座に指すようプロキシに指示します。これは、重大な本番エラーから回復する最も速い方法です。

リモートビルダーによる高速化

ローカルのラップトップでDockerイメージをビルドするのは、特にWi-Fiが弱い環境では時間がかかることがあります。設定で強力なVPSを「リモートビルダー」として指定できます。これにより、デプロイ時間を数分から60秒未満に短縮できる場合があります。

builder:
  remote: ssh://builder-user@builder-ip

「複雑さという税金」を捨てる

Kamal 2は、煩雑な手動管理のVPSと、過剰なKubernetesの間の溝を埋めてくれます。サーバーを使い捨てのものとして扱いながらも、ロジックの制御は手元に残せます。K8s of オーバーヘッドを取り除くことで、インフラ管理ではなく機能のリリースに集中できるようになります。成長中のほとんどのプロジェクトにとって、Kamal 2への移行は、実施できる最も効果的なDevOpsのアップグレードとなるでしょう。

Share: