弊社の一部プロジェクトでは Bitbucket Cloud を利用しています
Bitbucket Cloud には CI/CD ツールとして Bitbucket Pipeline が組み込まれています
Bitbucket Pipeline は通常、下記のようなフローを行うプロジェクトを想定して案内されています
- プロジェクトのビルド & テスト
- テスト環境へのデプロイ
- 本番環境へのデプロイ
一方で今回ご紹介するのは下記のような環境別にリソースを同一のリポジトリで管理しているプロジェクト向けのパイプラインです
- Static Resource files (S3 にデプロイなど)
- Kubernetes Manifest files
- Terraform Template files
リポジトリ構成
下記のように環境別にディレクトリを用意して、コンテンツを管理します
.
├ stage # テスト環境用
│ └ ...
├ prod # 本番環境用
│ └ ...
└ bitbucket-pipelines.yml
Bitbucket Pipeline は CI/CD で何を行うかを宣言的に行うため、リポジトリルートの bitbucket-pipelines.yml
に記述をします
バージョン管理対象に含まれるため、ロールバックや編集履歴が追いやすい利点があります
今回達成させるデプロイフロー
- 開発者がメインブランチから作業ブランチを切って、リソースを更新
- メインブランチに向けて Pull Request を作成
- Pull Request をマージ
- 更新があったデプロイ先に対してデプロイ準備が自動で整う
- 開発者が同意を行い対象にリソースをデプロイする
Pipeline 記述内容
最終的な bitbucket-pipelines.yml
は下記のようになります
pipelines: branches: master: - step: name: Before deployment clone: enabled: false script: - echo . - step: name: Deploy to Staging condition: changesets: includePaths: - stage/** trigger: manual deployment: Staging script: - # Write deploy command - step: name: Deploy to Production condition: changesets: includePaths: - prod/** trigger: manual deployment: Production script: - # Write deploy command
順を追って説明します
パイプラインの開始条件を定義
pipelines: branches: master: - step:
定義のルートプロパティとして pipelines
を定義します
次に、どのタイミングでパイプラインを開始するか指定を行います
# 特定のブランチが更新されたときに開始 pipelines: default: # 指定されたブランチ以外の push 時に開始 - step: branches: master: # master ブランチの push 時に開始 - step: feature/*: # 'feature/' で始まるブランチの push 時に開始
# プルリクエストの対象ブランチが更新された時に開始 pipelines: pull-requests: '**': - step:
# 手動・もしくはスケジュールで開始 pipelines: custom: sonar: # UI に表示されるパイプライン名 - step:
いずれの条件の場合でも、Bitbucket Pipeline の UI から特定のブランチ・条件のパイプラインを開始することができます
今回はメインブランチにマージをした際に自動でパイプラインが開始されてほしいためブランチタイプとして master
を指定しています
デプロイスクリプトを定義
- step: name: Deploy to Staging script: - echo 'Hello, World' - some-deploy-command execute
パイプライン内での処理は step
という単位で区切られ、実行するコマンドを script
に配列として定義します
今回の場合はデプロイする処理をこの中に記述します
ある程度決まった処理はパイプを用いることで簡略化できます
例えば AWS EKS への Kubernetes Manifest のデプロイの場合は下記のパイプが利用できます
Bitbucket Pipelines Pipe: AWS EKS run command
- pipe: atlassian/aws-eks-kubectl-run:2.2.0 variables: AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION CLUSTER_NAME: $CLUSTER_NAME KUBECTL_COMMAND: $KUBECTL_COMMAND
なお、環境変数はリポジトリの設定項目から指定できます
デプロイ環境ごとに参照する変数
ステップを Deployments に登録
- step: name: Deploy to Staging deployment: Staging script:
ステップに deployment
プロパティをセットすることで実行後に Deployments 項目に履歴が登録されます
Deployments からは関連 Pull Request やファイル差分の確認ができます
ステップを手動で実行するまで保留
- step: name: Deploy to Staging trigger: manual deployment: Staging script:
trigger: manual
を追加することでそのデプロイステップを明示的に実行するまで保留します
UI から deploy
ボタンを押すとデプロイ前の確認画面が出るようになります
デプロイ先や差分などの最終確認を行うことができるため、慎重にデプロイを行いたい場合はこの定義をお勧めします
特定のファイルの差分がある場合のみステップを実行
Conditional steps and improvements to logs in Bitbucket Pipelines
- step: name: Deploy to Staging condition: changesets: includePaths: - stage/**
condition
を定義することでステップの開始条件を指定できます
現在利用できるのは condition.changesets.includePaths
のみとなり、対象ファイルを配列で指定します
指定したファイルが前回パイプラインが稼働してから差分がない場合はステップが自動的にスキップされるため、必要のないデプロイを防げます
今回の場合は環境ごとにディレクトリを分けているので、変更のあった環境のみデプロイを行わせるために指定を行っています
注意点
最初のステップに trigger: manual
を設定することはできない
何故か仕様として設定できないため、今回は回避策として「何も行わない」ステップを定義しています
pipelines: branches: master: - step: name: Before deployment clone: enabled: false script: - echo . # 何もしない - step: name: Deploy to Staging
clone.enabled: false
を定義することでリポジトリクローンの処理が省かれ、若干実行速度を短縮できます
デプロイステップを並列実行することはできない
parallel
プロパティを用いることで複数ステップを並列実行することができます
例えば依存しない複数のモジュールのビルドを並列実行することで実行時間の短縮ができます(Bitbucket Pipeline では基本的にスケーラブルな Docker コンテナで実行されるため並列実行におけるパフォーマンスの劣化を気にしなくて良い)
pipelines: default: - parallel: - step: script: - echo 'モジュールA のビルド' - step: script: - echo 'モジュールB のビルド'
今回の場合テスト環境のデプロイと本番環境のデプロイはそれぞれ依存しないので、parallel
を利用したいですが、これも仕様として deployment
の場合のみ並列実行が行えません
そのため先にどちらかのデプロイが必要となります
対策として condition
を入れて変更のないデプロイメントを自動省略できるようにしていますが、両方の環境のリソースを更新した場合は順にデプロイする必要があります
デプロイメントの定義順に沿ってステップを定義する必要がある
リポジトリのデプロイメント設定にてデプロイ環境の定義ができますが、ここの順番(Test
→ Staging
→ Production
)の順番に step
の順番も定義しないとエラーになります
# この定義はエラーになる - step: deployment: Production - step: deployment: Staging
補足、改善点
デプロイ画面の差分表示はリポジトリ全体の差分として表示される
例えば、テスト環境のみのデプロイであっても本番環境用のディレクトリの差分が表示されてしまうため、混乱しないよう注意する必要があります
事前に静的なパイプライン定義を行ってからコミットをする
今回のようなリポジトリ内でパイプラインを宣言的に正義する方法では、コミットしてリポジトリにプッシュするまで結果が確認できない という特徴があります
これにより
- 定義ファイルを編集
- コミット & プッシュ
- パイプライン実行でエラー
の手順を繰り返すことが特に構築初期段階では多いです
一方でエラー内容で多い点として下記があげられます
- 定義方法が間違っている
- YAML の文法が間違っている
パイプラインツールではこういったケースに備えて設定ファイルの静的解析ツールを用意しているのもが多く、Bitbucket Pipeline にも存在します
Validator for bitbucket-pipelines.yml
上記のツールでは静的解析に加えてパイプラインの構築サポートも機能として含まれているため、活用すると構築の工数を節約できることが期待できます
Pull Request で検証デプロイを行う
「パイプラインの開始条件」で説明したように Pull Request 上で開始するパイプラインの定義が行えます
Terraform Template や Kubernates Manifest などの Dry-run が行えるリソースに関しては、事前にデプロイ検証が行えているとレビュワーがより安心してマージを行えるようになります
Pull Request 画面には Pipeline のステータスが表示されます
またマージできる条件として「Pipeline が成功していること」を追加できるため、検証済みでないとマージできないよう厳しく設定することも可能です
Bitbucket Pipeline には Pipeline が成功した後に自動マージを行う機能も提供しているため活用するとスムーズに運用が行えるでしょう
Automatic Merging When Builds Pass
必ずメインブランチからデプロイを行う
分岐したそれぞれのブランチからデプロイを行ってしまうと、他のユーザが異なるデプロイを行う際に意図しない差分が発生することにつながります
今回は master
ブランチの更新時のみパイプラインが開始されるようにしていますが、UI からパイプラインを手動で開始する際はどのブランチでも開始することができるため注意が必要です
Preminum プランを用いている場合は、設定画面から特定のブランチ・ユーザのみデプロイを行えるよう設定が可能なのでご活用ください
master
ブランチの更新を Pull Request からのみ許可させることをリポジトリ設定から行うこともできます
最後に
Tagbangers は Atlassian のソリューションパートナーとして、今回紹介した Bitbucket Cloud も含め Atlassian 製品の導入についてのコンサルティング・環境構築・サポート・アドオンの開発を行っております
興味のある方は是非お問い合わせください