[レポート] DEV317: 高度な継続的デリバリーのベストプラクティス #reinvent

DEV317: Advanced Continuous Delivery Best Practices のセッションレポートとなります。
2018.11.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、佐伯です。初めてre:Inventに参加しております!なんかお祭り感がすごくて興奮しっぱなしです。DEV317「Advanced Continuous Delivery Best Practices」のセッションレポートとなります。それではどうぞ!

セッション概要

Continuous delivery (CD) enables teams to be more agile and quickens the pace of innovation. Too often, however, teams adopt CD without putting the right safety mechanisms in place. In this talk, we discuss opportunities for you to transform your software release process into a safer one. We explore various DevOps best practices, showcasing sample applications and code with AWS CodePipeline and AWS CodeDeploy. We discuss how to set up delivery pipelines with nonproduction testing stages, failure cases, rollbacks, redundancy, canary testing and blue/green deployments, and monitoring. We'll discuss continuous delivery practices for deploying to Amazon EC2, AWS Lambda, and Containers (such as Amazon ECS or AWS Fargate).

スピーカー

Felipe Almeida - Senior Software Dev Engineer, AWS Curtis Rissi - Sr. Solutions Architect

このセッションで話すこと

  • AWSにおけるいくつかの継続的デプロイメントのベストプラクティス
  • どのように、なぜこれらのベストプラクティスを行うか
  • どのようにして継続的なデプロイメントを達成するか

基本的なCDにおけるベストプラクティス

  • ソースコードのバージョン管理
  • ビルドの自動化
  • デプロイの自動化
  • ひとつ以上のインスタンスへのデプロイ
  • ユニットテスト
  • インテグレーションテスト
  • 継続的デリバリー
  • オペレーションダッシュボード

このセッションで出てくるAWSサービス

  • Amazon CloudWatch
  • Amazon SNS
  • AWS Lambda
  • AWS CodeDeploy
  • AWS CodePipeline

ひとつの自動化されたパイプラインは以下のようになっているべきである

  • コードとして定義されている
  • AWS CodeCommitなどによってバージョン管理されている
  • 他のAWSサービスやサードパーティツールと連携して拡張できる
  • パイプラインの成功/失敗のフィードバックを提供できる

自動化への機会

  • CIプロセス: ビルド、インテグレーションテスト、UIテスト
  • ヘルスチェック
  • アプリケーションテスト
    • 総合的なユーザーテストとアプリケーションパフォーマンスモニタリング
  • 通知とアラート
    • AWS CloudWatchアラームとSplunkやDatadogなどのサードパーティツール
    • Amazon SNS, Slack, Amazon SNS, Slack, Pagerduty

Step1: ビルドとユニットテスト

  1. ソースの変更をトリガーとしてパイプラインを実行
  2. ビルドとユニットテストを実行
  3. インテグレーション環境へデプロイ
  4. UIテストを実行
  5. インテグレーションテストを実行

Step2: ビルドとテストの失敗通知

  1. テストを実行
  2. CloudWatch EventsでFailed ActionをトリガーにAWS Lambdaを実行
  3. AWS LambdaでSlackなどに通知

ベストプラクティスとしてデプロイメントの正常性確認

デプロイメントヘルスステータスの管理

  • オートメーションの基礎を構築する
  • デプロイ後にサービスが動作していることを検証する目的で構築する
  • これらの手動作業を削減できる

ローリングデプロイ方式の場合、デプロイの正常性を確認せずにデプロイを行ってしまうとすべてのインスタンスにデプロイがされてしまい、サービスのダウンタイムが発生してしまう。

ローリングデプロイに安全性を追加する

  1. 各ホストのヘルスステータスを検証する
  2. デプロイ対象の最低何%が正常であることを確認する
  3. もしデプロイが失敗した場合はロールバックする

Step1: デプロイメントの検証 - AppSpec.yml

以下の様にAppSpec.ymlでValidateServiceライフサイクルイベントでサービスの正常性を確認するスクリプトを実行する。(Webサービスであれば自身にHTTPリクエストを実行して正常性を確認するなど)

  • 参考リンク: AppSpec の「hooks」セクション - AWS CodeDeploy
    version: 0.0
    os: linux
    files:
      - source: source
        destination: /webapp/my_app
    hooks:
      ApplicationStart:
        - location: scripts/start.sh
          timeout: 3600
      ValidateService:
        - location: scripts/validate_running_service.sh
          timeout: 3600
          runas: codedeployuser

Step2: 最小限の正常なホスト設定を使用する

Step3: デプロイ失敗時にロールバックする

一度にひとつのセグメントにデプロイ

セグメント化によるデプロイリスクの低減

  • デプロイ失敗時の影響を最小限にする
  • 実際のユーザーが実行する前に問題を発見できる可能性がある
  • デプロイが失敗しても影響範囲を狭めてロールバックをより早く行うことができる

セグメント化の概要

  1. プロダクション環境のデプロイを複数のセグメントに分割する
  2. ひとつのセグメントごとにデプロイする
  3. デプロイ後にひとつのセグメントをテストする
  4. 2と3を繰り返す

Step1: プロダクション環境のデプロイを複数のセグメントに分割する

一般的なセグメント分割の例:

  • リージョン
  • アベイラビリティゾーン
  • サブゾーン
  • シングルホスト(カナリアデプロイ)

デプロイグループをセグメントとして使用する: セグメントごとにデプロイグループを作成、タグまたはAutoScalingグループでセグメントを判別する。

Step2: 各セグメントにデプロイする

  1. 最小のセグメントにデプロイ
  2. Post-deploymentテスト
  3. ひとつのアベイラビリティゾーンにデプロイ
  4. Post-deploymentテスト
  5. 残りのアベイラビリティゾーンにデプロイ
  6. 他のリージョンでも同じことを繰り返す

Step3: 各セグメントでのテスト

パイプラインにセグメントテストを追加する: CodePipelineに以下のアクションを追加して拡張する

アクション タイムアウト
Testアクション 1時間
Lambda Invokeアクション 1時間
Customアクション 7日間
Approvalアクション 7日間

Approvalアクションをトリガーとしたテスト例

Approvalアクション -> Amazon SNS -> AWS Lambdaと連携し、Lambdaファンクションでテストを行う。

Post-deploymentテストの作成

セグメント化のまとめ

  • セグメント化してデプロイすることで不具合等の影響を小さくできる
  • 最小のセグメント化
    • リージョン
    • リージョンごとのカナリアデプロイ
  • それより大きなセグメント化
    • アベイラビリティゾーン
    • サブゾーン
  • 各セグメントが稼働する前にテストをする

マルチプルリージョンへのデプロイ

クロスリージョンデプロイ

  • 2018年11月に新機能追加
  • ひとつのパイプラインからクロスリージョン/クロスアカウントへのデプロイが可能になった
  • 低レイテンシと高可用性を実現する

パイプラインにガバナンスを実装

非準拠のパイプラインをブロック

  • 紹介した変更を導入したり、新しいパイプラインを追加したりするとダウンタイムなどの重大な問題が発生する可能性があります。
  • AWS Configを活用して、プロダクション環境へのデプロイを許可する前にパイプラインのコンプライアンスを確保することができます。

AWS Config rulesで安全性を追加する

  • AWS Config rulesを作成する
    • 組織のベストプラクティスに則っていない場合アラートとするAWS Config rulesを作成
  • プロダクション環境をブロックするようなパイプラインを構築する
    • Approvalアクションでプロダクション環境のデプロイを一時停止する
    • コンプライアンスに準拠している場合、Lambdaで自動承認する

まとめ

CodeBuild、CodeDeploy、CodePipelineを使ったシンプルなCI/CD環境を構築したことはありますが、CodePipelineのApprovalアクションから更にテストを実行するなど、私では思いつきもしなかった方法が紹介されており、目からウロコでした。サービス規模にもよると思いますがデプロイの分割についても、すごい勉強になりました!