なうびるどいんぐ

脳みそ常時-3dB

GitHub Actionsの使い方

      2019/08/28    HimaJyun

GitHub Actions、ベータ申し込んでたら使えるようになったので使ってみました。

それと、設定ファイルの構文がHCLからYAMLに変わったらしく巷にある記事が軒並み腐ったので、YAMLでの使い方。

スポンサーリンク

ちなみにこの記事は2019/08/24、ベータ中の情報なので、未来の読者の環境では大幅に変わっている可能性が猛烈に高い。

最新の情報に関しては公式ドキュメントを読みましょう。

できること

割といろいろできる。

CI/CDはもちろんできるし、cronのような使い方もできる、古くなったissueやPRの自動closeとかも可能。

以下は実際の例。

CI

GitHubではCI含め各アクションをworkflowと呼び、これらは.github/workflows/(任意のファイル名).ymlにファイルを作成すると可能。

たとえば、Java(Maven)のCIを実行したいならこんな感じ。

name: Java CI

on: [push]

jobs:
  build:
    name: maven package
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Build with Maven
      run: mvn package --file pom.xml

各言語の標準的なCI設定はactions/starter-workflowsを参考にすると良いと思う。

各ワークフロー内に個別にジョブを設定可能。更にワークフローそのものを複数定義できる(最大20個)。

1つのプロジェクト内でいくつかの言語を使用しているような場合でも個別にCIを仕掛けることが可能。

通常のpush時とプルリクエストで別のCIを実行したり、issueやPRの管理を同時に行うことも可能。

定期実行

GitHub Actionsではcron形式の定期実行が可能。

例えばaction/staleを使うと古いissueやPRの自動closeが可能。神経質な人向け。

name: "Close stale issues"
on:
  schedule:
  - cron: "0 * * * *"

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/stale@v1
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        stale-issue-message: '開けっ放しで古なってるから閉じるで?'
        days-before-stale: 30
        days-before-close: 5

この例では30日放置後に古いラベルが追加される。

その後、古いラベルが削除されないか、新規のコメントがないまま5日経過するとcloseされる。

そのほかいくつか設定が可能、issue開けっぱで放置する奴とかにムカついてるなら役に立つかも。

もちろんそれ以外にも、workflowで実行可能なものならなんでも定期実行できる。

たとえば、草が生えてる事に価値観を見出す異常者勤勉な方々を欺くために毎日自動commitするとか?

cronの時間は恐らくUTCだと思われる。JST(UTC+9)を基準に設定すると思った通りの時間に実行されない可能性がある。

環境変数とシークレット変数

環境変数も当然ながら利用可能。デフォルトの環境変数はドキュメントに記載されている。

steps:
- name: Variables
  run: echo ${GITHUB_SHA} ${RUN_MODE}
  env:
    RUN_MODE: production

ちなみに、envに指定する変数名は小文字で設定しても大文字に変換される。

また、GITHUB_で始まる環境変数名は予約されているため使用できない。

シークレット変数などもサポートされている。これはSettings→Secretsから設定する必要がある。
GitHub Actions secret variables

シークレット変数はYAML内でsecrets.変数名と指定すれば使用できる。デフォルトではコマンドの環境変数としては渡されないため、コマンドで使用したい場合にはenvで渡す必要がる。

steps:
- name: Use secret variable
  env:
    SECRET_VARIABLE: ${{ secrets.SECRET_VARIABLE }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    echo ${SECRET_VARIABLE}
    echo ${GITHUB_TOKEN}
    echo ${GITHUB_SHA}

secrets.GITHUB_TOKENはデフォルトで定義されているシークレット変数。リポジトリへのアクセスに利用できるトークンが設定されている。出来上がった成果物を自動でreleaseする時などに使える。

シークレット変数に指定された値は出力からマスクされる。
GitHub Action secret variables output

Actionsのログは誰からも閲覧可能だが、シークレット変数の中身は誰かに見られることはないので漏らしちゃいけない感じのAPIキーやトークンでも利用できる。

静的サイトジェネレーターでビルドしてS3にpush、みたいな動作もActionsだけで完結可能。

Dockerの利用

Dockerも使用可能なのでその気になれば割となんでも出来る。

- name: docker test
  uses: docker://alpine:latest
  with:
    args: echo test

コンテナイメージの指定はdocker://{ホスト}/{イメージ}:{タグ}、ホストを省略した場合はDockerHubからpullされる。

withでargsやentrypointが指定可能なので、コンテナイメージさえ用意できれば何でもできる。

ちなみにDockerを使用する場合はruns-on(後述)がLinuxでなければならない。(そこはWindowsコンテナとか対応してないのか……)

MySQLなどの利用

MySQLやRedisのようなものが必要な場合はservicesを利用する。

services:
  nginx:
    image: nginx
    ports:
    - 8080:80
  mysql:
    image: mysql
    ports:
    - 3306
steps:
- name: mysql port
  run: echo ${PORT}
  env:
    PORT: ${{ job.services.mysql.ports['3306'] }}
- name: curl
  run: curl http://localhost:8080/

ホスト側のポート番号は指定しても良いし、しなくてもいいっぽい。

指定しなかった場合はランダムなポートが割り当てられる。このポート番号はjob.service.サービス名.ports['ポート番号']で取得できる。

「CIの時のデータベースどうしようか?」問題も綺麗に解決できる。

構文

ここで全ての構文を解説するのは無駄(公式ドキュメントを読むべき)だし、面倒なのでここではよく使われそうなものをいくつか。

特定ブランチだけ

onでどのような時にworkflowを実行するか指定できる。利用可能な値は公式ドキュメントのEvents that trigger workflowsを見るべきである。説明めんどくさいし。

良く使われそうなのはpushpull_request辺りだろうか?

# 単一の値
on: push
# 複数の値の時はarrayになる
on: [push, pull_request]

ブランチの指定も可能。

たとえば、pull_requestはすべて、ブランチはmasterだけでCIを行うなら次のように。

on:
  push:
    branches:
      - master
  pull_request:

masterとdevelopブランチだけでCIを行うなら次のように

on:
  push:
    branches:
      - master
      - develop

他にも細かい指定が可能。ドキュメントを読もう(説明がめんどくさい……)

利用可能なOS

runs-osで使用できる値は公式ドキュメントのVirtual environmentsで、各OSにインストールされているソフトウェアはSoftware in virtual environmentsに説明がある。

現段階で指定可能な値は以下の通り。

  • Ubuntu 18.04: ubuntu-latest, ubuntu-18.04
  • Ubuntu 16.04: ubuntu-16.04
  • Windows Server 2019: windows-latest, windows-2019
  • Windows Server 2016 R2: windows-2016
  • macOS X Mojave 10.14: macOS-latest, macOS-10.14

Dockerコンテナを利用したい場合はOSがLinux=Ubuntuでなければならない……はずなんだが、WindowsでもDockerがインストールされている。

Windowsコンテナ使えるのかと思って色々やってみたが上手くいかなかった。

macOSはiOS用のSDKとかシミュレーターも使える模様。

複数の環境

複数の環境(OS、バージョン)でCIを行いたいなら、個別に設定する事も可能だがビルドマトリックスを使用すると設定の記述が楽。

runs-on: ${{ matrix.os }}
strategy:
  matrix:
    java: ['8','11','12']
    os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: Set up JDK ${{ matrix.java }}
  uses: actions/setup-java@v1
  with:
    java-version: ${{ matrix.java }}

こんな感じ。strategymatrixで使用したい環境を指定した変数を用意し、それをstepsなどで${{ matrix.変数名 }}の形で参照する。

当然ながらにジョブは環境*環境の数で増える。例えば上の例なら3*3で9個のジョブが作成される。プライベートリポジトリでの利用時には注意。

OS固定でもOK。(逆の言語バージョン固定でももちろんOK)

runs-on: ubuntu-latest
strategy:
  matrix:
    java: ['8','11','12']
steps:
- uses: actions/checkout@v1
- name: Set up JDK ${{ matrix.java }}
  uses: actions/setup-java@v1
  with:
    java-version: ${{ matrix.java }}

includeやexcludeを使用して、特定の組み合わせだけを追加/除去することも可能。

matrix:
  java: ['8','11','12']
  os: [ubuntu-latest, windows-latest, macOS-latest]
  exclude:
  - os: windows-latest
    java: '12'

(includeを試してみたが上手く動かせなかった)

式が使える。ifなどで分岐することが可能。

steps:
- name: if
  if: github.event_name == 'push'
  env:
    GITHUB_CONTEXT: ${{ toJson(github) }}
  run: echo "$GITHUB_CONTEXT"

その気になればかなり複雑なことができると思うが、ワークフローそのもののメンテナンス性が悪化する可能性があるので気を付けて使う方が良いだろう。

利用可能な式などは公式ドキュメントのContexts and expression syntaxを参照。

その他

その他、細かい所とか。

キャッシュは不可能

どうやらファイルをキャッシュしたりする機能はないっぽい?

依存関係の解決にクソ時間かかるようなプロジェクトだと都度クソ時間かかる可能性がある。

そのため、docker化可能な処理はdockerイメージにするなどの工夫が必要になるかもしれない。

まだベータだしね、そのうち実装されるかな……?

organizationで使える?

使えるはず。ただしベータでは別途申し込みが必要。

雑にテストしてみたが、organizationではActionsのタブが存在しなかった。

ただ、「organizationでは使えない」というのも考えづらいし、ベータの申し込みページを開くと自分のアカウントとは別にorganizationのアカウントが表示されたので、ベータでは別途申し込みが必要だと思われる。

正式公開の際には全アカウントで使えるはず。

プライベートリポジトリでの利用

パブリックリポジトリは完全無料で使える。各ジョブの実行時間は6時間まで、普通は十分だろう。(逆に、6時間以上掛かるビルドってもうそれCI崩壊してない?)

プライベートリポジトリの場合はプラン別で月あたり何分間ランナーが使えるか決まっている。

Freeプランの場合は月2000分、Proプランの場合は3000分、Teamプランの場合は10000分、Enterpriseなら50000分……という具合。

まだ公開されていないが、ランナーのセルフホストも出来るらしく、その場合は当然ながら自分のマシンリソースなので好きなだけ使える。

セルフホストランナーそのものは無料。GCPの無料プランにセルフホストのランナー乗っけたら完全無料で永久にぶん回せるかもしれないね。

料金設定

「無料分のランナーでは足りない」なんて時は従量課金で追加のランナーを購入可能。

課金は分単位で、Linuxなら$0.008/分、Windowsなら$0.016/分、macOSなら$0.08/分。

どのマシンも2コア、7Gメモリ。

逆に言えばそれ以外の時(パブリックリポジトリでの利用時、無料分のランナーで足りている時)には料金一切不要。

macOSもWindowsも無料。試しにmacOSのCIを動かしてみたが特に金払えと表示されたりはしなかった。

バッジ

CIの結果を画像とかで表示する奴は今のところ実装されてない。

結果自体はコミット履歴に表示されていたりするのでそのうち実装される気がする。

というか要らねーだろあんなもん……(小声

CPUとメモリ

これは恐らく実行されるマシンによっても違うだろうが、/proc/cpuinfoやfreeは以下の通り。

processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 79
model name	: Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz
stepping	: 1
microcode	: 0xffffffff
cpu MHz		: 2294.686
cache size	: 51200 KB
physical id	: 0
siblings	: 2
core id		: 0
cpu cores	: 2
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 20
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs
bogomips	: 4589.37
clflush size	: 64
cache_alignment	: 64
address sizes	: 44 bits physical, 48 bits virtual
power management:

freeは以下の通り。

              total        used        free      shared  buff/cache   available
Mem:           6.8G        621M        5.3G        692K        945M        5.9G
Swap:          8.0G          0B        8.0G

2コア、7Gメモリのマシン。ちなみに追加の有料ランナーもこのスペック。

Microsoft Azureで実行されているらしい。そりゃまぁ今はMicrosoft傘下だからそうなるよね。

雑感

ザっと触ってみた感じ、結構悪くなさそう。かなり色々できるような設計になっている。

設定ファイルには多少の慣れが必要だが、GitHubと統合されており全部GitHubで完結するので簡単に使い始められる。

わざわざサードパーティーのCIサービスを使わなくても、GitHub Actionsで十分だという人は少なくないのでは?(逆にCIサービス各社は色々と苦戦することになるかも?)

macOSやWindowsも無料だし、プライベートリポジトリでも使えるし、大抵のやりたい事は出来るはず。表立って見えなくても、プライベートでCI回す人とかは増えそうだ。

外部のサービスにAPIのアクセス権を与える必要もないのでその辺もちょっと安心。

ビルドもまぁまぁ早い。ただしこれは正式公開されて利用者増えてくるとどうなるか分からないが。

Package Registryも開発中だし、GitHubで開発、GitHubでCI、GitHubでパッケージ公開、ついでに公式サイトはPages……という全GitHub構成なプロジェクトも増えるかもしれない。

(ちなみに、この記事を書くためにテストした残骸はHimaJyun/actions-testにある)

 - プログラミング