【SREチーム ブログリレー3回目】
こんにちは。エンジニアリンググループ、SRE の伴です。
エムスリーでは、AWS クラウド上に GitLab をホスティングして使っています。このため、 GitLab CI を使った CI/CD の構築が積極的に行われています。
SRE チームでも、インフラの管理に Infrastructure as Code (以下、IaC) ツールを利用しており、そのコードを GitLab で管理し、CI/CD を構築しています。
しかし昨年時点では、SRE 管理のリポジトリで CI/CD を構築できていないものがまだまだ存在していました。このため、昨年5月にエムスリーにジョインしてから、それらリポジトリ CI/CD の改善をしています。
ここでは、その改善の一部である「Trigger 機能を使った CI/CD 構築」と「gitlab-comment の導入」について紹介させてください。
これまでの運用と GitLab CI
SRE チームのタスクに、全社で共通するインフラの管理があります。例えば、DNS レコードの登録・削除や、オンプレサーバの更新などです。
これらは、Roadworker や Ansible といった IaC ツールで管理されています。
一方で、管理はされているものの CI/CD の構築はされておらず、更新の度にチームの誰かが手動で適用する運用が取られていました。
これまでの運用の流れ
CI/CD を構築する以前を紹介すると、以下のような流れで作業していました。
- コードを修正して MergeRequest (以下、MR) を作る
- MR をマージ
- 踏み台サーバで git pull
- 手動で IaC のツールを使ってリリース
- リリースしたログを残す
という様な手順をひとつずつ真心込めて手動で行っていました。
手順こそ簡単なものの、それなりに頻繁に発生する作業な上、ある程度の時間もかかるため、なんとか解消したい! となっていました。
Trigger 機能を使った CI/CD 構築
課題
基本的には、インフラコードを管理しているリポジトリで CI を組めば良いのですが、一部リポジトリではそう単純には行きませんでした。
例えば、歴史的経緯から Ansible を管理するリポジトリは、社内のエンジニアに広く権限が与えられています。SRE 以外も閲覧でき、かつ MR も作成できる様にしているためです。
このため、Ansible を管理しているリポジトリで CI/CD を組んでしまうと、SRE 以外にも CI/CD の実行権限が与えられるため、インフラの更新ができてしまい監査的にも問題となります。
また、実行権限以外にも秘密鍵等のクレデンシャルの保管にも注意する必要があります。
GitLab では CI/CD Variables として、環境変数やクレデンシャルを保存できますが、Maintainer 以上の権限があれば閲覧できてしまいます。実行できなくするとしても、各インスタンスへ接続に使う秘密鍵等をリポジトリに登録してしまうと、SRE 以外の知られてはいけない人にも秘密鍵が閲覧できてしまい、本来許可されていないサーバへ強い権限でログインできてしまう恐れがありました。これももちろん、監査的に問題となります。
こういった場合の理想としては、リポジトリに適切な権限を割り振り直して SRE のみが強い権限を持つべきです。しかし、リポジトリより上位レイヤの Namespace (GitHub で言うところの Organization 相当) 単位で割り当てられた権限があったり、リポジトリ自体の利用者数が多いことから、権限を振り直しリポジトリ構成を作り直すのはコストが大きく、避けたい状態でした。
これらを踏まえると、新たに構築する CI/CD の条件は以下のようになります。
- エンジニアなら誰でも、Ansible リポジトリを閲覧したり、MR を出すことが可能
- SRE だけがその MR から CI/CD を実行可能
- CI/CD に使う秘密鍵などは、権限が無いユーザの目に触れない
Trigger 機能を使ってみる
今回、これらの解決のために使用したのは、GitLab の Trigger 機能です。Trigger 機能は、特定のブランチやタグに対して Pipeline を生成する機能です。これは、同じリポジトリでも、異なるリポジトリに対しても使える機能になります。
今回は、SRE しか存在しない Namespace を用意し、この機能を使って Ansible を適用するための Pipeline を生成するようにしました。 Pipeline の構成図は以下のようになります。
Ansible のリポジトリでは、SRE のみ所属するリポジトリ(図中、NamespaceB) の ansible_ci リポジトリに、Trigger 機能を使って連携するのみとなります。
この Trigger 機能の良いところは、Trigger 先リポジトリに実行権限がないユーザは、 Trigger 元の Pipeline からはジョブを実行できない点です。また、Pipeline 自体は NamespaceB で作成されるため、 CI/CD Variables も NamespaceB に登録すれば、権限のないアカウントからは閲覧できない点も良い点です。
実際に組んだ Ansible リポジトリの .gitlab-ci.yml は以下のようになりました。
stages: - trigger trigger_pipeline: parallel: matrix: - target: - serviceA - serviceB - serviceC - (...省略...) stage: trigger trigger: project: NamespaceB/ansible_ci branch: main variables: TARGET: $target PARENT_COMMIT_SHA: $CI_COMMIT_SHA (...省略...) rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE =="web" when: manual changes: - $target/**/*
少し工夫している点としては、Ansible で管理しているサービスは非常に多いため、GitLab CI の parallel 機能を使って、順次 CI/CD 構築できたものを target に加えるだけで簡単に対象サービスを追加できるようにしています。現在も更新頻度の高いものから CI/CD 構築している最中です。
実際に Pipeline を実行すると以下のように Pipeline が表示されます。
ansible_ci 側の Pipeline では、Trigger 元の Variables (今回で言うところの、TARGET
や PARENT_COMMIT_SHA
) を受け取れるため、これらを使って適切なブランチとサーバに対して変更を適用できます。
GitLab Comment の導入
次に、CI/CD を回したあと、CI/CD の実行結果を MR のコメントに残したいとなりました。これはリリースしたログを残す必要があったことと、CI/CD ログを都度見に行かなくてもMR を開けば、すぐに出力結果を確認できたほうが便利だろうと考えたためです。
そこで、そういった GitLab 用のツールが無いか探しましたが、残念ながら見つからなかったため gitlab-comment というツールを開発しました。元は GitHub 用の OSS として公開されていたものをフォークして、GitLab 用に書き換えたものになります。
ここでの gitlab-comment を使う利点は、必要なコマンドの実行結果のみをコメントに残せる点です。素のログを見に行くと、CI/CD に使うツールのインストールなどのログが冒頭に多く、読みづらさがありますが、gitlab-comment を使うことで、必要な結果だけを選択してコメントに残せるため便利です。
これで、MR を見ればそのMR Pipeline の成功・失敗や変更内容が分かりますし、リリースログを残す作業も MR のコメントやログを参照すれば良くなったため、チームからはリリースの体験が良くなったと評価いただきました。
実際に他のチームでも利用いただいている様で、過去の記事でも、実際の利用例を交えて少し紹介いただいています。
まとめ
GitLab CI でリリース体験の向上に挑戦してみたお話でした。本来なら Namespace もしくはリポジトリ単位で権限を分離するところ、Trigger 機能を権限の分離に活用してみたら思いのほか上手くいきました。似たような要望や事例があるかは分かりませんが、もしあればその一助になれば幸いです。
まだまだ SRE が管理するリポジトリの中には、様々な理由から CI/CD 構築できていないリポジトリもあるため、これからも改善に挑戦していきたいと思っています。
We are hiring!!
エムスリーでは CI/CD 改善に興味のある SRE エンジニアを募集しています。
もちろん SRE に限らず各種エンジニア大歓迎です。CI/CD に限らずエムスリーのエンジニアに興味を持っていただいた方は、ぜひとも以下のリンクからお問い合わせ下さい!