GitLabを活用したプラットフォーム・エンジニアリング

こんにちは、中山( @k1nakayama ) です。

皆さんの組織では、プラットフォーム・エンジニアリングについて、既に取り組まれていますか?昨今では様々な場面で、このプラットフォーム・エンジニアリングについて、語られるようになってきています。
しかしながら、なかなかどこから取り組んでよいか分からなかったり、複数のプロジェクト横断で取り組むべき内容であることから、取り組めていない方々が多いのではないでしょうか?

今回は、そんなプラットフォーム・エンジニアリングについて、GitLabを活用して取り組んでいく方法について紹介していきたいと思います。

  • プラットフォーム・エンジニアリングについて興味がある方
  • 複数のチームでソフトウェア開発に取り組んでおり、組織全体で開発者体験の向上を図りたいと考えている方
  • GitLabについて興味があるが、具体的な使い方がイマイチ分からないという方

プラットフォーム・エンジニアリングとは

上記はプラットフォーム・エンジニアリングについて、Gartnerが説明しているものになります。
ここで重要なキーワードは下記となります。

  • セルフサービス型
  • ツール/自動化/情報から成る
  • 抽象化

セルフサービス型で自ら必要なリソースをプロビジョニングすることができ、一貫性のある開発・デプロイメントフローになっていて、それらをツールにより自動化されていることで、開発ライフサイクル上の複雑な物事を抽象化して、エンジニアの活動をサポートするためのプラットフォームとなっているものとなります。

これらに取り組むことにより、開発者体験を向上させ、組織全体で標準化を図れることにより品質の均一化やナレッジの共有を図ることができ、結果としてビジネス価値を向上させていくことが出来ます。

GitLabによるプラットフォームの構築

今回は下記の要素を組み込むことでGitLabを活用したプラットフォームの構築を進めていく方法を紹介いたします。

  • 汎用的なCI/CDの構築
  • アプリケーションのテンプレート化
  • 開発環境
  • 開発プロセスの標準化
  • モニタリング
  • ナレッジ共有

汎用的なCI/CDの構築

ソフトウェア開発を進める上で、CI/CDが構築されている状態で開発を進めると、開発後の手戻りを防ぎやすくなったり、機械的に一連のデプロイ作業が進められるため、ミスなく進めることができ、大幅な工数の削減に繋がります。しかし、そのようなCI/CDをまだまだ導入できていないプロジェクトも多いのではないでしょうか?

CI/CDを構築できていない背景には、そもそもCI/CDパイプラインを構築するために、必要となる知識(学習コスト)が多く必要となることや、プロジェクト毎にデプロイ先やアプリケーション自体の構造が異なるため、毎回パイプラインを構築する知識を十分にもっているエンジニアが構築に当たらなければならないといった問題が多いように思います。

CI/CD components

このような課題を解決していくGitLabの機能として、CI/CD componentsがあります。
CI/CD componentsは、名前の通りCI/CDに必要な各ジョブの定義をコンポーネント化して、再利用可能な構成単位として定義することが出来ます。これにより、例えばPythonコードのユニットテストを行うジョブをコンポーネントとして定義する場合、下記のような定義でコンポーネント化できます。

spec:
  inputs:
    stage:
      default: test
    image:
      default: python:3.12
    basedir:
      default: backend/appname
    targetdir:
      default: functions
---
unittest-job:
  stage: $[[ inputs.stage ]]
  image: $[[ inputs.image ]]
  needs: []
  cache:
    paths:
      - .cache/pip
  script:
    - pip install -U pip
    - pip install -r $[[ inputs.basedir ]]/requirements-dev.txt
    - pip install -r $[[ inputs.basedir ]]/requirements.txt
    - python3 -m pytest -vv $[[ inputs.basedir ]]/$[[ inputs.targetdir ]]/tests/ --cov=$[[ inputs.basedir ]]/$[[ inputs.targetdir ]]/src --junitxml=report.xml --cov-branch --cov-report term --cov-report xml:coverage.xml
  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - $[[ inputs.basedir ]]/**/*
  artifacts:
    when: always
    reports:
      junit:
        - report.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

このような形でユニットテストのコンポーネント化を定義し、下記のように各アプリケーションでは利用します。

include:
  - component: $CI_SERVER_FQDN/my-org/cicd-components/unittest-python@1.0.0
    inputs:
    basedir: backend/app1

stages: [build, test, release]

上記のようにユニットテスト1つとっても、CI/CDの定義を1から行おうとすると複雑だったり、PythonやPytestなどのフレームワークに対する知識に加え、GitLabにおけるユニットテストレポート等の扱い方などの知識も必要となるため、誰にでも簡単に定義できるものではありません。しかし、CI/CD componentsの機能を使用することで、ジョブの定義が抽象化されるため、誰にでも簡単に利用することができるようになります。

CI/CD Catalog

上記を読んでいただいて、感のいい方だとお気づきかもしれませんが、社内で再利用可能なCI/CD componentsが様々な場面で利用できるものとして用意されたとして、果たして本当に使用できるでしょうか?そうです、このままでは共有されているコンポーネントにどのようなものがあるかすら分からず、更にはそのコンポーネントがどんなジョブを実行してくれて、どんなパラメータを受け付けるのかを、自分でテンプレートファイルを読んで解析しなければ使えません。

そこで、そのような情報をまとめたものが、CI/CD Catalogです。
CI/CD Catalogは、各コンポーネントがどんなコンポーネントとして利用できるのかのREADMEと、どんなインプット(パラメータ)を受け付けるのかの情報を体系的にまとめられているカタログであり、このカタログから自分が必要とするコンポーネント情報を見つけて、READMEに従って導入することで、コンポーネントの情報を即座に知ることが出来ます。また、CI/CD Catalogは様々なベンダーやGitLabパートナーからもパブリックに提供されており、多くの人が必要とするCI/CDを手軽に利用できるようにもなっています。

出典:GitLab CI/CD Catalog https://gitlab.com/explore/catalog

アプリケーションのテンプレート化

多くの場合、社内で開発するソフトウェアプロダクトには、共通する点がある場合が多いかと思います。例えば、Webアプリケーションを構築する場合、フロントエンドにNext.js、バックエンドにREST API(AWSのAPI Gateway + Lambda(Python))、データベースはAurora、デプロイはAWS CDKで・・・、という形の大筋の構成は同じという形です。このような場合でも、新たなプロダクトを立ち上げて、アプリケーション独自のコードを書き始める前に、基盤となるコードを用意するだけで何時間、場合によっては何日という時間を費やすことになるかと思います。そして、これらを用意したうえで、上記で紹介したCI/CD Catalogから今回のアプリケーションに適したパイプラインを構築するために必要なコンポーネントを見つけてきてCI/CDを構築し、細かな設定を行い、ようやく独自のコードを開発していく準備が整います。

カスタムプロジェクトテンプレート

そこで利用したい機能が、カスタムプロジェクトテンプレートになります。まずは、上記のようなアプリケーション開発を行う上で基盤となる初期構築を行った状態のリポジトリを作成します。この初期構築には、普段の開発ライフサイクルに必要なブランチがあればブランチ自体も作成しておき、ブランチやタグの保護機能も設定しておきます。また、.gitlab-ci.ymlには、必要なCI/CDパイプラインの定義を行ったものを設定しておきます。ここから先は各アプリケーションで実装内容が異なる、というところまで構築し終えたら、そのプロジェクトの上位グループの設定メニュー > 一般 > カスタムプロジェクトテンプレートで、構築した初期設定済みのプロジェクトを選択します。

あとは、新たなプロジェクトを立ち上げる際に、「新しいプロジェクト」の作成から、「テンプレートから作成」を選択し、グループタブを選択すると、先程設定したプロジェクトが表示され、「テンプレートを使用」のボタンを押下し、プロジェクトの名前等の設定を行うことで、上記で構築済みのリポジトリの状態で、新しいプロジェクトを作成することが出来ます。

ちなみに、これによりリポジトリ内のコードだけでなく、ブランチやタグの保護設定や、機密情報に該当しない機能の設定、イシューボードの設定などもコピーされますので、プロジェクトを立ち上げたあと行うべき作業を最小限にとどめて、即座にアプリケーション固有の開発に着手していくことが可能となります。

開発環境

プロジェクトを開始する際に、エンジニアによってOSやエディタが異なっていたり、プロジェクトに必要な依存関係が正しくインストールされていないことによる時間のロスなど、オンボーディングにおける問題も多くあります。また、業務委託のエンジニアなどに一時的にプロジェクトに加わってもらう場合などでは、1時間でも早く開発環境が整った状態で、整備された手順書などに従って開発を進められると効果的です。

GitLab Workspaces

このような場面で利用したい機能が、GitLab Workspacesです。この機能は、予めAWSのEKSなどの環境上に、GitLab Agent for Kubernetesが入ったKubernetesクラスタを構築しておくことで、プロジェクト内に配置したdevfileに従ってVSCodeを利用したWebIDEの環境を構築することが出来ます。これにより、プロジェクトに合わせた統合開発環境を瞬時に構築する事ができるうえ、ブラウザ上で扱うことができる環境なので、エンジニアはどのような環境からでも安全に開発に携わることが可能となります。また、構築する環境のイメージをカスタマイズできるため、予め必要な依存関係のインストールなどを行っておくことや、統制をとるための各種設定等を行ったうえで提供することができます。更に、全員が同じ環境で開発を進めることができるため、オンボーディング時のマニュアル化などを進めやすく、ナレッジを共有しやすいこともメリットとなります。

開発プロセスの標準化

本記事の冒頭で、プラットフォーム・エンジニアリングの説明の中で「一貫性のある開発・デプロイメントフローになっている」という説明を行いました。この一貫性のあるフローとは、どのようなものでしょうか?

例えば、必ずフィーチャーブランチからmainブランチをターゲットとするMRが作成されていて、マージする前にはコードに対するユニットテストが実行されていて、テストカバレッジは前回よりも落ちておらず、セキュリティスキャンが実行されていて、少なくとも高レベル以上の脆弱性が検出されておらず、依存関係スキャンによりコピーレフト系のライセンスが使われている依存パッケージが含まれていないことを確認した上で、2人以上からの承認をもらっていないとマージが許可されない。MRに対するコードは上記パイプライン上でReview用アプリとして一時的にデプロイがされており、実際に動かして確認ができる状態になっている。更に、MRが承認されマージされると、開発環境にデプロイされ、Gitタグとしてセマンティックバージョンのついたタグを発行すると、ステージング環境にデプロイされ、さらなる手動承認で本番環境にデプロイされる。全てはこのプロセスに従ってコードの開発からデプロイまでが一貫して行われる、といったようなものです。

コードオーナー

上記の流れを統制を効かせて運用していくためには、.gitlab-ci.ymlが勝手に更新されることがなければこのような流れの大部分を満たすことが出来ます。そのため、.gitlab-ci.ymlに対してコードオーナーの設定を行うことにより、当該ファイルの更新時には、通常の承認プロセスに加えて特定のコードオーナーの承認を必要とする形にすることにより、抑制することが可能です。

マージリクエスト認証ポリシー

セキュリティスキャンの結果や、ライセンススキャンの結果に対して、追加の承認を必要とする設定については、マージリクエスト認証ポリシーを設定しておくことで、組織全体で必要な承認を強制することができます。

スキャン実行ポリシー

上記のマージリクエスト認証ポリシーを設定しておくことで、脆弱性が検出されなかった場合などには問題がないものとして処理されますが、例えばシークレットスキャンを必ず実行できているかは問わない形となってしまいます。そこで、必ず実行させたいスキャンについて、スキャン実行ポリシーを設定しておくことで、パイプライン上のスキャンを強制させることができます。

マージリクエストの承認ルール

プロジェクトの設定 > マージリクエストの画面から、承認ルールを設定することが出来ます。この設定を行っておくことで、マージリクエストの必要承認数や、カバレッジチェックなどを設定することができます。ちなみに、この設定はプロジェクト毎に設定となりますが、上記で紹介したカスタムプロジェクトテンプレートによりコピーできる設定となります。

保護ブランチ・保護タグ

mainブランチなどの特殊なブランチに対して、直接プッシュを行うことを禁止するために、保護ブランチとして設定し、そのブランチに対するアクションを実行できるユーザーを設定することなどが可能です。この設定を最上位のグループで全体的に行っておくことで、統制の効いた管理を徹底し、一貫したフローを作ることができます。

モニタリング

プラットフォームエンジニアリングに取り組まれている方であれば、当然ながらDevOpsにおいての取り組みは進められていることと思います。そうなると、上記までで説明したような、開発やデプロイメントの部分に加え、運用フェーズにおけるプラットフォーム化も欠かせません。

インシデント管理

インシデント対応はビジネスに影響を与える可能性のあるものであり、組織内でのナレッジを活かしてできるだけ早期に解決できることが望まれます。このようなものについても、例えばインシデント発生時に報告する内容などを、イシューテンプレートとして設定することで運用を統一することができます。

更に、オンコールスケジュールの管理とエスカレーションポリシーを使用した管理を行うことで、インシデント発生後、◯分経過しても対応がされていなさそうな場合は、オンコールスタッフや特定のユーザーにメール通知される仕組みなども設定可能です。

また、インシデント発生から◯分以内の解決を目標とするといったSLAのための設定も行うことが可能です。

アラート管理

複数のプロジェクトがあれば、様々なアラートを管理する必要があります。しかし、アラートをGitLabで受け取る設定を共通して行うことで、アラート発生後の運用について、全てのプロジェクトで統一した形で進められます。

例えば、AWSのCloudWatch Alarmで検知した問題を、GitLab アラートのWebhook URLでインテグレーションし受け取る形にすることで、各プロジェクトで発生しているアラートを、GitLab上で全て管理することができます。

もちろん、アラートを受け取ったら自動的にインシデントとして起票することもでき、全てのインシデントを欠かさず管理することを自動化することができます。アラートが解決された場合に、その解決通知を受け取ると、作成されたインシデントを解決済みに自動的にすることもできます。

バリューストリーム分析

GitLab上の全てのプロジェクトにおいて、イシュー作成からイシューへの着手、コードの実装、テスト、デプロイといった各フローについて、どのプロセスにどれだけ時間が掛かっているかなどのバリューストリーム(価値を生み出す各種行程)を分析する機能です。GitLabは開発プロセス全体を包括的に管理するプラットフォームとなっているため、イシューの作成からデプロイ、その後のインシデントまでも全てのプロセスについて、細かく分析することが可能です。

このバリューストリーム分析を組織全体で確認することも、グループ単位やプロジェクト単位で確認することもでき、これらの分析からより生産性を高めるためのヒントを得ることができます。

また、DevOpsにおいて一般的な指標とも言える、Four Keysの分析もバリューストリーム分析の一環として提供されており、本番環境へのデプロイ回数や、インシデント発生回数、インシデントの解決までの時間などにより、Four Keysの各指標を分析することが容易に行えます。

ナレッジ共有

最後にナレッジ共有です。プラットフォームとして情報の共有を行いやすくなっていることは重要です。GitLabを使用することで、様々な面で情報やナレッジの共有を図ることができます。

Epic・イシュー

組織全体でEpicを管理することで、プロジェクト横断でのアイディア等の管理を行っていくことや、それらに対するコメントでディスカッションを行い、それらの履歴を残していくことで、どんな経緯でこのような決定が行われたかまでを情報として残し共有することが可能です。

イシューについてはプロジェクト毎の管理となりますが、上記で説明したようにイシューテンプレートを組織全体で共通化することにより、管理していく内容を統一化し、後の保守管理を行いやすくなります。

Wiki

GitLabにはWikiを作成する機能もあります。これを組織全体やグループ、プロジェクト毎に作成することができるので、例えばGitLabを活用した開発の進め方についての、様々なルールやプロセスについての説明をWikiとして残しておくことで、新たにメンバーとして参加する方のオンボーディングに役立てることも可能です。

高度なキーワード検索

高度なキーワード検索機能を使用することで、Epicやイシュー、マージリクエスト、Wikiなどはもちろん、コード内やコミットメッセージ、Epicやイシューに対するコメントなど様々な情報を対象にキーワードで検索を行うことができます。

これにより、過去にこんな問題は無かったか?このような戦略についてどうしていたか?など、様々な場面で組織全体の情報を検索し参考にすることができます。

まとめ

プラットフォームエンジニアリングを自分の組織に取り入れていくことで、開発体験を大きく向上させることができ、ビジネスに貢献できます。しかしながら、そのようなプラットフォームをイチから構築していくことはなかなか難しいものです。

今回紹介したGitLabを活用したプラットフォームエンジニアリングでは、GitLabで使える様々な機能を活用し、自分たちの組織に合わせて自動化された開発プラットフォームを、比較的容易に作ることができ、抽象化されたものにすることができるため、誰でもプラットフォームに従った開発プロセスを進めていくことができるようになるかと思います。

ぜひ試してみてください。

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!