LoginSignup
106
75

【初心者向け】【入門】GitHub Actionsの書き方についてデバッグ設定、runs-onやcheckoutなどの仕組みや構造も含めて徹底解説

Last updated at Posted at 2022-10-10

概要

GitHub Actionsの

  • 仕組みや構造
  • 基本的な書き方(ワークフロー、ジョブ、イベントなど)
  • よく出てくるruns-on、actions/checkoutで何してるのか
  • 環境変数とsecrets
  • サービスコンテナ
  • 環境のsetup
  • 権限

について解説していきたいと思います

そもそもGitHub Actionsとは

公式に

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline.

と書かれているようにビルド、テスト、デプロイなどを自動化するCI/CDプラットフォームのことです
今まではCircleCIやTravisCIなどの外部サービスと連携する必要がありましたがGitHub Actionsと使うことでCI/CDをGitHub内で完結させることができるようになりました

GitHub Actionsの仕組み

.github/workflowsディレクトリ内にymlファイルを設置し、Workflow(ワークフロー)をファイル内に書きます。指定したEvent(push、pull_requestなど。後述)が発生すると実行されます

.github/workflowsのディレクトリ名を間違えると実行されないので注意してください

Workflow(ワークフロー)はJob(ジョブ)単位で分けられています
JobはRunner(ランナー)という仮想マシンのインスタンス上で実行されます
JobはさらにStep単位で分けられており、Step内にコマンドなどの処理が実行されます。
github_actions.jpg

書き方を学んでいこう!

簡単なワークフローを例に書き方を少しずつ学んでいきましょう
今回説明するのは

  • jobs
  • on
  • runs-on
  • uses
  • steps
  • run
  • env
  • secrets
  • service container

です。かなり量が多いですが一つずつ確認していきましょう

jobs

処理の最上位単位です
jobsの中に1つ以上のジョブIDと共に処理が設定され、並列で実行されます

.github/workflows/tutorial.yml
jobs:
  # "my_first_job"というジョブIDでジョブを定義
  my_first_job:
    name: My first job
  # "my_second_job"というジョブIDでジョブを定義
  my_second_job:
    name: My second job

左のJobsにジョブ名が記載されます

スクリーンショット 2023-06-15 10.26.05.png

on

どのイベントが発生したら処理を実行するか指定します

.github/workflows/on.yml
# リモートリポジトリへpush時にjobsを実行
on: [push]

よく使われるのは以下の表のとおりです

イベント 説明
push リモートリポジトリへpush時
pull_request プルリクエスト作成時
deployment デプロイ時
release リリース時
issues GitHub Issues関連の処理発生時
schedule cronによる定期実行

上記以外で使用できるイベントはかなり多いため、詳細はドキュメントを参照してください

runs-on

ジョブを実行するOS(ランナー)を指定します

.github/workflows/os.yml
# ubutnuの最新版を指定
runs-on: ubuntu-latest

指定したランナーの詳細は実行する際にSet up jobsという項目が表示されるのでそこから確認できます
スクリーンショット 2022-10-10 9.40.52.png

一般的なWeb開発ではUbuntuを選択するケースが多いかと思います(ローカル上で動かすコンテナのイメージがUbuntuかAlphineのため)
使用できるランナーの一覧は以下の通りです

使用できるランナー(OS) 記述方法 メモ
Windows Server 2022 windows-latest/windows-2022 windows-latestと記述してもWindows Server 2022を指定できる
Windows Server 2019 windows-2019 -
Ubuntu 22.04 ubuntu-latest/ubuntu-22.04 ubuntu-latestと記述してもUbuntu 22.04を指定できる
Ubuntu 20.04 ubuntu-20.04 -
macOS 13 macos-13 Beta版
macOS 12 macos-latest/macos-12 macos-latestと記述してもmacOS 12を指定できる
macOS 11 macos-11 -

uses

第三者もしくはGitHubが作成したActionsをyml内に記載することで実行することもできます
よく使われているのがGitHubが用意しているactions/checkout@v4です

.github/workflows/checkout.yml
  - name: Checkout
    uses: actions/checkout@v4

usesに見たことない文字列が表示されていることが多いのでそういう時は下記のmarketplaceから検索してみましょう

actions/checkout@v4って何してるの?

興味のある方だけ見ていただければ幸いです
簡単なActionを作ってみたので挙動を確認してみましょう
今までのおさらいで

  • jobs
  • on
  • runs-on

を使用しています。後述のsteps、name、runについては後ほど説明します
現時点ではこれ書いてたらコマンド実行できるんだなあと思っていただけたらと大丈夫です
リモートリポジトリへpushすると

  • (チェックアウト前の)ファイル構成とパスを確認するコマンドを実行
  • usesを使ってactions/checkout@v4を実行
  • (チェックアウト後の)ファイル構成とパスを確認するコマンドを実行

するという流れになっています

.github/workflows/linux-command.yml
name: command
on: [push]
jobs:
  command:
    name: Use Linux commands
    runs-on: ubuntu-20.04
    steps:
      - name: Show ubuntu details
        run: lsb_release -a
      - name: Inspect files before checkout
        run: ls -la
      - name: show current directory before checkout
        run: pwd
      - name: Checkout
        uses: actions/checkout@v4
      - name: Inspect files after checkout
        run: ls -la
      - name: show current directory after checkout
        run: pwd
      - name: show all branches after checkout
        run: git branch -a

まずはUbuntuのバージョンやコードネームを確認します
runs-onで指定したUbuntuが選択されていることが確認できます

.github/workflows/linux-command.yml
  - name: Show ubuntu details
    run: lsb_release -a
logs
Run lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.5 LTS
Release:	20.04
Codename:	focal

次にactions/checkout@v4を実行する前のファイル構成とパスを確認します

.github/workflows/linux-command.yml
  - name: Inspect files before checkout
    run: ls -la
  - name: show current directory before checkout
    run: pwd

/home/runner/work/<リポジトリ名>/<リポジトリ名>のパス内に何も入っていないことが確認できます

logs
Run ls -la
total 8
drwxr-xr-x 2 runner docker 4096 Oct  9 22:02 .
drwxr-xr-x 3 runner docker 4096 Oct  9 22:02 ..
Run pwd
/home/runner/work/<リポジトリ名>/<リポジトリ名>

/home/runner/work/<リポジトリ名>/<リポジトリ名>ってどこから来ているのか解説すると、自身で作成されたワークフローを実行するパスのことで$GITHUB_WORKSPACEという環境変数を読み込んで実行しています
環境変数の中身を確認すると以下のようになっているかと思います

GITHUB_WORKSPACE=/home/runner/work/<リポジトリ名>/<リポジトリ名>

/home/runner/work/までは一緒ですがその後はWorkflowを実行するリポジトリ名がディレクトリ名として指定されます

actions/checkout@v4を実行します

.github/workflows/linux-command.yml
  - name: Checkout
    uses: actions/checkout@v4
logs
Run actions/checkout@v4
Syncing repository: shun198/***-<リポジトリ名>
Getting Git version info
Temporarily overriding HOME='/home/runner/work/_temp/da727d01-5e2c-459c-b8db-380fb0265762' before making global git config changes
Adding repository directory to the temporary git global config as a safe directory
/usr/bin/git config --global --add safe.directory /home/runner/work/<リポジトリ>/<リポジトリ>
Deleting the contents of '/home/runner/work/*/<リポジトリ名>/<リポジトリ名>'
Initializing the repository
Disabling automatic garbage collection
Setting up auth
Fetching the repository
Determining the checkout info
Checking out the ref
/usr/bin/git log -1 --format='%H'

ログがかなり多いので手順を簡単に説明すると

  1. ランナー内のリポジトリのGitの処理設定
  2. Gitの認証設定
  3. リモートリポジトリから処理を実行するブランチのリポジトリのソースコードをfetch
  4. fetchしたソースコードと同じブランチをチェックアウト

しています。要するにランナー内にリモートリポジトリにあるソースコードをクローンに限りなく近い形(厳密には違う)で複製していることになります。
クローンだとデフォルトのブランチ(main、develop)のソースコードしか抽出できず、作業する際に使うfeatureブランチのソースコードだけテストできないからfetchとcheckoutをしているのだと筆者は考えています
これについて詳しい方がいましたらぜひご教授いただけると幸いです
actions/checkout@v4の詳細を知りたい方は実際にログを確認してみてください

実行した後のファイル構成、パス、ブランチ一覧を確認します

.github/workflows/linux-command.yml
  - name: Inspect files after checkout
    run: ls -la
  - name: show current directory after checkout
    run: pwd
  - name: show all branches after checkout
    run: git branch -a

/home/runner/work/<リポジトリ名>/<リポジトリ名>のパス内に自身が作業したブランチのファイル構成が確認できました
また、git branch -aを実行してもmainやdevelopブランチはなく、作業していたfeatureブランチのみ表示されたことが確認できました(git cloneだとデフォルトで設定したmainブランチのソースコードがクローンされるはずです)

logs
Run ls -la
  ls -la
  shell: /usr/bin/bash -e {0}
total 88
drwxr-xr-x 11 runner docker 4096 Oct  9 22:02 .
drwxr-xr-x  3 runner docker 4096 Oct  9 22:02 ..
drwxr-xr-x  2 runner docker 4096 Oct  9 22:02 .devcontainer
drwxr-xr-x  8 runner docker 4096 Oct  9 22:02 .git
drwxr-xr-x  3 runner docker 4096 Oct  9 22:02 .github
-rw-r--r--  1 runner docker 3088 Oct  9 22:02 .gitignore
drwxr-xr-x  2 runner docker 4096 Oct  9 22:02 .vscode
-rw-r--r--  1 runner docker 4664 Oct  9 22:02 README.md
drwxr-xr-x  5 runner docker 4096 Oct  9 22:02 containers
-rw-r--r--  1 runner docker 1836 Oct  9 22:02 docker-compose.yml
-rwxr-xr-x  1 runner docker  126 Oct  9 22:02 entrypoint.sh
-rwxr-xr-x  1 runner docker  661 Oct  9 22:02 manage.py
drwxr-xr-x  3 runner docker 4096 Oct  9 22:02 application
-rw-r--r--  1 runner docker  207 Oct  9 22:02 requirements.txt
drwxr-xr-x  5 runner docker 4096 Oct  9 22:02 static
Run pwd
  pwd
  shell: /usr/bin/bash -e {0}
/home/runner/work/<ディレクトリ名>/<ディレクトリ名>
Run git branch -a
  git branch -a
  shell: /usr/bin/bash -e {0}
* feature/01

actions/checkout@v4の説明は以上です

steps

図でも説明した通り一つのjobsは1つ以上のstepsで構成されており、stepsの中にrunコマンドが1つ以上構成されています

run

runに実行するコマンドを以下のように記載していきます
nameにrunの処理について書くことができ、GitHub上で確認できます

.github/workflows/linux-command.yml
  - name: Inspect files before checkout
    run: ls -la
  - name: show current directory before checkout
    run: pwd

スクリーンショット 2022-10-10 12.07.54.png

また、複数以上のコマンドを実行したい時は run | と記載します

.github/workflows/linux-command.yml
  - name: Inspect and show current directory files before checkout
    run: |
        ls -la
        pwd

env

ワークフロー内に環境変数を設定できます
環境変数を使用する際はenvの下に以下のように

SECRET_KEY: test

という風に環境変数の名前と対応する値を記載します

.github/workflows/env.yml
env:
  SECRET_KEY: test
  DJANGO_SETTINGS_MODULE: project.settings.local
  ALLOWED_HOSTS: 127.0.0.1
  MYSQL_ROOT_PASSWORD: root
  MYSQL_DATABASE: test-db
  MYSQL_HOST: 127.0.0.1
  MYSQL_PORT: 3306
  MYSQL_USER: test
  MYSQL_PASSWORD: test

secrets

こちらも環境変数を格納することができます
envと違って

  • AWSのシークレットキー
  • AWSのアクセスキー

など見られたくない情報を格納するときに使うのが一般的です
secretsを使うことで秘匿情報を暗号化した状態で使用できます

リポジトリのSettingsを開きます
スクリーンショット 2022-09-30 21.18.05.png

Security>Secrets>Actionsを開きます
スクリーンショット 2022-09-30 21.18.32.png

New repository secretを押します
スクリーンショット 2022-09-30 21.20.19.png

以下にsecret名と値を入れます
一度Add secretを押すと二度と中身が見れないので注意してください
スクリーンショット 2023-07-14 21.39.32.png

secretを作成していくと以下のようになります
スクリーンショット 2023-07-14 21.40.46.png

secretsの使用方法

secretsを使用するときは

${{ secrets.AWS_ACCESS_KEY }}

という風に記載することで暗号化した状態の環境変数を使用できます
以下が公式のAWSの認証用のActionを使った例です

.github/workflows/secrets.yml
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
        aws-region: ap-northeast-1

デバッグの設定

Settingsタブのsecretsに

  • ACTIONS_RUNNER_DEBUG
  • ACTIONS_STEP_DEBUG

をTrueで保存すると

  • Runnerの実行ログ
  • Step毎の実行ログ

を確認することができ、デバッグ効率がよくなリます

スクリーンショット 2023-06-15 10.27.41.png

スクリーンショット 2023-06-15 10.27.57.png

  • 設定前
    スクリーンショット 2023-06-15 10.28.15.png

  • 設定後
    スクリーンショット 2023-06-15 10.28.34.png

サービスコンテナ

ワークフローを実行する際に必要になるサービスを使用するためのDockerコンテナです
バックエンドの単体テストを自動実行する際にDBのサービスコンテナを使うのが一般的です
サービスコンテナを使うことでGitHub内のランナー上でDBなどのサービスを利用する必要がないのでワークフローを単純化できる上にランナー内の限られたリソースを無駄に使わなくて済むので実行速度も短縮できます

サービスコンテナの設定方法

.github/workflows/service-container.yml
    services:
      db:
        image: mysql:8.0
        ports:
          - 3306:3306
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: test-db
          MYSQL_USER: test
          MYSQL_PASSWORD: test
        options: >-
          --health-cmd "mysqladmin ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

サービスコンテナを作成するときはservicesを定義し、
imageはDocker hubにある各サービスの公式のDocker imageのバージョンを指定します
今回はMySQLのコンテナを作成します
DBをフレームワークと接続する際は環境変数も設定するのが一般的なので先ほど紹介したenvを使用します
今回の例ではテストを実行するだけなのでsecrets内に環境変数を定義せずにテスト用の環境変数を使用しています

options

options内に実行したい任意のコマンドを記載します
DBやRedisなどのインメモリキャッシュとの接続の際はヘルスチェックコマンドを記載するのが一般的です
ヘルスチェックって何?コマンドの意味がわからないという方は以下の記事を参考にしてください

サービスコンテナの詳細は以下のとおりです

環境のsetup

GitHub Actionsの公式もしくは各言語の公式が出しているactionを使うとワークフロー内でパッケージのインストールコマンドを書かずに設定できます
例えばGitHub Actionsが出しているsetup-pythonというactionを使うだけでランナー内にpipを入れたり、Pythonを入れるコマンドを書かずにPythonを実行できる環境を用意できます

今回は

  • Python
  • Node.js

を例にsetup系のactionの使い方を記載します

Python

公式が出しているPythonのsetup用のactionです

.github/workflows/setup-python.yml
steps:
    - uses: actions/checkout@v4

    - uses: actions/setup-python@v5
      with:
        python-version: '3.11' 
    - run: python my_script.py

オプションとしてPoetryを使ってインストールしたパッケージをCacheできます
Cacheを使うことで2回目以降ワークフローを実行する際にpoetry installを実行するとインストールしたパッケージをCacheを参照して使うのでインストール時間が短縮されます

.github/workflows/setup-python.yml
steps:
    - uses: actions/checkout@v4
    - name: Install poetry
      run: pipx install poetry
    - uses: actions/setup-python@v5
      with:
        python-version: '3.11'
        cache: 'poetry'
    - run: poetry install

また、python-version-fileのオプションを使うことでpyproject.toml内に記載されたPythonのversionを自動的に適用させることもできます

    - uses: actions/setup-python@v5
      with:
        python-version-file: "pyproject.toml"
        cache: 'poetry'
    - run: poetry install

以下がsetup-pythonの詳細です

Node.js

公式が出しているNode.jsのsetup用のactionです
Nodeのversionについては16,18,20をサポートしています
以下がnpmを使ってCacheを使うときのワークフロー例です

.github/workflows/setup-node.yml
steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 16
        cache: 'npm'
        cache-dependency-path: '**/package-lock.json'
    - run: npm ci

npm以外にyarnを使ったCacheのワークフローも実装できます

.github/workflows/setup-node.yml
steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 16
        cache: 'yarn'
        cache-dependency-path: '**/package-lock.json'
    - run: npm ci

また、node-version-fileのオプションを使うことでpackage.json内に記載されたNodeのversionを自動的に適用させることもできます

The node-version-file input accepts a path to a file containing the version of Node.js to be used by a project, for example .nvmrc, .node-version, .tool-versions, or package.json. If both the node-version and the node-version-file inputs are provided then the node-version input is used. See supported version syntax.

.github/workflows/setup-node.yml
steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version-file: 'package.json'
    - run: npm ci
    - run: npm test

Voltaを使ってNodeのバージョンを指定した際はVoltaに記載したNodeのバージョンを適用します
もし、Voltaの記述がない場合はenginesがあればengines内のNodeのバージョンを適用します

When using the package.json input, the action will look for volta.node first. If volta.node isn't defined, then it will look for engines.node.

package.json
{
  "engines": {
    "node": ">=16.0.0"
  },
  "volta": {
    "node": "16.0.0"
  }
}

権限

GitHub Actionsではデフォルトのバージョンをワークフロー内で自身で決めることもできます
各権限のことをスコープといい、デフォルトは全てread権限です
スコープには

  • read
  • write
  • none

の3つの権限を付与できます
ワークフロー内でスコープとその権限を一つ以上定義した場合、定義していない他のスコープの権限は全てnoneになります
各スコープの詳細は以下の通りです

permissions:
  actions: read|write|none
  checks: read|write|none
  contents: read|write|none
  deployments: read|write|none
  id-token: read|write|none
  issues: read|write|none
  discussions: read|write|none
  packages: read|write|none
  # GitHub Pages
  pages: read|write|none
  pull-requests: read|write|none
  repository-projects: read|write|none
  security-events: read|write|none
  statuses: read|write|none

permissionを自身で定義するワークフロー例

GitHubが公式に出しているconfigure-aws-credentialsを例に説明します
本ワークフローではAWSと認証するためにトークンが必要で、そのトークンを使うためにpermissionを変更しているんだ、くらいの理解で大丈夫です

jobs:
  deploy:
    name: Upload to Amazon S3
    runs-on: ubuntu-latest
    # These permissions are needed to interact with GitHub's OIDC Token endpoint.
    permissions:
      id-token: write
      contents: read
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - name: Configure AWS credentials from Test account
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::111111111111:role/my-github-actions-role-test
        aws-region: us-east-1
    - name: Copy files to the test website with the AWS CLI
      run: |
        aws s3 sync . s3://my-s3-test-website-bucket
    - name: Configure AWS credentials from Production account
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::222222222222:role/my-github-actions-role-prod
        aws-region: us-west-2
    - name: Copy files to the production website with the AWS CLI
      run: |
        aws s3 sync . s3://my-s3-prod-website-bucket

yml内で以下のようにpermissionを使っています

    permissions:
      id-token: write
      contents: read

id-tokenはGitHub Actions内でOIDCを使う際に使用します

Fetch an OpenID Connect (OIDC) token. This requires id-token: write. For more information, see "About security hardening with OpenID Connect"

先ほど説明した通り全てのスコープのデフォルトの権限はreadです
OIDCを取得するにはwrite権限を付与する必要があるので明記します
ここで一つ注意してほしいのが、先ほど

ワークフロー内でスコープとその権限を一つ以上定義した場合、定義していない他のスコープの権限は全てnoneになります

と記載しました
ワークフロー内でcheckoutを使ってリポジトリ内のコードをfetchしています
id-tokenのpermissionをwriteにしてしまうとcheckoutを実行するのに必要なcontentsスコープがnoneになってしまい、fetchできなくなってしまうのでcontentsのpermissionをreadと明記する必要があります
permissionを書き換えるときは注意しましょう

まとめ

初めてGitHub Actionsを触った時はどれが何をしているかさっぱりわからなかったのですが仕組みや書き方をある程度理解していればそこまで難しくなく、むしろやっていて楽しいなと個人的に思いました

記事の紹介

本記事は基礎編なのでより本格的なGitHub Actionsの使い方について詳しく記載しきれませんでしたが、

  • Cache
  • メタデータ構文
  • GitHub Pages
  • OpenID Connect

など様々な記事を執筆したので興味ある方はよかったら見ていただけると幸いです

参考

106
75
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
106
75