ここまで課題の抽象度を高められると、次に何をすべきなのかが見えてきます。ここからはCI/CDを用いて私がGoogle Groupsの管理を自動化するまでに歩んだ手順をなぞって紹介します。
まず作業する対象、すなわちソフトウェア開発におけるテストの対象やデプロイの対象がプログラマブルであることを確認します。これがプログラマブルではないと、そもそもCI/CDを活用できません。
デプロイ対象であるGoogle Groupsの操作は、Googleが提供しているAPIを利用できます。次に、申請はプログラマブルである必要もあります。旧来の環境では、プログラマブルとは言えませんでした。紙の申請書を模倣したようなフォームを提供する申請管理システムが採用され、申請内容は、自由記述のテキストエリアに記述されていました。自由に記述できるため、ユーザーが思い思いに記述します。申請書自体がプログラマブルな形で取得できるかどうか以前に、申請の内容が構造化されていません。しかし、これはこの申請そのものの仕組みを変えてしまえば解決できると考えました。
申請内容をまずは構造化する必要があります。構造化されたデータとして、この例ではYAMLというフォーマットを採用しました。
YAMLとは、第1回、第2回で登場したGitHub Actionsの設定を記述するのにも使われている構造化されたデータを表現するための文書フォーマットです。YAMLはハッシュと配列を扱えるため、Google Groupsとそのメンバーという構造を扱うのに向いていそうだと考えました。
また、YAMLは行指向のフォーマットです。これは、CI/CDを利用して自動化する場合は1つのメリットとなります。
CI/CDを用いて自動化する場合、CI/CDから扱いやすいデータを使いたいというモチベーションが生じます。必然的に構造化されたテキストデータを使うことになります。
そして、申請を受理した場合その受理した内容を取り込む、すなわち差分の取り込みをサポートする環境があると便利です。取り込んだ結果がその管理対象のシステム(ここではGoogle Groups)全体の状態を示すものとなるからです。このような構造化されたデータは、それを扱う手段が豊富です。例えば契約が終了した取引先が参加しているGoogle Groupsを抽出するような作業を、テキストエディタの検索機能や、grepコマンドのようなCLIコマンドなど、作業者のスキルに応じてさまざまな手段を選択できます。
これらのモチベーションが、結果的にGitHub上のリポジトリにデータを置きたいというモチベーションにつながります。そして、gitの差分は行指向です。従って、YAMLが行指向の記述をサポートしているのは大変都合が良かったのです。
そして、GitHubで作成したPull Requestを申請として扱うことも、Pull Requestの仕組みが持っている強みを享受できます。それは、変更の内容が実際のYAMLという構造化データの差分として見えることに加え、Pull RequestのDescriptionを用いて、その変更の意図を説明できることです。Pull Requestによる申請を用いると、Descriptionが詳細に記述されるかは申請者次第ですが、少なくとも加えられる変更は個別具体的に示されることになります。どのような変更かが明確になり、承認者と作業者がそれを把握するための負担も軽減されます。
ここまで前置き、考え方の紹介をしてきました。ここからは実施のツールの紹介と運用例を紹介します。まず、YAMLに基づいてGoogle Groupsに変更を加えるCLIツール(josef)を作成しました。
そして、下記のようなYAMLを生成します。すでにGoogle Groupsを運用している場合、josefの機能を用いてそれを全てYAMLに出力することも可能です。
- group_mail_address: example@ml.example.com members: - member1@example.com - member2@example.com
このようなYAMLをGitHub上で管理します。次に、josefを使ってGitHub Actionsを用いたCI/CDを構築します。
この申請の内容をチェックするGitHub Actionを構築しており、これがCIに近い役割を担います。josefでdiffを出力することで、このYAMLの変更がそもそもYAMLのフォーマットを守っているのか、また意図した以上の変更が生じないかが確認できます。GitHubにはSecretという機能を用いて認証情報を保持する機能があり、その機能を利用してGoogle Workspaceのサービスアカウントのクレデンシャルを保存しています。josefとGoogleのAPIラッパーの都合でjsonの形で扱いたいため、変換する処理を挟んでいます。それが「bundle exec ruby bin/make_credential.rb」です。環境、運用で取り扱い方はさまざまだと思うので、詳細は割愛します。
name: DryRun on: pull_request: jobs: dry-run: name: DryRun container: ruby:3.0.0 env: GOOGLE_WORKSPACE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_WORKSPACE_SERVICE_ACCOUNT_JSON }} GOOGLE_WORKSPACE_ACTOR: "actor@example.com" GOOGLE_WORKSPACE_CREDENTIAL_PATH: ./credential.json DOMAINS_FILE_PATH: ./domains.yml steps: - uses: actions/checkout@v2 - name: DryRun run: | gem install bundler:2.1.4 bundle config set path 'vendor/bundle' bundle install --quiet git checkout . bundle exec ruby bin/make_credential.rb bundle exec josef diff ./groups.yml --exclude ./execution_groups.yml
申請がYAMLになったことで、変更内容に禁止されている操作、例えば特定のGoogle Groupsには社外のメールアドレスを追加してはならないなどを検査することも可能です。次に、このYAMLを変更するPull Requestがマージされたときに実行されるCDに当たるActionを見ていきます。
name: Apply on: push: branches: - main jobs: apply: name: Apply container: ruby:3.0.0 env: GOOGLE_WORKSPACE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_WORKSPACE_SERVICE_ACCOUNT_JSON }} GOOGLE_WORKSPACE_ACTOR: "actor@example.com" GOOGLE_WORKSPACE_CREDENTIAL_PATH: ./credential.json DOMAINS_FILE_PATH: ./domains.yml steps: - uses: actions/checkout@v2 - name: setup run: | gem install bundler:2.1.4 bundle config set path 'vendor/bundle' bundle install --quiet git checkout . bundle exec ruby bin/make_credential.rb - name: print diff run: bundle exec josef diff ./groups.yml --exclude ./execution_groups.yml - name: apply run: bundle exec josef apply ./groups.yml --exclude ./execution_groups.yml
CI/CD活用後のフロー
このActionを構築することで、作業者の手順はCIが適切に実行されていることを確認してマージするだけになります。すると、先に示した「旧来のGoogle Groups運用フロー」はこのように変わります。
見た目上、派手な変化は感じられないかもしれません。しかし、変更作業が人の手作業からjosefによる実行、かつCI/CDを用いて自動化されたことで大量の申請にも対処可能になりました。オンボーディングの際にたくさんのGoogle Groupsに追加してもらうように申請され、作業者がその作業をこなすのに数十分かけることもなくなりました。
作業のステップが増えているように見えますが、作業者の作業量は削減されています。申請管理システムを開き、申請内容を確認し、Google Workspaceの管理画面を開いて適用していた作業が、GitHubのPull Requestの画面のみで完結するようになっているためです。分かりやすくするために作業者がマージする構造を取っていますが、一般的なソフトウェア開発同様、申請者や承認者がマージする運用にすることも可能です。
GMOペパボでCI/CDを活用した申請、承認、適用のフローは他にもあります。その1つが「Slack」のユーザーグループへのユーザーの追加です。ユーザーグループへのユーザー追加も、Pull Requestを申請とする運用をしています。誰でもユーザーグループ追加を好きにできるようにした場合、役割が重複したグループが生まれてしまったり、オンボーディングのフローに必要なものを管理職が把握しきれなかったりするなどの弊害が発生します。
申請をPull Requestに統一することで、ユーザーグループの作成や編集といった作業もオープンなものとなります。それにより、過去にオンボーディングで使ったPull Requestを参照することでどのユーザーグループに参加すべきかも参照可能です。こちらはArisaidとYAMLを用いて実現しています。
GMOペパボではIDaaS(IDentity as a Service)に「OneLogin」を採用しています。大抵のIDaaSにはアプリケーションあるいは役割の組み合わせをユーザーに付与する「Role」と呼ばれる機能があります。OneLoginにもその機能がありますが、このRoleにユーザーをひも付ける作業もやはり手作業で実施すると漏れが出たり、作業までの待ち時間が発生してしまったりしていました。このRoleは割り当てられるものでアクセスできるSaaSが変わります。つまり、誤ったRoleを割り当てると本来見られるべきではない情報資産にアクセスできてしまいます。
またその情報資産に対するアクセスを許可するという承認をするフローを構築する必要も出てきます。これもやはり、YAMLを基にRole割り当てを実施するCLIツールを作成し、申請、承認、適用のフローにCI/CDを組み込み自動化しています。
ある部門に配属になった人にはこのRoleを割り当てるというような定型的な対応がPull Requestの履歴として残るため、オンボーディングの際にも効果的な仕組みです。こちらも、Slackのユーザーグループと同様、Roleの割り当てを管理し制限することそのものが目的ではありません。統制を取りつつもその仕組みにより効率的に割り当てることを目的として実施しています。
3回の連載に渡り、CI/CDの仕組みやCI/CDの仕組みを組み込むことによる自動化、効率化、そしてソフトウェア開発の範囲を超えたCI/CDの仕組みの活用方法を紹介しました。第3回では、ソフトウェア開発におけるCI/CDが組み込まれるフローを、抽象度の高い視点で捉えた上でソフトウェア開発以外の作業にCI/CDを組み込む視点、考え方を紹介しました。ソフトウェア開発に限定することなくCI/CDを組み込むことで、ソフトウェア開発以外の業務においても効率化を図ることができます。
CI/CDで実現する自動化は、業務の効率化をもたらします。この効率化は、1つのCI/CDの実行や自動化された作業にだけ注目すると小さいものに見えるかもしれません。しかし、これが繰り返し実行され、何度も積み重なることで得られる効率化は、組織のスケールアップに負けないフロー、貢献できるフローを作ることに役立ちます。また1つのフローにCI/CDを組み込むことで他のフローにも組み込められると気が付けるかもしれません。
読者の皆さんの組織でも、ソフトウェア開発においてはもちろんのことそれ以外の作業にもCI/CDの仕組みを取り入れてみてはいかがでしょうか。
GMOペパボのコーポレートエンジニア部門に所属。Rails製社内サービスの実装やエンドポイント管理やSaaS運用など、手広くやってます。
Copyright © ITmedia, Inc. All Rights Reserved.