デプロイメント:成果物を環境に配置する能動的な行為

アプリケーションをビルドし、成果物(アーティファクト)にパッケージングしてリポジトリに保存しました。次は何でしょうか?リポジトリに置かれた成果物は単なるファイルです。それが実際に環境に配置されて実行されて初めて価値を持ちます。この配置して実行する行為こそ、エンジニアがデプロイメントと呼ぶものです。

デプロイメントは受動的な状態ではありません。能動的なアクションです。デプロイメント前、ステージング環境はバージョン1.1.0を実行しています。デプロイメント後はバージョン1.2.0を実行します。その環境で何かが変わりました。誰か、または何かが成果物を取得し、適切なサーバーに移動し、起動したのです。

デプロイメント中に実際に何が起こるのか

チームがバージョン1.2.0をステージングに送ることを決定した場合、一連の具体的なステップが実行されなければなりません。誰かがリポジトリから成果物をプルします。それをステージングサーバーに転送します。古いプロセスを停止し、新しいプロセスを起動し、正常に動作していることを確認します。環境は新しい状態になります。

以下は、これらのステップをシェルコマンドで示した具体例です。

scp myapp-v1.2.0.jar user@staging-server:/opt/myapp/ && \
ssh user@staging-server "systemctl stop myapp && \
  cp /opt/myapp/myapp-v1.2.0.jar /opt/myapp/current.jar && \
  systemctl start myapp"

これが、デプロイメントが単なるファイル保存とは異なる理由です。完璧な成果物リポジトリがあり、ビルドされたすべてのバージョンが保存されていても、それらの成果物が環境に配置されて実行されるまでは、何もデリバリーされていません。デプロイメントは「ビルドした」と「どこかで実行されている」の間の架け橋です。

次のシーケンス図は、デプロイメントとリリースの分離を示しています。

sequenceDiagram participant AR as Artifact Registry participant DT as Deployment Tool participant S as Server participant LB as Load Balancer DT->>AR: Pull artifact v1.2.0 DT->>S: Transfer artifact DT->>S: Stop old process (v1.1.0) DT->>S: Start new process (v1.2.0) DT->>S: Verify health S-->>DT: Healthy Note over DT,LB: Deployment complete DT->>LB: Switch traffic to v1.2.0 Note over DT,LB: Release happens

ここで自然と湧く疑問は、デプロイメントはユーザーがすぐに新しいバージョンを使えることを意味するのか、ということです。必ずしもそうではありません。デプロイメントとリリースは、チームがしばしば一緒に行うものの、異なる概念です。

デプロイメントとリリースの違い

デプロイメントは技術的なアクションです。成果物を環境に配置して実行します。リリースはアクセスに関するものです。「ユーザーが実際に新しいバージョンを使い始めるのはいつか?」という問いに答えます。

チームが午前2時にバージョン1.2.0を本番環境にデプロイしたと想像してください。本番サーバーは新しいバージョンを実行していますが、チームは意図的にまだユーザートラフィックを新しいバージョンにルーティングしていません。デプロイメントは行われましたが、リリースは行われていません。ユーザーはまだ古いバージョンを使っています。チームはドアを開ける前に、新しいバージョンが正常であることを確認できます。

次に、逆のシナリオを想像してください。チームは本番環境にデプロイし、すぐにすべてのユーザーを新しいバージョンに誘導します。この場合、デプロイメントとリリースは同じステップで発生します。どちらのアプローチも有効ですが、違いを理解することで選択肢が広がります。

なぜこの分離が重要なのでしょうか?デプロイメントは失敗する可能性があるからです。失敗した場合、環境を以前の状態に戻す方法を知っておく必要があります。そのアクションをロールバックと呼びます。ロールバックは基本的に、同じ環境への古いバージョンのデプロイメントです。チームが「新しいバージョンをプッシュする」ことだけを知っていて、デプロイメントが元に戻せるアクションであることを理解していなければ、問題が発生したときに苦労することになります。

デプロイメントは常にスムーズとは限らない

慎重に計画しても、デプロイメントは問題に直面することがあります。サーバーのディスク容量が不足するかもしれません。設定ファイルにタイポがあるかもしれません。リポジトリからダウンロードした成果物が破損しているかもしれません。ネットワークの問題で転送中にタイムアウトが発生するかもしれません。

このため、すべてのデプロイメントには検証が必要です。成果物が配置されて実行された後、誰かまたは何かが環境が実際に正常であることを確認しなければなりません。アプリケーションはリクエストに応答していますか?ログはクリーンですか?期待されるメトリクスは正常範囲内ですか?

検証は自動化することも手動で行うこともできますが、存在しなければなりません。検証なしで完了したデプロイメントは、何も問題が起きていないことを願っているだけです。願望はデプロイメント戦略ではありません。

実用的な意味合い

デプロイメントを受動的な状態ではなく能動的なアクションとして捉えると、いくつかのことが明確になります。

第一に、デプロイメントは再現可能です。今日バージョン1.2.0をデプロイできるなら、明日も同じ環境に同じ結果でバージョン1.2.0をデプロイできるべきです。それが真でない場合、デプロイメントプロセスに隠れたステップや依存関係があります。

第二に、デプロイメントは元に戻せます。バージョン1.2.0が問題を引き起こす場合、同じ環境にバージョン1.1.0をデプロイして戻せるべきです。それがロールバックです。ロールバックが困難またはリスクが高い場合、デプロイメントプロセスを改善する必要があります。

第三に、デプロイメントは検証可能です。妥当な時間内に、デプロイメントが成功したか失敗したかを把握できるべきです。スクリプトがエラーなく実行されたかどうかだけでなく、アプリケーションがその環境で実際に正しく動作しているかどうかも確認する必要があります。

シンプルなデプロイメントチェックリスト

デプロイメントを完了と呼ぶ前に、以下のチェックを実行してください。

  • 成果物は正しい環境に配置されましたか?
  • 新しいバージョンが実際に実行され、トラフィックを受け付けていますか?
  • 基本的なヘルスチェックはパスしていますか(レスポンスコード、レイテンシ、エラー率)?
  • 古いバージョンが実行されていないことを確認できますか(段階的なロールアウトを行っている場合を除く)?
  • 必要に応じてロールバックする方法を知っていますか?そのロールバックパスはテスト済みですか?

このチェックリストは網羅的ではありませんが、最低限をカバーしています。すべてのチームは、自身の環境とアプリケーションの特性に基づいてこれを拡張する必要があります。

まとめ

デプロイメントは、成果物がファイルではなくなり、実行中のサービスになる瞬間です。それは能動的で、再現可能で、元に戻せ、検証可能なアクションです。デプロイメントとリリースを分離することで、ユーザーが変更をいつ目にするかを制御できます。すべてのデプロイメントを検証することで、ユーザーが問題を発見する前に問題を発見できるようになります。

次回チームが「デプロイした」と言ったら、尋ねてみてください:実際に成果物を配置して、それが実行されていることを確認しましたか?それとも、単にボタンを押して願っただけですか?その答えが、あなたのデプロイメントプロセスがどれだけ成熟しているかを教えてくれるでしょう。