Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

GitHub ActionsでK8sのマニフェストを生成できるようにして開発リードタイムを改善する(後編)

研究開発部 Architectグループ ML PlatformチームのKAZYこと新井です。ちなみに名古屋にある中部支店に所属です。

開発リードタイムを改善するためにGitHub ActionsでKubernetesのマニフェスト生成できるようにした話をします。

前後編の2つに分けて公開しており、今回は後編として具体的な実装部分をお話します。

▼前編 buildersbox.corp-sansan.com

なお、本記事は【R&D DevOps通信】という連載記事のひとつです。

目次

作成したワークフロー

構成図
具体的なワークフロー

処理の流れ

  1. ユーザがパラメータを決めてGitHub Actionsのworkflow dispatchのトリガーを手動で引く
  2. プライベートリポジトリをクローンするためにGitHub Appからトークンを取得
  3. テンプレートが保存されているプライベートリポジトリからCookiecutterでテンプレートを取得(認証に先程のトークン使用)
  4. 取得したファイルをコミットしてプルリクエストを作成

GitHub Appによるトークン取得

デフォルトのトークンは組織内の他のプライベートリポジトリをクローンする権限を持っていません。

そのため権限を持ったトークンを発行する必要があります。

発行する方法は

  • GitHub Appによるトークン認証
  • パーソナルアクセストークンによる認証

があります。

今回はGitHub Appによるトークン認証にします。

パーソナルアクセストークンによる認証は

  • 細かな有効期限コントロールができない
  • 発行した人に管理が依存してしまう

という理由から使いませんでした。

PythonのプライベートパッケージをGitHubで作るときにも同様のことを書きました。

buildersbox.corp-sansan.com

Cookiecutter

Cookiecutterとは、プロジェクトテンプレートからプロジェクトを作成してくれるPython製コマンドラインツールです。 github.com

研究開発部内で利用実績があり馴染みがあるものです。 buildersbox.corp-sansan.com

今回は主にアプリケーションごとに異なるパラメータの制御に用いています。

GitHub Actinsからプルリクエスト作成

Create Pull Requestのアクションを利用しました。 コミットメッセージやOpen/Draft、PRのメッセージなどが自由に設定できるので便利です。

github.com

実装

作成したワークフローファイルがこちらです。

name: Generate Manifest

on:
  workflow_dispatch:
    inputs:
      service_name:
        description: Service name
        required: true
      use_secret:
        type: boolean
        description: Use Secret Value
        default: false
      environment:
        type: choice
        description: Environment
        required: true
        default: staging
        options:
          - development
          - staging
          - production

jobs:
  create-manifest:
    name: "[${{ github.event.inputs.environment }}] Generate manifest."
    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.10"

      - name: Install cookiecutter
        run: pip install cookiecutter

      - name: Generate github token
        id: generate_token
        uses: tibdex/github-app-token@021a2405c7f990db57f5eae5397423dcc554159c # v1.7.0
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.APP_PRIVATE_KEY }}

      - name: Add template
        run: |
          cookiecutter \
          https://x-access-token:${ACCESS_TOKEN}@github.com/eightcard/randd_cookiecutter.git \
          --output-dir services/${{ github.event.inputs.namespace }} \
          --overwrite-if-exists \
          --skip-if-file-exists \
          --no-input \
          project_name=${{ github.event.inputs.service_name }} \
          namespace=${{ github.event.inputs.namespace }} \
          use_secret=${{ github.event.inputs.use_secret }}
        env:
          ACCESS_TOKEN: ${{ steps.generate_token.outputs.token }}

      - name: Create Draft Pull Request
        uses: peter-evans/create-pull-request@b4d51739f96fca8047ad065eccef63442d8e99f7 #v4.2.0
        with:
          base: main
          draft: true
          branch-suffix: timestamp
          add-paths: | # 必要なファイルだけコミットする
            services/${{ github.event.inputs.namespace }}/${{ github.event.inputs.service_name }}/batch/base/
            services/${{ github.event.inputs.namespace }}/${{ github.event.inputs.service_name }}/batch/overlays/${{ github.event.inputs.environment }}/
          commit-message: "[${{ github.event.inputs.environment }}] Add manifest from template."
          title: "[${{ github.event.inputs.environment }}] Create ${{ github.event.inputs.service_name }} batch manifest."

cookicutterのオプションについて補足

--overwrite-if-exists:書き込み先ディレクトリが存在する場合は上書きする

--skip-if-file-exists: ファイルが既に存在する場合はファイル作成をしない

という2つのオプションを付けています。

その理由は環境ごとに別々でマニフェストを作成した際に共通部分のファイルを上書きしてしまわないようにするためです。

研究開発部のアプリケーション基盤ではKustomizeを使って環境差分を管理しています。 そして以下のようなディレクトリ構造を採用しています。

services/<namespace>/
└── <service name>
    └── <application type>
        ├── base/
        └── overlays
            ├── production/
            └── staging/

そのためbaseディレクトリ以下のファイルは環境共通部分になります。

Cookiecutterテンプレート管理に用いた理由

Kubernetesでのテンプレートを用いるための他の候補としてHelmのTemplateがありました。 HelmというのはKubernetes向けのパッケージマネージャーでテンプレートを用いたパッケージ作成機能があります。 helm.sh

Helmも便利*1なのですが、今回は以下の理由でCookiecutterを選びました。

  • Cookiecutter研究開発部内で利用実績があること
  • PythonのJija Templateでテンプレートを扱えること(HelmのTemplateはGo Template)
  • マニフェストファイル自体の追加削除の制御がCookiecutterの方が簡単そうだ感じたこと*2
    • Cookiecutterのドキュメントにはhook機能を用いたファイル制御の例の記載があります

    • 作成したワークフローではuse_secretというオプションでSecretリソース作成の制御をできるようにしました

おわりに

テンプレートから値を入れてプルリクエストを作成することは汎用性が高そうなので今後もどこかで使えるかもしれません。

アナウンス

求人

私の所属するML Platformチームを含む、研究開発部Architectグループでは一緒に働く仲間を募集しています。是非一緒に働きましょう。

R&D MLOps/DevOpsエンジニア / Sansan株式会社

*1:例えば開発時、Cookiecutterでマニフェストのテンプレート確認は一度ファイルへの出力が必要ですが、Helmであればlint, dry-run, debugオプションでファイルへの出力無しでのテンプレート確認ができます

*2:Helmではどうやってやるのが良さそうかわかりませんでした

© Sansan, Inc.