GitHub Actionsを使ってEC2に自動デプロイ 

GitHub Actionsを使ってEC2への自動デプロイをやります。
本やり方ではセキュリティグループのIP制限問題にも対応しています。
画像を多めに使って初めて構築する方にもわかりやすくまとめています。

# はじめに
Github Actionsを使用してCI/CD（Continuous Integration/Continuous Deploy）環境のCD（自動で本番環境にリリースを行う）部分についてやり方をご紹介します。

元々やっていたやり方は直接EC2サーバ内にSSH接続で入ってgit pullを直接実行していました。サーバは1台なのでまだいいのですが、頻度が多くなってくるととても面倒です。
これが負荷分散によってサーバが増大したりすると1台ずつ対応は現実的に難しいですね。
それを解消するために自動デプロイの方法を実装しました。

# 実装することの概要
developブランチへのマージ・プッシュなどをトリガーに実行

↓

Github Actionsに登録されているworkflowを実行

↓

EC2に入り、git fetch とgit pullを実行

↓

問題なければworkflowで緑チェックが入る

※本来ではあればセキュリティグループのIP制限によって
Githubからsshで入ることはできないのですがIAMで発行した情報を元にAWS CLIで実行するためセキュリティグループの制約をくぐり抜けて実行ができます。

# 前提
・Githubで管理しているリポジトリをEC2内に配置していること
・EC2内にSSHで入れてgit pullなど実行できること

# 主な手順
1. IAMユーザーの発行
2. 鍵の生成・登録
3. GithubにSecrets情報の登録
4. Github Actionsのworkflowを作成
5. 実行テスト

# 1. IAMユーザーの発行
新規にIAMユーザーを発行します。
ポリシーにはAmazonEC2FullAccessをつけておきます。

作成後は下記の緑枠の箇所でアクセスキーを発行できます。

![スクリーンショット_2023-12-04_15_18_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/91d5dda5-5aa3-a641-8571-a780ae319017.png)

ユースケースの選択は「コマンドラインインターフェイス (CLI)」になります。
![スクリーンショット 2023-12-04 15.20.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/11be4222-7d4c-2d4e-e4e3-9a92b69907da.png)

ここで発行されたアクセスキーとシークレットキーは後で使いますのでメモしておいてください。

# 2. 鍵の生成・登録
デプロイしたいサーバからGithubのリポジトリへ接続するための鍵を生成します。
そして生成された公開鍵をGithubに登録します。

## 2.1 鍵の生成

```
# EC2サーバーにSSH接続
$ ssh ec2

# .sshに移動
$ cd ~/.ssh

# キーをgenerate
$ ssh-keygen -t rsa

Enter file in which to save the key ():  // Enter
Enter passphrase (empty for no passphrase):  // Enter
Enter same passphrase again:  // Enter
```

これにより、`id_rsa`と`id_rsa.pub`の2つの鍵、つまり秘密鍵と公開鍵が生成されました。

※id_rsa以外の命名にするとgitコマンド実行時に私の環境では失敗したため、他の名前にすることはおすすめしません。

## 2.2 公開鍵をGithubに登録

以下のコマンドを用い、公開鍵をコピーしておきます。

```
$ cat ~/.ssh/id_rsa.pub
```

GithubのSettingを開き
以下の画像の手順に従い鍵の登録を行います。

![スクリーンショット_2023-12-04_15_34_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/d5c20778-d9e7-96b5-0407-d85e92afd996.png)

![スクリーンショット_2023-12-04_15_35_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/fc71b6aa-b453-1a3f-191b-d7ffa1900069.png)

![スクリーンショット_2023-12-04_15_43_40-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/cb55456d-38bc-a7e6-5957-da8bcf48fec9.png)

この手順によって公開鍵の登録が完了します。
登録時は「Never used」と表示されアイコンや文字は灰色になっています。
使用が問題なくできた場合に緑色に変化します。

# 3. GithubにSecrets情報の登録
GitHubには、各リポジトリごとに暗号化された変数を登録できる機能があります。
Secretsというもので.envと同じ使われ方をします。
この機能を利用することで、公開できないシークレット情報をGitHubリポジトリ内で管理してソースコードには表示することなく隠した状態で管理し、GitHub Actionsで使用することができます。
今回はこの機能を利用して必要な情報を変数として事前に登録しておきます。

GitHub のリポジトリに移動し、Settings → Secrets の順に進み、以下の情報を登録していきます。

![スクリーンショット_2023-12-04_15_54_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/6ff680e6-047c-ffa7-2e6f-79fc3f0f2c73.png)

Secrets一覧画面にて登録していきます。

<table>
  <caption>HTMLの要素</caption>
  <thead>
    <tr>
      <th>名前（任意）</th> <th>記載内容</th> <th>例</th>
    </tr>
  </thead>
  <tr>
    <td> HOST_NAME </td> <td>サーバのホスト（IPやドメイン）</td> <td>（サーバー情報を確認してください）</td>
  </tr>
  <tr>
    <td> USER_NAME </td> <td>デプロイサーバーログインのusername</td> <td>ec2-user（サーバー情報を確認してください）</td>
  </tr>
  <tr>
    <td> PRIVATE_KEY </td> <td>生成した秘密鍵の内容</td> <td>※生成した秘密鍵のid_rsaの中身</td>
  </tr>
  <tr>
    <td> AWS_ACCESS_KEY </td> <td>IAMユーザーのアクセスキー</td> <td>※IAM発行時に取得したアクセスキー</td>
  </tr>
  <tr>
    <td> AWS_SECRET_ACCESS_KEY </td> <td>IAMユーザーのシークレットキー</td> <td>※IAM発行時に取得したシークレットアクセスキー</td>
  </tr>
  <tr>
    <td> EC2_SECURITY_GROUP_ID </td> <td>EC2のセキュリティグループID</td> <td>sg-00XXXXXXXXXXXX</td>
  </tr>
</table>


![スクリーンショット_2023-12-04_15_56_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/4b8fed97-46c3-447c-e1f7-e5213e4cce45.png)

上記のように登録されていれば大丈夫です。
これらの登録が何のことかまだわかりにくいと思いますがこの先のworkflowの設定で使います。

Secrets 情報の登録により、GitHub Actions のジョブを記述する YAML ファイルから変数として参照することが可能になります。

なお、EC2 のセキュリティグループIDが必要な理由について説明します。
通常、EC2 のセキュリティグループ設定ではIP制限をして SSH 接続してアクセス可能な設定になっていることが多いため、GitHub からのアクセスを許可するためにはセキュリティグループの設定を変更する必要があります。

では、EC2 へのアクセス方法について説明します。

GitHub Actions が起動される GitHub の IP は毎回変動するため、事前に固定 IP を指定してアクセスを許可することはできません。
そのため、GitHub Actions が起動したタイミングで AWS CLI を使用して一時的にセキュリティグループに対してアクセスを許可する設定を変更します。そして、処理が終了したらセキュリティグループを元に戻します。
このようにすることで、GitHub Actions から EC2 へのアクセスを一時的に許可し、安全に処理を行うことができます。
[引用元](https://note.com/ryoppei/n/nf2bf7ee78b0b)

# 4. Github Actionsのworkflowを作成
GithubのリポジトリにてヘッダーにあるActionsを選択します。
これがGithub Actionsです。

## 4.1 Github Actionsの作成

「New workflow」を押下してworkflowの登録へと進みます。

![スクリーンショット_2023-12-04_16_15_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/69195692-dde7-aeff-ef05-61b973533779.png)


色々と便利なworkflowが用意されているのですが
今回は手動入力で作成するため「set up a workflow yourself」を選択します。

![スクリーンショット_2023-12-04_16_58_01-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/248c203b-2d1c-3f3f-6ea3-8fbfd085243b.png)



この画面になり、
workflowの名前とジョブの設定をします。

![スクリーンショット_2023-12-04_16_26_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/1c8fe577-e160-9226-6579-8bc9d515832e.png)

下記をymlファイルとして設定してください。
「プロジェクトディレクトリ」と記載がある箇所は配置しているアプリのディレクトリ名に差し替えてください。

```yaml
name: EC2 auto deploy

on:
 pull_request:
   branches: [ main ]
   types: [closed]

 workflow_dispatch:

jobs:
 build:
   runs-on: ubuntu-latest
   steps:

     # IP取得ライブラリをインストール
     - name: Public IP Install
       id: ip
       uses: haythem/public-ip@v1.3

     # BranchをCheckout
     - name: Checkout
       uses: actions/checkout@v2

     # AWS CLIをインストールする
     - name: AWS CLI install
       run: |
         curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
         unzip awscliv2.zip
         sudo ./aws/install --update
         aws --version

     # AWS CLIにキーを設定をする
     - name: AWS set Credentials
       uses: aws-actions/configure-aws-credentials@v1
       with:
         aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
         aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
         aws-region: ap-northeast-1

     # デプロイする
     - name: Deploy
       run: |

         # SSHのセキュリティグループを開放する
         aws ec2 authorize-security-group-ingress --group-id ${{ secrets.EC2_SECURITY_GROUP_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32

         # SSH接続して、git pullする
         echo "${{ secrets.GIT_PRIVATE_KEY }}" > private_key
         chmod 600 private_key
         ssh -oStrictHostKeyChecking=no ${{ secrets.EC2_USER_NAME }}@${{ secrets.EC2_HOST_NAME }} -i private_key "cd /var/www/html/プロジェクトディレクトリ && git fetch --prune && git checkout main && git pull origin main"

         # SSHのセキュリティグループを閉じる
         aws ec2 revoke-security-group-ingress --group-id ${{ secrets.EC2_SECURITY_GROUP_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
```

[引用元](https://note.com/ryoppei/n/nf2bf7ee78b0b)

## 4.2 それぞれの設定項目の解説

### 4.2.1 on:でやっていること

ここでは GitHub Actions のトリガーを設定します。

```
pull_request:
   branches: [ main ]
   types: [closed]
```

mainブランチへのプルリクエストがクローズされた時に、プルリクエストを出した側のブランチがクローズされ、このタイミングで起動するように設定されています。

### 4.2.2 runs-on: でやっていること

今回はubuntu-latestを選択しています。
ここでは使用しているEC2のlinuxであってもubuntu-latestとしてください。
Github Actionsを実行する環境をubuntu-latestとする意味になります。


```
runs-on: ubuntu-latest
```

### 4.2.3 jobs:でやっていること
jobsの中のstepsには、実際に行う処理を記述していきます。
jobsでは、nameを使用して作業の名前を指定し、usesを使用して特定のライブラリを使用するかどうかを設定し、runで具体的な処理内容を記述します。

```
● name + uses
● name + run
```

実行されている内容を順番に説明していきます

```
● GitHub ActionsのIPを取得します。
● ブランチをチェックアウトします。
● AWS CLIにキーを設定してCLIからEC2を操作可能にします。
● EC2のセキュリティグループを開放します。
● mainに取り込まれた内容をEC2上にpullします。
● EC2のセキュリティグループを閉じる。
```
# 5. 実行テスト
workflow_dispatchイベントの登録によって手動でworkflowを実行できるようになっています。

![スクリーンショット_2023-12-04_16_42_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/13820e03-ce46-de52-670b-d567c07aed70.png)

実行してみるとその結果を3点リーダー内メニューの「View workflow file」から確認できます。
左メニューのbuild内を開いて問題なく実行できていればチェックマークが入り、buildメニューの左に緑チェックが入ります。

各フェーズの細かい情報も確認できます。

![スクリーンショット_2023-12-04_16_45_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/27024b70-ae5a-3d9b-83e3-60205f54e405.png)

これは手動実行でしたので、
実際のプルリクエストのマージ時の挙動も試して見たところ問題ありませんでした。

これで完了です。

# 終わりに
今回はEC2への自動デプロイを実装してみました。
Github Actionsを使えば他にも自動テストや自動コンテナ作成や自動メールなど他に色々とやれることがありそうですね。
IAMのアクセスキーやシークレットキーなどは漏れてしまうのは大問題ですのでセキュリティには十分注意して実装をお願いします。
よい自動デプロイライフを！

# 参考
・アクセスキーの発行
https://qiita.com/yamasakk/items/3060d22faeed8e05ebe4
・公開鍵のGithunへの登録
https://codelikes.com/github-ssh-connection/
・EC2への自動デプロイ
https://note.com/ryoppei/n/nf2bf7ee78b0b