GitHub Actions ワークフローで複数のジョブ実行を制御する

GitHub Actions ワークフローでは、複数のジョブを順次実行・並列実行・条件実行することができます。各ジョブは異なるマシン(Runner) もしくは コンテナイメージで実行されます。

順次実行

何も指定しなければ、ジョブは並列に実行されます。順次実行するには、needs キーワードで、先行のジョブを指定します。

name: Sequential Jobs
on:
  push:

jobs:
  Build1:
    runs-on: ubuntu-latest
    steps:
    - run: echo Build1

  Build2:
    runs-on: ubuntu-latest
    needs: Build1
    steps:
    - run: echo Build2

実行結果

f:id:kondoumh:20210122075032p:plain

並列実行 (フォーク)

ジョブを実行後に複数のジョブを並列実行するには、各ジョブの needs に分岐元のジョブを指定します。

name: Fork Jobs
on:
  push:

jobs:
  Setup:
    runs-on: ubuntu-latest
    steps:
    - run: echo Setup

  Build1:
    runs-on: ubuntu-latest
    needs: Setup
    steps:
    - run: echo Build1

  Build2:
    runs-on: ubuntu-latest
    needs: Setup
    steps:
    - run: echo Build2

実行結果

f:id:kondoumh:20210122075441p:plain

並列実行 (ジョイン)

並列ジョブをジョインして最終の処理を行うには needs にジョインしたいジョブを列挙します。

name: Join Jobs
on:
  push:

jobs:
  Build1:
    runs-on: ubuntu-latest
    steps:
    - run: echo Build1

  Build2:
    runs-on: ubuntu-latest
    steps:
    - run: echo Build2

  Teardown:
    runs-on: ubuntu-latest
    needs: [Build1, Build2]
    steps:
    - run: echo Teardown

実行結果

f:id:kondoumh:20210122075806p:plain

フォークとジョインの組合せ

CI でビルド後に複数のテストを並列実行して成功したらデプロイするような例です。

name: Deploy
on:
  push:
    paths:
    - .github/workflows/deploy.yml

jobs:
  Build:
    runs-on: ubuntu-latest
    steps:
    - run: echo Build

  TestA:
    runs-on: ubuntu-latest
    needs: Build
    steps:
    - run: echo Test A

  TestB:
    runs-on: ubuntu-latest
    needs: Build
    name: Run Test B
    steps:
    - run: echo Test B

  Deploy:
    runs-on: ubuntu-latest
    needs: [TestA, TestB]
    steps:
    - run: echo Deploy

実行結果

f:id:kondoumh:20210122085107p:plain

条件実行 (ワークフローの最後に結果を通知)

GitHub Actions ではワークフローの状態は内包するジョブの失敗・成功に依存します。1つでもジョブが失敗していれば、ワークフローの状態は失敗です。ワークフローの状態は success / failure などの関数で取得できるため、ジョブに if 条件文で実行条件を指定します。

  Deploy:
    runs-on: ubuntu-latest
    needs: [TestA, TestB]
    steps:
    - name: Deploy
      run: echo Deploy

  Notify_succeed:
    if: ${{ success() }}
    runs-on: ubuntu-latest
    needs: Deploy
    steps:
    - name: Notify to Slack channel
      uses: rtCamp/action-slack-notify@v2
      env:
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        SLACK_USERNAME: GitHUb Actions
        SLACK_TITLE: Workflow Succeeded
        SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
        SLACK_MESSAGE: 'Run number : #${{ github.run_number }}'

  Notify_failure:
    if: ${{ failure() }}
    runs-on: ubuntu-latest
    needs: Deploy
    steps:
    - name: Notify to Slack channel
      uses: rtCamp/action-slack-notify@v2
      env:
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        SLACK_USERNAME: GitHUb Actions
        SLACK_TITLE: Workflow failed
        SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
        SLACK_COLOR: danger
        SLACK_MESSAGE: 'Run number : #${{ github.run_number }}'

Slack への通知に、以下の Action を利用しました。

github.com

失敗時の実行結果

f:id:kondoumh:20210121235049p:plain

通知の例

f:id:kondoumh:20210122001019p:plain

成功時の実行結果

f:id:kondoumh:20210122000707p:plain

通知の例

f:id:kondoumh:20210122000916p:plain

野良 Scrapbox アプリ - Linux 用バイナリも Release に含めました。

これまで Windows と macOS のビルドを Release からダウンロードできるようにしていましたが、最近 Linux デスクトップも使うようになってきたので、Linux のバイナリを配布しようと思いました。

ひとまず起動確認。

f:id:kondoumh:20210119211652p:plain

ビルドして実行したところ GNOME のドック? にアイコンが出てません。

f:id:kondoumh:20210119211722p:plain

electron-builder を使ってるんですが、issue が立ってました。

github.com

この issue のコメントにあるコード書いたら一応アイコンが出ました。

f:id:kondoumh:20210119211741p:plain

配布形式としては、deb や rpm など特定のディストリビューションのパッケージではなく AppImage 形式のバイナリを配布することにしました。Ubuntu 20.0.4.1 と CentOS 8 では動作しました。

ダウンロードして利用するときは、実行用のパーミッションを付けます。

f:id:kondoumh:20210120001856p:plain

f:id:kondoumh:20210120001913p:plain

というわけでリリース。

github.com

Electron アプリもちゃんと動くので作業環境としては Linux デスクトップでも普段は生活していけそうです。

Apple Silicon のバイナリも作りたいですが、手元に M1 Mac ありません。GitHub Actions の Runner も今のところ Intel Mac しかないようです。AWS の EC2 インスタンスに Apple Silicon の Mac が来るのももう少し先なのでもうしばらく待ちですね。electron-builder も Pre-release では対応してます。

ワークアウトしたら Pixela に草を生やす PWA

テレワークで外出が減って、運動不足を自覚するようになりました。人間ドックでも数値がちょっと悪くなってました。そこで YouTube の Fit boxing チャンネルなどで室内運動するようになりました。外出した日は意識して歩数を伸ばすようにしたりしてます。

やはりモチベーション維持には、GitHub の Contribution graph のようなのあるといいなと思って Pixela にグラフを作りました。

pixe.la

数日は cURL コマンド叩いてましたが、スマホから更新できるように PWA にしてみました。

f:id:kondoumh:20210111180537g:plain

Boxing でも Walking でもやったら commit。1回のワークアウトで 20% 進捗するようにして、5回 commit したら輪が閉じます。commit と revert はそれぞれ Pixel の increment / decrement API を叩いているだけ。

まだ10日目。 f:id:kondoumh:20210111174305p:plain

2020 ふりかえり

今年は4月から完全テレワークになって外出が減り、外での飲食もなくなり、生活が大きく変わりました。

Job

クラウドネイティブなプロダクト開発に参加して丸2年が過ぎました。SRE チームとして活動しています。環境構築を自動化したり、可用性やセキュリティを高めるための設定を適用したりして安定運用を目指しています。Kubernetes 関連の技術を色々試せるのでいい経験です。

もう1つ少しだけ入ってたプロジェクトは離任して、その稼働を会社のマーケティング活動に使いました。

Mamezou-tech

会社の GitHub Organization で同僚の人とささやかな OSS 活動を始めました(業務外)。

github.com

僕は GitHub Actions をよく使うので Kubernetes のパッケージ管理やコンテナビルドの Action を公開してます。issue やプルリクもたまに来るので週末に対応したりしてました。

github.com

github.com

同僚の人は Concourse CI の Kubernetes resource を公開しています。

github.com

CI 関連の OSS は仕事でも使えるし、意外と使ってもらえたりするので題材としてはよかったです。

あと Scrapbox のグラフ構造を抽出する CLI ツールも公開してます。これは個人リポジトリでもよかったのですが、最初は OSS の数が少なかったので。

github.com

Personal Development

自分のリポジトリでは、野良 Scrapbox アプリもちょいちょいリリースしてました。Electron のリリースに追従するのが主でした。使っている NPM パッケージにプルリクを送ったりもしました。

github.com

追加した機能では、Markdown 変換が便利でけっこう使ってました。

blog.kondoumh.com

Scrapbox の更新情報をスマホで見たくて、Vue.js と Netlify Functions で PWA を作ってました。

github.com

グラフ構造可視化の画面も同じ PWA に組み込んでます。

blog.kondoumh.com

会社用の private プロジェクトを見るための PWA も同じ構造で作ってて便利に使ってます。

個人的な開発は Scrapbox を題材にしたものがほとんどでした。

Gadgets

テレワークになったので、リモートマシンに繋ぐためのシンクライアント端末と自分の MacBook を切り替えて使うようになりました。超久々にキーボード・マウス切り替え器を導入。

scrapbox.io

自宅の作業環境を最適化するため、客先にずっと置いてた REALFORCE と Microsoft Ergonomic Mouse 持って帰って使ってます。

scrapbox.io

scrapbox.io

ディスプレイも長年使ってる ASUS の WQHD 27inch。ベゼル太いです。

scrapbox.io

コロナ禍初期の頃はディスプレイも品切れが続いてました。

今年も 2015年の MacBook Pro リニューアルしてません。ずっとクラムシェルで使ってたせいかバッテリーが膨張してしまいました。仕事ではかなりハイスペックなマシンを使ってますが、自分の MacBook ではちょっとした Web アプリ作ったり Go で CLI を書く程度だったので結局買わずに過ごしてしまいました。仕事マシンで作業してる時間が圧倒的に長いのもあります。M1 Mac が出るまでは時折 Ryzen PC を物色してましたが Apple Silicon 凄いらしいので当面 Mac から離れられないのではと思ってます。

iPad Pro 11inch 2018 奥さんのを譲ってもらって使ってます。画面綺麗でヌルヌル動くし、Magic Keyboard / Trackpad とペアリングするとサブマシンとしてもかなり使えます。YouTube に可処分時間をかなり取られてますが、視聴は iPad です。MacBook だと CPU が高騰してファンが回るし、画面も占有されるのでマシンを分けてます。

blog.kondoumh.com

ThinkPad TrackPoint Keyboard 2 はなかなか良いですが、毎日長時間使ってると左小指がつりそうになるので、たまに自社のオフィスで作業する時に使うことにしました。

blog.kondoumh.com

Zoom や Teams 会議用にヘッドセットを追加。支給された iPhone で使ってます。

scrapbox.io

今年は「三体」をはじめ SF を読む時間が増え、Kindle の稼働が上がりました。

scrapbox.io

Software and Services

今年はやはり Zoom ですね。有償プラン契約して使ってます。1日何時間も会話しながら画面共有して作業してます。

zoom.us

Teams は Outlook と連動して会議の設定や参加が楽なところがよいです。チャットは高機能ですが動きがちょっともっさり、画面共有は Zoom の方が使いやすいです。

www.microsoft.com

Zenn 個人で開発されたサービスと聞いてサインアップだけしました。けっこう流行ってますね。本を書いて売ったりできるのもユニークです。

zenn.dev

Netlify は個人プロジェクト用によく使ってます。

www.netlify.com

GitHub の Arctic Code Vault プロジェクトも話題になりました。自分のしょぼいコードも北極に埋められるのか〜とちょっと面白かったです。

archiveprogram.github.com

GitHub は仕事でも個人でも365日使ってますが、GitHub Actions も随分使いやすくなりましたし、Bot で作業を自動化できたり、ナイトモードに対応したりと進化を続けてます。そんなに落ちなかったし。Microsoft による買収はいい方向に作用してると言えるのではないでしょうか。CodeSpaces のローンチも楽しみです。

Ingress は8周年。今年は外出が減ったので新機能の Dronenet であちこちにドローン飛ばしてました。Intel map も活用してました。

medium.com

YouTube Premium に入りました。広告ないのはとても快適ですね。登録しているチャンネルもかなり増えてしまいました。

Scrapbox は個人メモにも活用してます。

blog.kondoumh.com

Mos は macOS で Windows 用マウスでもスムーズスクロールを実現できるユーティリティ。これで、Windows でも macOS でも同じマウスを切り替えて使えるようになりました。

mos.caldis.me

最後に

来年は徐々に日常が回復していくことを祈ってます。

Scrapbox プロジェクトのグラフ構造可視化 - その後

Scrapbox のページ間リンクを可視化するやつです。

Graphviz バージョン blog.kondoumh.com

D3.js バージョン blog.kondoumh.com

D3.js バージョンを半年ぶりにちょっと触りました。と言っても Visualization の方式を変えたとかではなく、ノードをフィルタリングする UI を追加してみたっていう内容です。

Scrapbox API でページ毎の views と linked のカウントが取れます。これをフィルタリングの指標とします。スライダーの UI コンポーネントで2つの数値の Range を調整するようにしました。

vuetifyjs.com

views と linked を独立で調整できるようにしてます。

f:id:kondoumh:20201220220645p:plain

自分の Scrapbox プロジェクトを可視化してみたところです。

scrapbox.io


Scrapbox graph visualization

ハッシュタグのように使うページはやたらと 1-hop リンクが増えて行きます。文章内で言及されることによって自然とハブになるページとは違って、可視化した時はノイズに近いものになります。ハッシュタグかどうかの判定はデータからはできないので、リンク数で定量的に削る作戦です。Graph データを作るときにメタデータを出力するようにすれば UI でフィルターできそうですね。

個人 Scrapbox プロジェクトなので高々数100件しかありませんが、会社の Scrapbox は6000ページを超えており*1、全てのノードを描画するのは重すぎなので views で10件以上とかで絞り込めば閲覧に耐える速度になりました。

と言うことで、ノードの数を絞るのに views の Min を、ハッシュタグ的なノイズ的ページを隠すのに links の Max をうまく設定することでグラフ構造が浮き彫りになる感じです。

もっとピュンピュン動いて欲しいところですが、レンダリングアルゴリズムの見直しはまた今度。

*1:元データを作成するのに5分ぐらいかかります。(データ取得が大部分を占めていますが)。

GitHub Actions の Composite run steps action を使った Action を作る

この夏に登場してたのを見逃してました。

github.blog

以前は GitHub Actions のワークフローで再利用できる Action は Docker Container Action と JavaScript Action でした。

blog.kondoumh.com

Docker Container Action は手軽に作れますが、コンテナで実行するため揮発性で step 毎に docker build が実行されるとか、コンテナイメージをビルドする Action を作るにはベースイメージを docker にする必要があるなどやや不便なところもあります。JavaScript Action は JavaScript のスキルとGitHub 提供ライブラリの習得が必要でやや敷居が高いです。

GitHub Actions のワークフローで使われるシンタックスで Action が記述できればいいのにと思った人は多いのではないでしょうか。それが、Composite run steps action です。

これは、ワークフローで使う run step を Action 定義に埋め込むもので、Dockerfile や JavaScript の記述なしに action.yaml だけで Action が作れてしまうというものです。

docs.github.com

公式ドキュメントのサンプルはこんな感じです。

name: 'Hello World'
description: 'Greet someone'
inputs:
  who-to-greet:  # id of input
    description: 'Who to greet'
    required: true
    default: 'World'
outputs:
  random-number: 
    description: "Random number"
    value: ${{ steps.random-number-generator.outputs.random-id }}
runs:
  using: "composite"
  steps: 
    - run: echo Hello ${{ inputs.who-to-greet }}.
      shell: bash
    - id: random-number-generator
      run: echo "::set-output name=random-id::$(echo $RANDOM)"
      shell: bash
    - run: ${{ github.action_path }}/goodbye.sh
      shell: bash

runs: セクションに using: "composite" を書いて steps セクション配下に、run step を書き連ねて行けば実行してくれます。まさに欲しかったものです。このサンプルでは、別のシェルを作って起動していますが、複数コマンドを直接 yaml に書いても OK。ソフトウェアをダウンロードしてインストールするような処理も簡単に書けます。

    - run: |
        curl -LO https://github.com/roboll/helmfile/releases/download/v0.135.0/helmfile_linux_amd64
        mv helmfile_linux_amd64 helmfile
        chmod +x helmfile
        mkdir -p $HOME/bin
        mv helmfile $HOME/bin
        echo "$HOME/bin" >> $GITHUB_PATH
      shell: bash

shell 属性は必須のようです。

Composite run steps action は GitHub Actions でワークフローを書いた経験があれば作成できるため、Action を作る障壁はかなり下がったと言えると思います。

利用できるのは run のみで、uses で他の Action を呼び出したりすることはできません。複雑なワークフローをまるっと Action にして再利用することはできませんがシェルスクリプトと併用すれば相当複雑なこともできそうです。ただし Action 自体はシンプルな機能にとどめた方が開発も利用も楽ですので、高機能すぎる Action を作るのはやめた方がよいです。

ただ、ワークフロー自体を organization などの単位で共有して色々なリポジトリから利用したいという要求はあって、そのために Organization and enterprise workflows というフィーチャーが予定されています。

github.com

残念ながら現時点では提供時期未定ですが。

Netlify Functions を PWA のバックエンドで使う

Netlify は静的サイトをホスティングするのに便利です。

blog.kondoumh.com

JSON データを置いてちょっとしたデータソース的にも使えます。

blog.kondoumh.com

しかし、JSON を静的に配置できるだけだと上の記事のように更新のためのパイプラインを実装する必要があるし、リアルタイム性も犠牲になります。PWA のバックエンドでちょっと動的な処理をしたい場合に Netlify Functions を利用する選択肢が提供されています。

docs.netlify.com

Functions は AWS Lambda を利用したサービスであり、簡単にバックエンドの API を追加できるようになっています。Node.js が 使えるようになったのが1年ぐらい前で今は Go も使えるようです。

www.netlify.com

JAMstack の A は API の A ですが、その API Stack が強化されたことになります。Functions がなくても外部の API を叩くことはできましたが、サーバー不要で自作の API と一緒にデプロイできるのが進化です。

既存の PWA サイトに Netlify Functions を追加するには、プロジェクトのルートに netlify.toml ファイルを追加します。

[build]
  command = "npm run build"
  functions = "dist/api"

npm -i netlify-lambda で Netlify Functions を使うためのライブラリを追加します。その他、API の実装に必要なライブラリも追加しておきます。

  "dependencies": {
    :
    "netlify-lambda": "^2.0.1",
  },

PWA の src ディレクトリとは別の専用のディレクトリを用意して API のソースコードを追加します。

exports.handler = async (e, c) => {

  const data = await hoge();
     :
  return {
    statusCode: 200,
    body: JSON.stringify(data),
  };
};

Functions の API を resources/api/hoge.js に書いたとして Vue.js のプロジェクトへの追加後の構成はこんな感じ。

.
├── resources
│   └── api
│        └── hoge.js     
├── src
│   ├── assets
│   ├── components
│   ├── plugins
│   ├── router
│   └── views
├── netlify.toml
├── package.json
├── vue.config.js
└── test

package.json の build script で PWA のビルドと netlify-lambda の CLI を順次実行するように変更します。下記は Vue CLI と Netlify Functions CLI を実行する例です。

{
  "scripts": {
     :
    "build": "vue-cli-service build && netlify-lambda build resources/api"
  }
}

これで PWA と Functions のエンドポイントが一気にデプロイできます。

Functions の利用側では同一サイトの .netlify/functions 配下のパスを指定して API を呼び出します。

  const res = await fetch(".netlify/functions/hoge", {
    headers: {
      "foo": bar
    }
  })
  const json = await res.json()

Functions がデプロイできてしまえば、ローカルの開発時もデプロイ済みの Functions を呼び出せるように vue.config.js で devServer の proxy を設定しておけば楽です。

module.exports = {
  lintOnSave: false,
  devServer: {
    proxy: "https://hogehoge.netlify.app"
  }
}

Netlify のコンソール画面で呼び出しログも確認できます。もちろん、npm run dev でローカルに Functions を起動して、そのポートに proxy することも可能です。

以上のように AWS Lambda の機能をアドオンしたサイトがサクッと構築できるので、応用の幅が広がりました。

Functions の機能強化として、現在はベータ版ですが、時間のかかる処理(最大15分)をバックグラウンドで行わせることができる Background Functions も使えるようになるみたいです。

docs.netlify.com