【入門編】GitHub Actionsで「環境依存ファイル」を生成!Workflow環境で動的に生成したArtifactをデプロイ先へ安全に転送する方法 – バージョン管理・CI/CD活用バイブル

【GitHub Actions】ビルド時に生成される「環境依存ファイル」を安全にリレー!動的ArtifactでCI/CDの悩みを解決しよう!

やあ、みんな!先輩エンジニアの〇〇だよ。

新しい技術に触れるのってワクワクするよね!特に、開発を効率化してくれるCI/CD周りは、マスターすれば毎日の作業が劇的に楽になるから、ぜひ深掘りしていきたいところなんだ。

今日は、GitHub Actionsを使って、「環境依存ファイル」を賢く管理する方法について、みんなと一緒に学んでいこうと思う。

「環境依存ファイル」って、例えば `.env` ファイルとか、アプリケーションの設定を記述する `config.json` みたいなものを想像してみてほしい。これらは、開発環境、ステージング環境、本番環境のように、デプロイする場所によって内容が変わってくることが多いよね。

でも、これらのファイルをGitリポジトリに直接コミットするのは、セキュリティ的にも、管理のしやすさの点でも、あまり良い方法とは言えないんだ。特に、APIキーやデータベースのパスワードのような機密情報が含まれている場合は、絶対に避けたい。

じゃあ、どうすればいいんだろう?

そこで登場するのが、GitHub Actionsの強力な機能、Artifact(アーティファクト)なんだ!

Artifactを使えば、ビルドプロセス中に動的に生成されたファイルを、パイプラインの異なるジョブ間で安全に受け渡すことができる。まるで、バトンリレーのように、必要なファイルを次の工程に確実につなげてくれるイメージだね。

今回は、この「環境依存ファイル」をGitHub Actionsで動的に生成し、「upload-artifact」と「download-artifact」アクションを使って、複数のジョブ間で安全に転送する具体的な方法を、初心者のみんなにも分かりやすく、丁寧に解説していくよ。

これをマスターすれば、環境ごとの設定管理の悩みが解消されて、CI/CDパイプラインがもっとスムーズに、もっと安全になるはず!さあ、一緒にこの冒険に出かけよう!

—

🤖 なぜ「環境依存ファイル」の動的な生成と管理が重要なのか?

まずは、なぜこのテーマが重要なのか、その背景を軽くおさらいしておこう。

  • セキュリティの確保: 機密情報(APIキー、パスワードなど)をリポジトリに含めないことが鉄則。
  • 環境ごとの設定: 開発、ステージング、本番など、デプロイ先ごとに異なる設定が必要。
  • 管理の簡素化: 環境ごとの設定ファイルを個別に管理する手間を省きたい。
  • CI/CDの柔軟性: ビルド時に動的に設定を生成し、それをデプロイパイプラインに反映させたい。

これらの課題を解決するために、GitHub ActionsのArtifact機能が非常に役立つんだ。

—

🚀 GitHub ActionsのArtifactとは?

GitHub ActionsにおけるArtifact(アーティファクト)とは、ワークフローの実行中に生成されたファイルやディレクトリの集まりのこと。例えば、ビルドされた実行ファイル、テストレポート、そして今回のように動的に生成された設定ファイルなどがArtifactとして保存・管理できる。

Artifactには、主に以下の2つのメリットがある。

1. ジョブ間のデータ共有: あるジョブで生成したファイルを、後続のジョブで利用できる。
2. 実行結果の保存: ワークフローの実行結果として、後から確認・ダウンロードできる。

今日は、この「ジョブ間のデータ共有」という側面に焦点を当てていくよ。

—

🛠️ 準備するもの

特別なものは何もいらない!

  • GitHubアカウント
  • Gitリポジトリ(GitHub Actionsが設定されていること)

これだけあれば、すぐに始められるよ。

—

📜 HelloWorld的な動的ファイル生成とArtifact転送の基本

まずは、一番シンプルな例で、GitHub Actionsのワークフロー内で動的にファイルを作成し、それをArtifactとしてアップロード、そして別のジョブでダウンロードする流れを見てみよう。

シナリオ:

1. 最初のジョブ (`generate-config`): `app-config.json` という名前のファイルを動的に生成する。
2. 次のジョブ (`use-config`): `generate-config` ジョブで生成された `app-config.json` をダウンロードし、その内容を表示する。

1. `.github/workflows/dynamic-config.yml` を作成しよう

プロジェクトのルートディレクトリに、`.github/workflows/` ディレクトリを作成し、その中に `dynamic-config.yml` という名前でファイルを作成して、以下の内容を記述してほしい。

.github/workflows/dynamic-config.yml

name: Dynamic Config Generation & Transfer

on:
push: # masterブランチへのプッシュでワークフローを実行
branches:

  • main # ご利用のデフォルトブランチ名に合わせてください (例: main, master)

jobs:
generate-config:
runs-on: ubuntu-latest # ワークフローを実行するOSを指定

steps:

  • name: Checkout code # リポジトリのコードをチェックアウト

uses: actions/checkout@v4

  • name: Generate dynamic config file # 環境依存ファイルを動的に生成するステップ

id: generate # このステップにIDを付けて、後で参照できるようにする
run: |
# ここで動的に設定ファイルの内容を生成します。
# 例として、現在のコミットハッシュとタイムスタンプを含めてみましょう。
COMMIT_HASH=$(git rev-parse –short HEAD)
TIMESTAMP=$(date -u +”%Y-%m-%dT%H:%M:%SZ”)
echo “Generated config content:”
echo “{\”environment\”: \”development\”, \”commit_id\”: \”${COMMIT_HASH}\”, \”build_time\”: \”${TIMESTAMP}\”}” > app-config.json

# 生成したファイルの中身を確認 (デバッグ用)
echo “— app-config.json content —”
cat app-config.json
echo “——————————”
shell: bash # bashシェルで実行することを明示

  • name: Upload artifact # 生成したファイルをArtifactとしてアップロード

uses: actions/upload-artifact@v4
with:
name: app-config-artifact # Artifactの名前を指定
path: app-config.json # アップロードするファイルのパスを指定
# retention-days: 5 # 必要であれば、Artifactの保持期間を指定できます

use-config:
runs-on: ubuntu-latest
needs: generate-config # generate-configジョブが完了してから実行する

steps:

  • name: Download artifact # 前のジョブでアップロードしたArtifactをダウンロード

uses: actions/download-artifact@v4
with:
name: app-config-artifact # ダウンロードしたいArtifactの名前を指定
path: ./downloaded-config # ダウンロード先のディレクトリを指定

  • name: Use the downloaded config file # ダウンロードしたファイルの内容を表示・利用するステップ

run: |
echo “Successfully downloaded app-config.json!”
echo “— Content of downloaded app-config.json —”
cat ./downloaded-config/app-config.json # ダウンロードしたファイルパスを指定
echo “———————————————”

📝 コードの解説

順番に見ていこう。

  • `name`: ワークフローの名前。分かりやすい名前をつけよう。
  • `on`: ワークフローがトリガーされる条件を指定する。ここでは、`main` ブランチへのプッシュをトリガーにしている。
  • `jobs`: ワークフロー内で実行されるジョブの集合。
  • `generate-config`: 最初のジョブ。
  • `runs-on`: ジョブを実行するランナー(仮想環境)を指定。`ubuntu-latest` が一般的で便利だよ。
  • `steps`: ジョブ内で実行される一連のステップ。
  • `actions/checkout@v4`: リポジトリのコードを取得するアクション。これをしないと、ファイルが生成できなかったり、後続の処理でコードが使えなかったりする。
  • `Generate dynamic config file`: ここが今回のメイン!
  • `run:` キーの下に、シェルのコマンドを記述する。
  • `git rev-parse –short HEAD` で現在のコミットの短いハッシュを取得。
  • `date -u +”%Y-%m-%dT%H:%M:%SZ”` でUTCのタイムスタンプを生成。
  • `echo “…” > app-config.json` で、これらの情報をJSON形式にして `app-config.json` というファイルに書き込んでいる。これが「動的に生成された環境依存ファイル」だね!
  • `cat app-config.json` で、生成されたファイルの内容を確認している。これはデバッグに役立つから、最初は入れておくと安心だよ。
  • `actions/upload-artifact@v4`: GitHub Actionsが提供する便利なアクション。
  • `uses: actions/upload-artifact@v4`: アクションとそのバージョンを指定。
  • `with:`: アクションに渡すパラメータ。
  • `name: app-config-artifact`: Artifactに名前をつける。この名前で後から参照するから、分かりやすい名前にしよう。
  • `path: app-config.json`: アップロードしたいファイルのパスを指定。ここではカレントディレクトリにある `app-config.json` を指定している。
  • `use-config`: 2番目のジョブ。
  • `needs: generate-config`: このジョブは、`generate-config` ジョブが成功した後にのみ実行されるように指定。依存関係を明示することで、ワークフローの実行順序を制御できる。
  • `actions/download-artifact@v4`: Artifactをダウンロードするアクション。
  • `name: app-config-artifact`: ダウンロードしたいArtifactの名前を指定。`generate-config` ジョブでアップロードした時と同じ名前だね。
  • `path: ./downloaded-config`: ダウンロードしたファイルを保存するディレクトリを指定。ここでは `downloaded-config` という新しいディレクトリを作成して、その中に保存するようにしている。

🚀 動作確認

1. この `dynamic-config.yml` ファイルをリポジトリの `.github/workflows/` ディレクトリにコミット&プッシュする。
2. GitHubの「Actions」タブを開くと、ワークフローが実行されているのが確認できるはず。
3. ワークフローの実行が完了したら、`use-config` ジョブを展開してみよう。
4. 「Use the downloaded config file」ステップのログを見ると、`app-config.json` の内容が表示されているはずだ!

Successfully downloaded app-config.json!
— Content of downloaded app-config.json —
{“environment”: “development”, “commit_id”: “xxxxxxxxxxx”, “build_time”: “2023-10-27T10:00:00Z”}
———————————————

(`xxxxxxxxxxx` の部分は実際のコミットハッシュに、タイムスタンプも実行時間によって変わるよ)

どうかな? `generate-config` ジョブで生成されたファイルが、`use-config` ジョブでちゃんと使えているのが分かるはずだ。これがArtifactの力!

—

🔒 より実践的なシナリオ:環境ごとの設定ファイル生成

さて、HelloWorldは成功したね!
次に、もう少し実践的なシナリオで、環境ごとの設定ファイルを動的に生成して、それをデプロイワークフローに渡す方法を見てみよう。

シナリオ:

1. `generate-env-files` ジョブ:

  • `env` ジョブパラメータで渡される環境名(例: `development`, `staging`, `production`)に応じて、異なる `.env` ファイルを生成する。
  • 生成された `.env` ファイルをArtifactとしてアップロードする。

2. `deploy-to-env` ジョブ (環境ごとに実行):

  • `generate-env-files` ジョブで生成されたArtifactをダウンロードする。
  • ダウンロードした `.env` ファイルを使って、該当する環境へアプリケーションをデプロイする(デプロイ処理自体はダミー)。

1. `.github/workflows/deploy-workflow.yml` を更新

既存の `dynamic-config.yml` を少し変更するか、新しく `deploy-workflow.yml` という名前でファイルを作成して、以下の内容を記述しよう。ここでは、より汎用的にするために、Matrix Strategy を活用してみるよ。Matrix Strategyを使うと、複数の構成(この場合は環境)に対して、同じジョブを並列で実行できるんだ。

.github/workflows/deploy-workflow.yml

name: Deploy to Environments

on:
push:
branches:

  • main # デフォルトブランチへのプッシュでトリガー

環境設定を定義
この envs 配列の各要素が、実行される環境を表します。
env:
envs:

  • env_name: development

api_url: http://dev.example.com/api

  • env_name: staging

api_url: http://staging.example.com/api

  • env_name: production

api_url: http://api.example.com/api

jobs:
generate-env-files:
runs-on: ubuntu-latest
# Matrix Strategy を使って、定義した各環境に対してジョブを実行します。
strategy:
matrix:
environment: ${{ fromJson(env.envs) }} # env.envs を JSON としてパースし、matrix の要素にする

outputs:
env_config_artifact_name: ${{ steps.upload_env.outputs.name }} # Artifact名を後続ジョブで参照できるように出力

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Generate .env file for ${{ matrix.environment.env_name }} # 現在実行中の環境名を表示

id: generate_env
run: |
# 環境名とAPI URLを環境変数から取得
ENV_NAME=”${{ matrix.environment.env_name }}”
API_URL=”${{ matrix.environment.api_url }}”
BUILD_TIME=$(date -u +”%Y-%m-%dT%H:%M:%SZ”)

echo “Generating .env for environment: $ENV_NAME”

# .env ファイルの内容を生成
# ここに環境固有の機密情報などを記述します。
# 例: GitHub Secrets を使う場合は、${{ secrets.MY_SECRET_KEY }} のように参照できます。
echo “NODE_ENV=$ENV_NAME” > .env
echo “API_BASE_URL=$API_URL” >> .env
echo “BUILD_TIMESTAMP=$BUILD_TIME” >> .env
# echo “DATABASE_URL=${{ secrets.DATABASE_URL_${{ env_name }} }}” >> .env # 例: 環境ごとのシークレット

echo “— Generated .env content —”
cat .env
echo “—————————–”
shell: bash

  • name: Upload .env artifact

id: upload_env # 後で outputs で参照できるようにIDを付与
uses: actions/upload-artifact@v4
with:
# Artifact名を環境名を含めてユニークにする
name: env-artifact-${{ matrix.environment.env_name }}
path: .env
# retention-days: 3 # 必要に応じて保持期間を設定

# 環境ごとのデプロイジョブ
# generate-env-files ジョブが完了した後、各環境に対してこのジョブが実行されます。
deploy-to-env:
runs-on: ubuntu-latest
needs: generate-env-files # generate-env-files ジョブに依存
# generate-env-files ジョブで定義された matrix の各要素に対して、このジョブも実行されます。
# つまり、development, staging, production のそれぞれに対して deploy-to-env ジョブが動きます。
strategy:
matrix:
environment: ${{ fromJson(env.envs) }}

steps:

  • name: Checkout code

uses: actions/checkout@v4

# 前のジョブでアップロードされた、対応する環境のArtifactをダウンロード
# downloads-artifact アクションは、job-id の指定で特定のジョブのArtifactをダウンロードできます。
# ここでは、matrix で指定された環境に対応する generate-env-files ジョブのArtifactをダウンロードします。

  • name: Download .env artifact for ${{ matrix.environment.env_name }}

uses: actions/download-artifact@v4
with:
# Artifact名を正確に指定します。
# name: env-artifact-${{ matrix.environment.env_name }} # この書き方でもOKですが、matrix job-id を使うとより安全です。
name: env-artifact-${{ matrix.environment.env_name }} # generate-env-files ジョブの name を参照
path: ./downloaded-env # ダウンロード先のディレクトリ

  • name: Deploy to ${{ matrix.environment.env_name }} # デプロイ処理をシミュレート

run: |
echo “— Simulating deployment to ${{ matrix.environment.env_name }} —”
echo “Using environment variables from downloaded .env file:”
# ダウンロードした .env ファイルを source コマンドで読み込み、環境変数として利用可能にする
# 注意: source コマンドは、そのシェルセッション内でのみ環境変数を設定します。
# 複数のコマンドで一貫して使いたい場合は、export を使うか、file を直接読み込む必要があります。
# ここでは、echo で内容を表示するだけなので、source は必須ではありませんが、
# 実際のデプロイコマンドで環境変数を使いたい場合に役立ちます。
# source ./downloaded-env/.env

echo “NODE_ENV=$(grep NODE_ENV ./downloaded-env/.env | cut -d’=’ -f2)”
echo “API_BASE_URL=$(grep API_BASE_URL ./downloaded-env/.env | cut -d’=’ -f2)”
echo “BUILD_TIMESTAMP=$(grep BUILD_TIMESTAMP ./downloaded-env/.env | cut -d’=’ -f2)”

# ここに実際のデプロイコマンドを記述します。
# 例:
# echo “Deploying application to ${{ matrix.environment.api_url }}…”
# ./deploy-script.sh –env ${{ matrix.environment.env_name }} –config-file ./downloaded-env/.env
echo “Deployment to ${{ matrix.environment.env_name }} completed (simulated).”
echo “——————————————————-”

📝 コードの解説

今回のバージョンでは、さらに高度なテクニックを使っているよ。

  • `env:` セクション:
  • `envs:` というキーで、デプロイしたい環境のリストを定義している。各環境には `env_name` と `api_url` というプロパティを持たせている。
  • `env` セクションで定義した変数は、ワークフロー全体で参照できる。
  • `strategy.matrix`:
  • `generate-env-files` ジョブと `deploy-to-env` ジョブの両方で `strategy.matrix` を使っている。
  • `environment: ${{ fromJson(env.envs) }}` とすることで、`env.envs` で定義したリストの各要素(各環境)に対して、それぞれ独立したジョブインスタンスが生成される。
  • これにより、`development`, `staging`, `production` の3つの環境それぞれに対して、`generate-env-files` と `deploy-to-env` が実行されることになる。
  • `generate-env-files` ジョブ:
  • `run:` ステップの中で、`matrix.environment.env_name` や `matrix.environment.api_url` のように、Matrixで定義された現在の環境の情報を参照している。
  • `echo “…” > .env` や `echo “…” >> .env` で `.env` ファイルに情報を追記している。
  • GitHub Secrets の利用例: コメントアウトされている `echo “DATABASE_URL=${{ secrets.DATABASE_URL_${{ env_name }} }}” >> .env` の部分が重要。
  • `secrets.DATABASE_URL_${{ env_name }}` のように、環境名に応じて異なるGitHub Secretsを参照できる。
  • 例えば、`production` 環境では `secrets.DATABASE_URL_production`、`staging` 環境では `secrets.DATABASE_URL_staging` が参照される。
  • これにより、機密情報をリポジトリ外のGitHub Secretsに安全に保管し、必要な時だけワークフローで参照・利用できる。
  • Artifact 名の動的設定: `name: env-artifact-${{ matrix.environment.env_name }}` のように、Artifact名に環境名を含めることで、どの環境の設定ファイルなのかを識別しやすくしている。
  • `deploy-to-env` ジョブ:
  • `needs: generate-env-files` で依存関係を定義。
  • Artifact のダウンロード:
  • `uses: actions/download-artifact@v4`
  • `name: env-artifact-${{ matrix.environment.env_name }}`: ここで、`generate-env-files` ジョブで生成された、該当する環境のArtifact名を正確に指定する必要がある。
  • `path: ./downloaded-env`: ダウンロード先のディレクトリ。
  • `.env` ファイルの利用:
  • `run:` ステップの中で、ダウンロードした `.env` ファイルの内容を読み込んで、デプロイコマンドで利用する。
  • `echo “NODE_ENV=$(grep NODE_ENV ./downloaded-env/.env | cut -d’=’ -f2)”` のようなコマンドは、ダウンロードした `.env` ファイルから特定のキーの値を取得して、それをechoで表示している。
  • 実際のデプロイでは: `source ./downloaded-env/.env` のようにして `.env` ファイルを読み込み、その後のコマンドで直接環境変数(例: `$NODE_ENV`, `$API_BASE_URL`)を参照できるようになる。

🚀 動作確認

1. この `deploy-workflow.yml` ファイルをリポジトリの `.github/workflows/` ディレクトリにコミット&プッシュする。
2. GitHubの「Actions」タブを開く。
3. 「Deploy to Environments」ワークフローが実行されるはず。
4. ワークフローを展開すると、`generate-env-files` ジョブが `development`, `staging`, `production` の3つの環境それぞれで実行され、その後、`deploy-to-env` ジョブも同様に3つの環境それぞれで実行されるのが確認できる。
5. `deploy-to-env` ジョブのログを見ると、各環境に対応した `.env` ファイルがダウンロードされ、その内容が利用されている(シミュレーションされている)のが分かるだろう。

これで、環境ごとの設定ファイル生成と、それを安全にデプロイパイプラインへ渡すという、より実践的なCI/CDワークフローが実現できたね!

—

🚀 CI/CDパイプラインをさらに極めるためのヒント

今回紹介したArtifactを使ったファイル転送は、CI/CDの自動化における強力な武器になる。さらにパイプラインを最適化するために、いくつかヒントを共有しよう。

1. Artifact の保存期間:

  • `upload-artifact` アクションには `retention-days` というオプションがある。
  • 通常、Artifactはデフォルトで90日間保存されるが、不要になったArtifactは早めに削除することで、ストレージコストの削減や管理の簡素化につながる。
  • 短い期間(例: 3日、7日)で十分な場合は、明示的に設定しておこう。

2. Artifact の命名規則:

  • Artifactの名前は、後から識別しやすくするために、一貫性のある命名規則を適用するのがベスト。
  • 環境名、ビルドID、ファイルの種類などを組み合わせると、管理が楽になる。
  • 例: `build-${{ github.run_id }}-${{ matrix.environment.env_name }}.zip`

3. 機密情報の管理:

  • `.env` ファイルや設定ファイルに機密情報を含める場合は、必ずGitHub Secretsを活用しよう。
  • `secrets.YOUR_SECRET_NAME` の形式で参照できる。
  • 環境変数としてワークフローに渡すだけでなく、`secrets` を使って安全に保管・利用することが、セキュリティの基本中の基本だ。

4. Artifact の圧縮:

  • 複数のファイルをArtifactとしてアップロードする場合、`upload-artifact` は自動的に圧縮してくれる。
  • しかし、もし特定のディレクトリ全体をアップロードしたい場合は、`path` にディレクトリ名を指定するだけでOK。GitHub Actionsがディレクトリごと圧縮してくれる。

5. ジョブ間の依存関係の最適化:

  • `needs` を適切に設定することで、不要なジョブの実行をスキップしたり、並列実行できるジョブを効率的に配置したりできる。
  • ワークフローの実行時間を短縮し、コストを削減するのに役立つ。

6. `download-artifact` の `job-id` オプション:

  • 今回の例では、Artifact名を明示的に指定したが、`download-artifact` には `job-id` というオプションもある。
  • `job-id: generate-env-files` のように指定すると、指定したジョブIDで生成されたArtifactをダウンロードできる。
  • Matrix Strategy を使用している場合、`job-id` に Matrix の値を含めることで、より正確に目的のArtifactをダウンロードできる場合がある。
  • 例: `job-id: generate-env-files-${{ matrix.environment.env_name }}` (※ジョブID自体もMatrixで生成されている場合)
  • 今回のようにArtifact名にMatrixの値を含めている場合は、Artifact名を直接指定する方がシンプルで分かりやすいことが多い。

—

🎉 まとめ

お疲れ様!

今回は、GitHub ActionsのArtifact機能を使って、ビルド時に動的に生成される「環境依存ファイル」を、複数のジョブ間で安全かつセキュアにリレーする方法を学んだね。

  • `actions/upload-artifact` でファイルをアップロード。
  • `actions/download-artifact` でファイルをダウンロード。
  • Matrix Strategy を活用して、複数の環境に対する処理を効率化。
  • GitHub Secrets と組み合わせることで、機密情報も安全に管理。

これらのテクニックをマスターすれば、環境ごとの設定管理の悩みが解消され、CI/CDパイプラインがもっとスムーズに、もっと安全に運用できるようになるはずだよ。

新しい技術に触れるのは、時に難しく感じることもあるかもしれない。でも、一つ一つ丁寧に理解を深めていけば、必ず自分の力になる。今回学んだことを、ぜひあなたのプロジェクトで試してみてほしい。きっと、毎日の開発作業が、もっと快適になるはずだから!

また、何か分からないことや、さらに深掘りしたいことがあれば、いつでも気軽に声をかけてね。みんなのDevOpsライフを応援しているよ!

それでは、また次回の記事で会おう!

タイトルとURLをコピーしました