はじめに
こんにちは, Sansan株式会社プロダクト開発部エンジニアの北見です.
最近, 個人開発でCircleCIを使ったビルド&デプロイを構築することができました.
構築過程で「CircleCI Orb」という機能を見つけたのですが, これが非常に有用だったので, 紹介させて頂きます.
CI/CDパイプラインの歴史と構築時の悩み
Jenkins
プロダクトをビルド/デプロイするためのCI(Continuous Integration)やCD(Continuous Delivery)がもつ重要性は昔から叫ばれてきました.
CI/CDサービスでまず皆様が思いつくのは「Jenkins」ではないでしょうか?
オンプレミスサーバーへ簡単にインストールでき, CI/CDの走りとなった最も有名なソフトウェアですね.
GUIをオペレーションのメインとし, 簡単にパイプラインを作れるのが魅力です.
しかし扱うプロダクトが巨大化してくると, Jenkinsのパイプライン/サーバーの保守管理が特定のメンバー(いわゆる「Jenkins職人」)しかできなくなるという属人性も問題視されるようになってきました.
BlueOceanでパイプラインを可視化したり, Jenkins Configuration as Codeでコード化したりといった改善策は挙げられますが, どちらかというと巨大化して訳が分からなくなった物を押し付けられてしまった, というケースの方が多いのではないでしょうか.
「ジョブの更新しておいて」と言われたけれど
- 前任者がいない
- コード管理されてない
から
- そもそもどんなジョブがあるか分からない
- デグレった時のリカバリが難しい
先駆者として偉大な実績を残しているJenkinsですが, 広く使われるにつれ, 管理面での課題も明らかになっていきました.
CircleCI
時代は流れ, AWSを初めとしたクラウドサービスの利用が当たり前になり, CI/CDもできるだけクラウドサービスにお任せして楽をしたい, というニーズが高まってきました.
「CircleCI」は最も成功したクラウドCI/CDサービスの1つです. この記事をご覧の皆様の中にも, 個人/チームで利用されている, という方もいらっしゃるのではないでしょうか?
基本的な使い方は簡単です.
CircleCIのビルドパイプラインとなる仕様書(.ymlファイル)をGithubリポジトリのルート(.circleciフォルダ下)に配置するだけ.
CircleCIはその性質上「Infrastructure as Code」を(ほぼ)強制するので, Jenkinsよりも属人化するリスクが低いと言われています.
管理画面もCircleCIのマネージドサービスです. かっこいい.
しかし, 賢明な読者なら察したかも知れません.
「これって処理が複雑になってきたら, 結局Jenkinsの時と同じように, CircleCI職人ができるだけじゃないの?」
はい, その通りです^^;
.circleci/config.ymlファイルに何行にも渡って記述されたCLIの数々はCI/CDパイプラインの可読性を下げ, 改修を困難にします.
結局CircleCIも, 職人業からは逃げられないのでしょうか?
CircleCI Orb
この問題に一石を投じ, 解決策の1つとなりうるのが「CircleCI Orb」です.
CircleCI Orbは, パッケージ化されたビルドコマンド/パイプラインです.
本来であれば何行にも渡って記述していた処理を, ほんの数行で管理することができます.
AWS連携やSlack連携など, 需要が高いジョブは幸いCircleCI公式経由でリリースされているようですね.
circleci.com
今回は
1. 色々ビルドして
2. デプロイ前イベントとしてAWS CLIを叩き
3. AWS CodeDeployでデプロイする
というフローを想定し, 「AWS CLI」「CodeDeploy」をOrbで利用する例を見てみましょう.
なお, 今回CircleCIそれ自体を具体的に掘り下げることはしないので, ご了承ください.
CircleCI Orbの利用例(AWS CLI/CodeDeploy)
https://circleci.com/developer/orbs/orb/circleci/aws-cli
https://circleci.com/developer/ja/orbs/orb/circleci/aws-code-deploy
CircleCI Orbを使うには以下の2つの設定が最低でも必要です(2020年12月現在)
- CircleCIのバージョン指定を2.1に指定
- 使用するOrbを宣言する
今回はAWS CLIと AWS CodeDeployなので, config.ymlファイルは
version: 2.1 orbs: aws-code-deploy: circleci/aws-code-deploy@1.0.1 aws-cli: circleci/aws-cli@0.1 ...
のようにしてあげればOKです.
https://circleci.com/developer/orbs/orb/circleci/aws-cli#commands-setup
またAWS CLIのOrbは公式ドキュメントを見ると, CLIを実行するIAMユーザのRegion/Access Key ID/Secret Access Keyをプロジェクトの環境変数に登録する必要があることが分かります.
それでは肝心のOrbを使う処理を見てみましょう.
以下に示す `pre-deploy` ジョブは, AWS CLIをインストール&CLIによる操作を行います.
... jobs: pre-deploy: steps: - checkout - aws-cli/setup <-AWS CLIのインストールがこれだけで記述できます! - run: command: | aws XXXXX ... <-ここでもうAWS CLIのコマンドを実行できる! ...
マジで短くないですか?
ではさらに AWS Code Deploy を workflows に組み込んでみましょう.
「masterブランチにmergeされた時だけ, backend/frontendをビルドし, pre-deploy 処理でAWS CLIによる何かしらの事前チェックをして, AWS CodeDeployを実行する」
という実際にありそうなシチュエーションをconfig.ymlに書きおこしてみます.
... jobs: pre-deploy: ... build-frontend: ... build-backend: ... workflows: version: 2 build-and-deploy: jobs: - build-frontend: - build-backend: - pre-deploy: requires: - build-frontend - build-backend filters: branches: only: master ## ↓を書くだけで, AWS CodeDeployが走ります! ## CodeDeployの設定は各自頑張ってくださいm(_ _)m - aws-code-deploy/deploy: application-name: your-application-name bundle-bucket: your-bucket-name bundle-key: your-bundle-key deployment-group: your-deployment-group service-role-arn: your-servicerole-arn requires: - pre-deploy filters: branches: only: master
これ, 短くないですか?(確信)
やりたいことを生のCLIで長々と書くケースに比べ, 大分短いですし, 分かりやすいですね.
これを生の処理と比較してみましょう.
↓の公式サイトから「aws-code-deploy/deploy」がラップしている生のジョブリストを見てみます.
https://circleci.com/developer/ja/orbs/orb/circleci/aws-code-deploy#jobs-deploy
description: >- Ensures an application and deployment group exist then proceeds to bundle and upload an application revision to S3. Once uploaded this job will finally create a deployment based on that revision. executor: aws-cli/default parameters: application-name: description: >- The name of an AWS CodeDeploy application associated with the applicable IAM user or AWS account. type: string arguments: default: '' description: If you wish to pass any additional arguments to the aws deploy command type: string bundle-bucket: description: The s3 bucket where an application revision will be stored type: string bundle-key: description: A key under the s3 bucket where an application revision will be stored type: string bundle-source: default: . description: >- The directory relative to your project to package up into an application revision. type: string bundle-type: default: zip description: >- The file type used for an application revision bundle. Currently defaults to 'zip' type: string deployment-config: default: CodeDeployDefault.OneAtATime description: Predefined deployment configuration name. type: string deployment-group: description: The name of a new deployment group for the specified application. type: string get-deployment-group-arguments: default: '' description: >- If you wish to pass any additional arguments to the get-deployment-group command type: string service-role-arn: description: The service role for a deployment group. type: string steps: - checkout - aws-cli/setup - create-application: application-name: << parameters.application-name >> arguments: << parameters.arguments >> - create-deployment-group: application-name: << parameters.application-name >> arguments: << parameters.arguments >> deployment-config: << parameters.deployment-config >> deployment-group: << parameters.deployment-group >> get-deployment-group-arguments: << parameters.get-deployment-group-arguments >> service-role-arn: << parameters.service-role-arn >> - push-bundle: application-name: << parameters.application-name >> arguments: << parameters.arguments >> bundle-bucket: << parameters.bundle-bucket >> bundle-key: << parameters.bundle-key >> bundle-source: << parameters.bundle-source >> bundle-type: << parameters.bundle-type >> - deploy-bundle: application-name: << parameters.application-name >> arguments: << parameters.arguments >> bundle-bucket: << parameters.bundle-bucket >> bundle-key: << parameters.bundle-key >> bundle-type: << parameters.bundle-type >> deployment-config: << parameters.deployment-config >> deployment-group: << parameters.deployment-group >>
長い^^;
さらに個々のジョブ内でCLIの処理が走る訳ですが, それも生で書いていくとなると... ymlファイルはかなりの長さになってしまいそうですね.
しかし, Orbとしてラップされたジョブを利用した場合はたったの 6行です.
- aws-code-deploy/deploy: application-name: your-application-name bundle-bucket: your-bucket-name bundle-key: your-bundle-key deployment-group: your-deployment-group service-role-arn: your-servicerole-arn
さらに今回はCircleCI公式が出しているOrbを利用しているので, 自分たちでこのパイプラインのメンテをする必要もありません.
config.ymlの例(一部抜粋)
ここまでの処理をconfig.ymlにまとめると↓のような形になります.
version: 2.1 orbs: aws-code-deploy: circleci/aws-code-deploy@1.0.1 aws-cli: circleci/aws-cli@0.1 executors: default: your-own-executor-here: jobs: build-backend: ... build-frontend: ... pre-deploy: executor: default steps: - checkout - aws-cli/setup - run: command: | aws cli XXXX workflows: version: 2 build-and-deploy: jobs: - build-backend: - build-frontend: - pre-deploy: requires: - build-frontend - build-backend filters: branches: only: master - aws-code-deploy/deploy: application-name: your-application-name bundle-bucket: your-bucket-name bundle-key: your-bundle-key deployment-group: your-deployment-group service-role-arn: your-servicerole-arn requires: - pre-deploy filters: branches: only: master
色々と端折ってありますが, 大枠の部分は参考になるかと思います.
CircleCI Orbを使う上での注意点
非常に便利なOrbですが, 使用する上では以下のような注意点もあります.
- CircleCIのバージョンは2.1以上
- 公式提供されている各Orbの挙動はドキュメントを良く読んだ上で使う
- 複数のOrbを組み合わせた時, 思わぬ副作用が発生する場合がある
各Orbでラップしてくれているコマンド/ジョブは公式ドキュメントに生の処理が書かれてますので, 利用前に一読されることをお勧めします.
さいごに
以上, 私が使って良かったと感じている「CircleCI Orb」の紹介をさせて頂きました.
CI/CDの属人性を完全に解消するのは難しいですが, 短い記述が出来るに越したことはないです.
CircleCIのバージョン2.1以上が必要だったり, 各Orb独自の制約/ハマり所などもありますが, CI/CDパイプラインの改善に大きく貢献しうる選択肢であることに間違いありません.
circleci.com
気になったOrbはありましたか?
是非, 皆さんもCircleCI Orbにチャレンジしてみて下さい.