GitHub ActionsでEC2インスタンスの自動停止をするようにした

この記事は、Qiita エンジニアフェスタ 2022 [GitHub Actions の自分流の使い方をシェアしよう](https://qiita.com/official-events/14b94a693d6153857db4) の参加記事です。

https://qiita.com/official-events/14b94a693d6153857db4

## はじめに

僕は個人の作業環境の 1 つとして EC2 のインスタンスを立てているのですが、コストをなるべく書けたくはないので、使用するとき以外はインスタンスを停止しています。
ですが、インスタンスの停止を忘れてしまうことが多々ありました。

それから「自動で停止するようにしたいなぁ」と思い、AWS CLI でインスタンスを停止する GitHub Actions の workflow を用意して、schedule イベントでトリガーさせることにしました。

上記のようにした理由は、

- 自由が効く
- cron サーバーを用意するのはめんどくさい（というか cron サーバーを立ててる時点で本末転倒？）

です。
あとは単純に楽しそうだなという好奇心です。

以下で紹介している、EC2 インスタンスを停止する workflow をベースにカスタマイズすれば、自身のユースケースにあったインスタンス自動停止を実現できるかもしれません。

## 自分のユースケースを知る

EC2 インスタンスの自動停止を調べると、CPU 使用率などを監視する方法などが出てきました。
それでもいいかなと思ったんですが、本を読みながら or 調べ物をしながらインスタンスを起動しているときに停止されるのは「ちょっとなぁ」と思ったので、別の方法を考えました。

僕の場合、EC2 インスタンスに対してセッションマネージャーで接続をしてるので、

- セッションマネージャーのセッションがない & インスタンスが起動してる場合に停止をする

のが良さそうだなと思い、この方法を実現することにしました。

僕の場合は上記のような感じにしましたが、人によってユースケースは違うと思うので、自分のユースケースを知って自分に良い停止方法を導き出してみると面白いかもしれません。

## workflow を用意する

自分のユースケースにあった workflow を用意します。

以下は 1 時間ごとにインスタンスに停止をリクエストする例です。

```yaml:auto-stop-instances.yml
name: Auto stop instances

on:
  schedule:
    - cron: "0 * * * *"

permissions:
  contents: read

env:
  INSTANCE_IDS: "xxxxxxxxxx" # 停止したいEC2インスタンスのIDs

jobs:
  stop-instances:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v3
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-region: ${{ secrets.AWS_REGION }}
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      - run: aws ec2 stop-instances --instance-ids ${{ env.INSTANCE_IDS }}
```

上記の workflow をベースに自分のユースケースに合わせたものにカスタマイズをします。

僕の場合は、セッションマネージャーのセッションがない場合は、インスタンスを停止するようにしたいので、以下のようになります。

```yaml:auto-stop-instance.yml
name: Auto stop instance

on:
  schedule:
    - cron: "0 * * * *"

permissions:
  contents: read

env:
  INSTANCE_ID: "xxxxxxxxxx" # 停止したいEC2インスタンスのID

jobs:
  stop-instance:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v3
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-region: ${{ secrets.AWS_REGION }}
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      - run: aws ssm describe-sessions --state Active --output json > output.json
      - run: grep ${{ env.INSTANCE_ID }} output.json
        id: check-session
      - run: aws ec2 stop-instances --instance-ids ${{ env.INSTANCE_ID }}
        if: ${{ steps.check-session.outputs.stdout == '' }}
```

上記の例だと、1 つのインスタンスしか停止できないので、複数のインスタンスを停止したい場合は改良が必要です。

## 最後に

GitHub Actions で EC2 インスタンスの自動停止についてでした。

やっぱり、自分の役に立つものを自分でつくるのは楽しいですね。
しかも、それを手助けしてくれるツールやサービスが世の中に溢れているのには本当に感謝です。

この記事の内容が何かしら参考になれたら嬉しいです。

## Refs

- [GitHub Actions Documentation - GitHub Docs](https://docs.github.com/en/actions)
- [aws-actions/configure-aws-credentials: Configure AWS credential environment variables for use in other GitHub Actions.](https://github.com/aws-actions/configure-aws-credentials)
- [stop-instances — AWS CLI 1.25.6 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/ec2/stop-instances.html)
- [describe-sessions — AWS CLI 1.25.6 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/ssm/describe-sessions.html)