github actionsで自動デプロイ

# 経緯
オンプレでアプリの開発をすることになりました。

その際、自動デプロイで本番環境とステージング環境ができればみんな楽に動作確認ができる！

そんな思いから、「[github actionとは何か](https://qiita.com/ponponnsan/items/faca1092576bc48c1bd2)」や「[Jenkinsと比較してどう違うか](https://qiita.com/ponponnsan/items/94284c9764f63ba6fa7f)」についてまとめました。


今回は、Github actionsを無料で、自動デプロイする方法を記事にしたいと思います。



# github actionsを無料で使用したい！

## セルフホステッドランナー
github actionsには、大まかにgithubホステッドランナーとセルフホステッドランナーの2種類があります。

どちらもパブリックリポジトリの場合は無料なのですが、githubホステッドランナーでプライベートリポジトリの場合はアカウントのプランに応じて無料使用分とストレージが異なります。

セルフホステッドランナーの方ではプライベートリポジトリでの使用が無料なのに対し、メンテナンスコストは自己で負担する必要があります。

## セルフホステッドランナーとGitHubホストランナーの特性

以下にセルフホステッドランナーとGitHubホストランナーの特性を表としてまとめました。

| 特性                                   | GitHubホストランナー                           | セルフホステッド ランナー                        |
|----------------------------------------|-----------------------------------------------|--------------------------------------------------|
| ソフトウェア更新管理                   | オペレーティング システム、パッケージ、ツールの自動更新を受け取る    | ランナーの自動更新を制御可能、無効にすることもできる                      |
| ランナーの管理とメンテナンス            | GitHubが管理およびメンテナンス                  | ユーザーが管理およびメンテナンス                  |
| インスタンス提供                       | ジョブを実行するたびにクリーンなインスタンスを提供 | ジョブを実行するたびにクリーンなインスタンスを提供しない |
| 使用料金                               | GitHubプランの無料分を使う。超過時は分単位のレートが適用 | GitHub Actionsと一緒に無料で使用できるが、ランナーのメンテナンスコストはユーザーが負担 |
| 使用するマシン                         | GitHubが提供するランナーマシンを使用           | 既存のクラウドサービスまたはローカルマシンを使用   |
| カスタマイズ                           | 不可                                          | ハードウェア、オペレーティング システム、ソフトウェア、セキュリティの要件に合わせてカスタマイズ可能 |


また、それぞれに使用制限があります。
GitHubホステッドランナーとセルフホステッドランナーの使用制限を比較した表です。

| 機能/特性          | GitHub ホステッド ランナー                    | セルフホステッド ランナー                    |
|--------------------|---------------------------------------------|---------------------------------------------|
| 利用制限           | 制限なし                                    | GitHub Actions に 14 日以上接続されないと、GitHub から自動的に削除         |
| ジョブ実行時間     | 最大6時間まで実行可能                         | 24 時間キューに入れられているセルフホスト ランナーの各ジョブはキャンセル                         |
| ワークフロー実行時間 | 各ワークフローの実行は35日まで(待機、承認、実行時間含む)         | 各ワークフローの実行は35日まで(待機、承認、実行時間含む)                                    |
| APIリクエスト      | 1つのリポジトリの全アクションで1時間に実行できる最大リクエストは1000まで                                  |1つのリポジトリの全アクションで1時間に実行できる最大リクエストは1000まで                          |
| 同時ジョブ         | アカウントごとの同時ジョブ数に制限がある *下記写真                                   | 記載なし       |
| ジョブマトリックス         | ワークフローの実行ごとに最大で256のジョブを生成       | ワークフローの実行ごとに最大で256のジョブを生成       |
| ワークフロー実行キュー         | リポジトリあたり 10 秒間隔で 500 までのワークフロー実行      | リポジトリあたり 10 秒間隔で 500 までのワークフロー実行       |


![スクリーンショット 2024-03-20 11.27.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/85855312-08f6-892c-b0de-8418b3b91608.png)

macOSで使用すると同時に実行できるジョブが格段に減りますね。linuxで実行することをお勧めします。


セルフホステッドランナーの利用制限が気になりますね...14日以上接続されないと自動的に削除かぁ、どうなるかわかりませんが、継続的に使用することを前提にとりあえずこれでやってみようかな。



### セルフホステッドランナーをサービスとして利用する

セルフホステッドランナーを追加し、実行するだけだと、マシンを再起動した時や実行コマンドを終了してターミナルで他の作業をしている際ランナーがofflineになってしまいます。

なので、セルフホステッドランナーをサービスとして利用します。サービスとして利用するということがあまりわかっていませんが、要はマシン起動時に自動的にランナーを開始するようにできるようです。

リポジトリレベルのランナーとOrganizationレベルのランナー、Enterpriseレベルのランナーを選べるみたいなので、Organizationレベルのランナーを選択したかったのですが、やり方がわからずリポジトリレベルのランナーで試してみます。

→おそらくOrganizationの設定にて、リポジトリレベルのランナーと同じような手順で設定できそうです。

### 自己ホストランナーの追加
下記サイトを参考にして行います。

https://docs.github.com/ja/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners

「設定」→「Actions」→「runners」を開き、新しくself-hosted runnerを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/54d8b7bb-54fd-f76e-e8b4-eaa157258739.png)

ランナーを実行したいOSを選択し、コマンドが表示されるのでそれに従いセットアップを完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/92737060-6d18-ef41-2408-38cca2241ccf.png)


### ランナーをサービスとして利用する
セルフホステッドランナーの追加が無事できたところで、下記サイトを参考に進めていきます。

https://docs.github.com/ja/actions/hosting-your-own-runners/managing-self-hosted-runners/configuring-the-self-hosted-runner-application-as-a-service

1. 現在稼働しているセルフホステッドランナーを停止します。
1. `sudo ./svc.sh install`でサービスをインストール
1. `sudo ./svc.sh start`でサービスをスタート
1. `sudo ./svc.sh status`でサービスの状態をチェック

ちなみに、サービスのアンインストールは以下のようにできます。
1. `sudo ./svc.sh stop`でサービスの停止
1. `sudo ./svc.sh uninstall`でサービスのアンインストール

これで晴れてサービスとして使用することができると思います。
試しにrunnnerの一覧に戻ってみるとidle状態なのが確認できました！
また、再起動してもofflineにはなっていないようなので、設定はちゃんとできたかなと思います。

![スクリーンショット 2024-03-20 14.42.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/534f3cce-3bf5-8a47-136b-d89f230823c5.png)


# 自動デプロイしたい！

では、サーバーにssh接続でリポジトリをクローンするというワークフローを書いてみたいと思います。
リポジトリ内に`.github/workflows/`作成し、yamlで書いていきます。

```yaml
name: check deploy

on:
  push:
    branches:
      - stg

jobs:
  build:
    runs-on: self-hosted
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: ssh connection
        uses: appleboy/ssh-action@master
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          username: ${{ secrets.SERVER_USERNAME }}
          host: ${{ secrets.SERVER_HOST }}
          port: ${{ secrets.SSH_PORT }}
          script: |
            whoami
            pwd
            cd "${{ secrets.SERVER_DEPLOY_DIR }}"
            git config --global url."https://${{ secrets.GIT_TOKEN }}@github.com/".insteadOf "https://github.com/"

            git clone "${{ secrets.GIT_REPO_URL }}"

            echo "Deployment complete!!!"
```
少し補足すると、

`${{ secrets.SSH_PRIVATE_KEY }}`などは、環境変数です。githubのsecretsで設定してあるものを持ってきています。

githubの認証にgithub access tokenを用いています。しかし、カスタムでも1年以上の設定はできなかったため、設定は簡単ですが、更新しないといけません。

```
git config --global url."https://${{ secrets.GIT_TOKEN }}@github.com/".insteadOf "https://github.com/"
```

他の方法として、公開鍵を作成し、デプロイキーとして登録する方法があります。
こちらの方が、期限がないので使いやすそうですが、試していません。
いつか役に立ちそうなので書いておきます。

```yaml
- name: Deploy 
  env:
    SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_DEPLOY_KEY }}
  run: |
    mkdir -p ~/.ssh
    echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    git clone "${{ secrets.GIT_REPO_URL }}"
```

他にもrunでスクリプトファイルを実行させるという方法もあります。
私も本当はスクリプトファイルで実行させたかったのですが、実行ファイルがssh接続した際にないと言われてしまい...
やっぱりそのファイルだけ最初にコピーしないといけないのかなと思いつつ、面倒なので、そのまま書きました。

もし試した方がいれば、この方法なら簡単にいけた等々教えていただきたいです！

# 参考文献
https://docs.github.com/ja/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners

https://docs.github.com/ja/actions/learn-github-actions/usage-limits-billing-and-administration

https://zenn.dev/takashiaihara/articles/62b1f12d22c6bd

https://zenn.dev/hironobuu/articles/e85418948e896f

https://github.com/marketplace/actions/ssh-remote-commands