猫でもわかるWebプログラミング

試行錯誤しながらエンジニア(プログラマー)として働く猫のブログ。技術的な話や、働き方の話、読書録とか、試行錯誤している日常の話。

GitHub Actions から安価なVPSのサーバーにデプロイするための Self-hosted Runner

f:id:yoshiki_utakata:20200613140728p:plain

GitHub Actions で VPS にデプロイする

アプリケーションのデプロイするとき

  1. パッケージをビルド
  2. ビルド結果をデプロイ
  3. アプリケーションを再起動

といったことをよくやります。

GitHub公式のCIツールGitHub Actionsを使ってデプロイしたい時、

AWS の ElasticBeanstalk や ECS といった、フルマネージドなシステムを使っていると、イイカンジデプロイシステムが存在するので、GitHub Actionsからデプロイジョブを実行するだけで良かったりします。

しかし、個人開発等でAWSは高いので、VPSなど安価なサーバーを使いたい場合があります。最近は DigitalOcean とかが話題ですね。他にもさくら安価なサーバーはフルマネージドではないのでイイカンジデプロイシステムがありません。

そこで今回は GitHub Actions で Self-hosted runner を利用して VPS にデプロイしてみます。

Self-hosted runner とは

通常の GitHub Actions

GitHub Actions では実行環境を以下のように runs-on で指定します。

on:
  push:
    branches: [master]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - run: npm ci
        working-directory: ./

ubuntu-latest を指定すると、GitHubのサーバー上のどこかに仮想環境ができあがって、そこでこの workflow が実行されます。

これはテスト実行時にはカンタンで良いのですが、デプロイを実行しようとしたら、

  1. ビルド結果をどこかにアップロードし
  2. VPCサーバーに接続してビルド結果をダウンロード、アプリケーション再起動

となります。

Self-hosted runner を使うと

Self-hosted runner を使うと、この workflow を VPS サーバー上で実行することができます。そのため、アプリケーションの再起動まで自動で実行できます。

GitHub の master にマージされると、アプリケーションのデプロイから再起動まで一気にできるというわけです。

Self-hosted runner の注意点

Self-hosted runner は非常に脆弱なので気をつけてください。

workflow の内容は GitHub のリポジトリで管理されています。パブリックなリポジトリに Self-hosted runner を設定していると、workflow を書き換えて push することで、任意の処理をその VPC サーバー上で実行できるので気をつけてください。

例えば、workflow をすべてのブランチで実行できるように変更したうえで、SSH できる権限を追加する、といったことが可能です。

リポジトリをプライベートにしたり、プッシュできるユーザーを制限する、サーバーで workflow を実行するユーザーの権限を制限する、など体制を万全にしてください。

Self-hosted runner の使い方

大まかな流れは以下になります。

  • GitHub Actions を実行したいサーバーを GitHub に設定する
  • サーバーで Actions Runner デーモンを起動する
  • ブランチをプッシュするとそのサーバーで workflow が実行される

今回はサーバーとして ubuntu 18.04 を使います。

サーバーをGitHubに設定する

リポジトリの Settings -> Actions -> Add Runner

f:id:yoshiki_utakata:20200613131721p:plain

コマンドが出てくるので、この通りサーバーで実行します。

ただし、最後の run.sh はまだ実行しません。 run.sh は常時起動させておく必要があるので、後で systemd で常時起動させておくよう設定します。

また、実行するときは、GitHub Actions 用のユーザーを作成して実行するようにしました。

f:id:yoshiki_utakata:20200613134558p:plain

サーバーが追加されます。 run.sh を実行していないので、 Offline になっています。

f:id:yoshiki_utakata:20200613134726p:plain

run.sh を常時起動させる

/etc/systemd/system/actions-runner.service を作成し、以下のように設定しました。

deploy は GitHub Actions 用に作成したユーザーです。systemdの設定自体はrootユーザーで行います。

[Unit]
Description=GitHub Actions Runner Daemon

[Service]
ExecStart=/home/deploy/actions-runner/run.sh
ExecStop=/bin/kill ${MAINPID}
Restart=always
Type=simple
User=deploy
Group=deploy

Github Actions Runner Daemon を起動します。

# 設定をリロードする
$ systemctl daemon-reload

# スタートする
$ systemctl start actions-runner.service

# Active になっているか確認
$ systemctl status actions-runner.service

GitHub の設定ページで見ると、さっきまで Offline になっていたのが Active になっているはずです。

f:id:yoshiki_utakata:20200613135952p:plain

workflow を書く

runs-onself-hosted を指定すると設定したサーバーで実行されます。

サーバーをGitHubに登録する時にラベルをつけられたと思いますが、self-hosted はデフォルトでつけられるラベルで、これを runs-on に指定することで、そのサーバーで GitHub Actions が実行できます。

例えば [self-hosted, dev] と指定すると、 self-hosteddev の両方のラベルがついているサーバーで実行されます。一つのリポジトリで複数のサーバーを管理している場合は、このラベルを使って実行するサーバーを変えます。

on:
  push:
    branches: [master]
jobs:
  build:
    runs-on: [self-hosted]
    steps:
      - uses: actions/checkout@v2
      - run: docker build . --tag latest-app
      - run: docker-compose -f docker-compose-dev.yml down
      - run: docker-compose -f docker-compose-dev.yml up -d

この例では docker の stop と start を行っています。このように、通常の GitHub Actions ではできないようなことも Self-hosted runner では可能になります。

注意点として、例えば今回の場合 docker はあらかじめサーバーにインストールされている必要があります。