GitHub Actionsは商用システムのCI/CDツールとして使えるか?!

ARISE Tech Blog

Advanced Tech Divisionでデータエンジニアをしている對馬(つしま)です。前回は分析モデルを商用化する際に考慮すべき5つのこと について書かせて頂きましたが、今回は少し毛色を変えてCI/CDについて書かせて頂きます。CI/CDはGitHub Actions、CircleCI、Travis CI、AWS CodePipelineなど、様々なサービスが存在しますが、今回はGitHub Actionsの魅力や商用サービスのCI/CDサービスとして実用に耐えうるか、について簡単に書かせて頂きます。

GitHub Actionsの魅力

GitHub Actionsは2019年11月に一般公開されたGitHub公式のCI/CDサービスです。サービスの詳細については公式サイトやQiita等に多くの記事が公開されているのでそちらを参照頂ければと思いますが、このサービスの魅力は何と言ってもパブリックリポジトリであれば完全無料で利用できることです。プライベートリポジトリについてはプラン毎に月当たりの無料枠がありますが、Freeプランでも2,000分/月なので1回のデプロイに5分かかった場合、400回/月デプロイできる計算になります。十分すぎます。

参考:https://github.co.jp/pricing

何となく安そうだけど商用システムで使いものになるの?ってところが気になるところだと思いますので次にまとめてみました。

CI/CDに求めること

まず、私が商用システムで利用するCI/CDサービスに求めることは下記の通りです。

  1. 低コストであること
  2. ワークフローの定義ができること
  3. 設定の管理がシンプルであること
  4. Terraform等のInfrastracture as codeのデプロイが容易にできること
  5. シェルスクリプトの記述ができること
  6. 環境毎のデプロイが容易にできること

    1. 低コストであること

    冒頭に記載した通り、GitHub Actionsはパブリックリポジトリであれば完全無料です。プライベートリポジトリであってもプラン毎に月当たりの無料枠が設定されておりますので無料枠の中で収めれば、CI/CDにかかるコストは0です。

    2. ワークフローの定義ができること

    GitHub ActionsではYAML形式でワークフローファイルを作成できます。

    以下はシンプルな実装例です。

# ブランチをpushしたら"job1"と"job2"を標準出力する
on: push
jobs:
  # 1. 文字列"job1"を標準出力表示する
  job1:
    runs-on: ubuntu-latest
    steps:
    - run: echo "job1"
  # 2. 文字列"job2"を標準出力表示する ※job1が終わってから実行する
  job2:
    runs-on: ubuntu-latest
    needs: job1 # job1との依存関係を定義
    steps:
    - run: echo "job2"

3. 設定の管理がシンプルであること

上記の通り、YAML形式で1つのファイルで設定を管理するので扱いやすく、ワークフローは構造化するので可読性が高いです。

4. Terraform等のInfrastracture as codeのデプロイが容易にできること

AWSのCloudFormationやhashicorpのterraformなどで公開されているActionsが利用可能です。

以下はterraformをAWSにデプロイするシンプルな実装例です。

on: push
jobs:
  apply:
    runs-on: ubuntu-latest
    steps:
      # 1. 事前設定したGitHubのシークレットからAWSのクレデンシャルを設定
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      # 2. terraformのセットアップ
      - uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: 0.13.5
      # 3. terraform applyでAWSにデプロイ
      - run: |
          terraform init
          terraform apply -auto-approve

欲を言えばCircleCIのワークフローの手動承認機能が欲しいです。事前確認→承認→実行の流れでデプロイできると安心感を持てます。

5. シェルスクリプトの記述ができること

CI/CDサービスで用意された機能だけでは実現できないことに対応できるように個人的にはシェルスクリプトを書けることが絶対条件と考えています。

例えば、node.jsのDOTENVファイルや、AWSのElastic Container RegistryにDockerイメージをPUSHする際のタグなど、デプロイの前段のビルド時に動的に設定したいものがある場合はシェルスクリプトを使わないと実現できません。

「2. ワークフローの定義ができること」の実装例にある通り、GitHub Actionsはシェルスクリプトの記述が可能です。

6. 環境毎のデプロイができること

1つのリポジトリから開発環境や商用環境にデプロイしたいところですが、GitHub Actionsのシークレット(暗号化された環境変数)は環境毎に設定ができないので工夫が必要です。

理想的には複数のシークレットを束ねるコンテキストが存在し、コンテキストを指定してデプロイしたいところです。(例えば開発環境へのデプロイ時に「DEVELOPMENT」というコンテキストを指定すれば開発環境用のシークレットを使用してデプロイできる)

シークレットの設定イメージ(理想)

# 開発環境用
DEVELOPMENT: ←コンテキスト
  VAR_1: aaaaa ←シークレット
  VAR_2: bbbbb
  VAR_3: ccccc

# 商用環境用
PRDUCTION:
  VAR_1: ddddd
  VAR_2: eeeee
  VAR_3: fffff

しかし、2020年11月時点のGitHubは複数のシークレット束ねる機能は存在しません。

シークレットの設定イメージ(現実)

# 開発環境用
DEVELOPMENT_VAR_1: aaaaa ←シークレット
DEVELOPMENT_VAR_2: bbbbb
DEVELOPMENT_VAR_3: ccccc

# 商用環境用
PRDUCTION_VAR_1: ddddd
PRDUCTION_VAR_2: eeeee
PRDUCTION_VAR_3: fffff

では、どうやって環境毎にデプロイするかというと下記の3つの実現方法があると考えています。

  • 環境毎にYAMLファイルを用意し、それぞれで参照するシークレットを書き分ける
  • 1つのYAMLファイル内で環境毎に条件分岐させてデプロイする環境のシークレットを設定するようにする
  • リポジトリを開発環境用と商用環境用に分ける(開発リポジトリを正として、デプロイするソースコードを商用リポジトリに投入する)

1つ目は似たようなファイルを重複管理する手間がかかる。2つ目は分岐条件が必要なのでワークフローが複雑になる。3つ目はリポジトリの管理する手間がかかるものの、1つ目や2つ目の問題点を回避できます。

まとめ

複数の環境(開発、ステージング、商用)にデプロイするには少し工夫が必要ですが、商用システムのCI/CDサービスとして十分使えるのではないかと思いました。簡単に評価結果を下記にまとめました。

凡例:〇(実用に耐えうる)、△(使い方に工夫が必要)、×(実用に耐えられない)

最後に

GitHub Actionsは一般公開されたばかりなのでこれからどんどん進化していくのではないかと思います。日本語の技術記事は徐々に増えてきてますが、商用システムで実用に耐えうるかについての記事は見当たりませんでしたので今回書いてみました。少しでも参考になれば幸いです。