VPCの仮想サーバーを定期的に停止、起動する[IBM Cloud汎用操作ツール]

# はじめに
こちらは、下記で公開したツールを利用したユースケースの1例になります。

https://qiita.com/katahiro/items/70502a32492d9320309f

IBM CloudのVPCで利用可能な仮想サーバーのインスタンスは[Suspend Billing](https://cloud.ibm.com/docs/vpc?topic=vpc-suspend-billing)に対応しています。
つまり、使っていない間はサーバーを停止しておくと、そのサーバーに対してかかる費用のうち、vCPU、メモリ、利用OSにかかる請求を止めることが出来ます。
1カ月連続稼働させると請求が10%オフになる割引サービスはありますが、開発環境等、使っていない間は止めておきたい環境もあると思うので、定期的に停止、起動できるとよりコストを抑えた運用が可能になります。

IBM Cloudではポータル上でVPCの仮想サーバーを停止、起動を操作することが可能ですが、これを定期的に実行する機能はありません。

これを、作成した汎用操作ツールで実現する方法を紹介します。

# Code Engineでの設定
まずは、仮想サーバを停止するJobです。コマンド実行するだけの環境なので、スペックは最小にしましょう。

- Job Name : `任意の名称`
- Image Reference : `docker.io/hiroapps/ibmcloud-cli-image:1.1.0`
- Job instances : `1`
- Instance resources 
    - CPU and memory : `0.125 vCPU / 0.25 GB`
    - Ephemeral storage (GB) : `0.04`
- Resiliency settings 
    - Mode : `Task`
    - Number of job retries : 3
- Optional settings
    - Environment Variables (optional)
        - `COMMAND00` : `ibmcloud config --check-version=false`
        - `COMMAND01` : `ibmcloud login -- apikey [権限のあるAPIキー] -r [VPCのあるリージョン]`
        - `COMMAND02` : ``if [ `ibmcloud is in $INSTANCE_NAME --output json | jq -r ".status"` == "running" ]; then ibmcloud is instance-stop -f $INSTANCE_NAME ; fi``
        - `INSTANCE_NAME` : `[仮想サーバーのインスタンス名]`


:::note warn
2024/3/5 `COMMAND00`を追加しました。CLIのバージョンアップを問われるので、それを無視するための実行が必要になります。
:::

:::note
執筆時点で利用するイメージは `docker.io/hiroapps/ibmcloud-cli-image:1.1.0`としていますが、最新のイメージがある場合はそちらを利用ください。 
また、利用者でツールのイメージを別のコンテナレジストリに格納している場合はそちらを利用ください。
:::

`COMMANDxx`で指定する内容の注意点ですが、まずログインコマンドではVPCのあるリージョンを必ず指定してください。IBM Cloud CLIでVPCの操作は設定されているログイン時、または `ibmcloud target` コマンドで指定されたリージョンのVPC環境を対象とするためです。
インスタンスの停止コマンドは、インスタンスの状態が `runnning` つまり、通常稼働状態である場合に停止コマンドを実行するようにしています。`-f`のオプションを入れないと、停止してよいかの確認が行われてしまい、停止することが出来ないです。
今回は `COMMAND02` でインスタンス名の指定が2回あるので、インスタンス名自体を環境変数に指定して実行するようにしていますが、インスタンス名の環境変数は設定せずに、コマンドの中で直接インスタンス名を指定しても構いません。

# 実行してみよう
さて、上記の権限設定に問題なければ、先ほど指定した環境変数のコマンドに従ってVPCのインスタンスで停止指示が実行されます。

Jobを作成して、`Submit Job`でJobを手動実行してみましょう。

以下はJobの実行ログをLogDNAのサービスで確認したものです。
```console
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 ## COMMAND01 ##
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 $ ibmcloud login *****
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 API endpoint: https://cloud.ibm.com
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Authenticating...
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 OK
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Targeted account IBM (アカウントID)
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Targeted region jp-tok
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 API endpoint:      https://cloud.ibm.com
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Region:            jp-tok
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 User:              ServiceId-サービスID (サービスID名)
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Account:           IBM (アカウントID)
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Resource group:    No resource group targeted, use 'ibmcloud target -g RESOURCE_GROUP'
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 CF API endpoint:   
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Org:               
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 Space:             
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 ## COMMAND02 ##
Jan 24 11:15:18 Code Engine cli-test-jobrun-kcsg2-0-0 $ if [ `ibmcloud is in $INSTANCE_NAME --output json | jq -r ".status"` == "running" ]; then ibmcloud is instance-stop -f $INSTANCE_NAME ; fi
Jan 24 11:15:38 Code Engine cli-test-jobrun-kcsg2-0-0 Creating action stop for instance インスタンス名 under account IBM as user ServiceId-サービスID...
Jan 24 11:15:38 Code Engine cli-test-jobrun-kcsg2-0-0 Type      stop   
Jan 24 11:15:38 Code Engine cli-test-jobrun-kcsg2-0-0 Created   2024-01-24T02:15:37+00:00 
```
問題なく仮想サーバーの停止操作が実行されました。

これで仮想サーバーを停止するJobが作成できました。
では、仮想サーバーを起動するJobを作成しましょう。もう1つJobを新規作成して、下記のように設定してください。

- Job Name : `任意の名称`
- Image Reference : `docker.io/hiroapps/ibmcloud-cli-image:1.1.0`
- Job instances : `1`
- Instance resources 
    - CPU and memory : `0.125 vCPU / 0.25 GB`
    - Ephemeral storage (GB) : `0.04`
- Resiliency settings 
    - Mode : `Task`
    - Number of job retries : 3
- Optional settings
    - Environment Variables (optional)
        - `COMMAND00` : `ibmcloud config --check-version=false`
        - `COMMAND01` : `ibmcloud login -- apikey [権限のあるAPIキー] -r [VPCのあるリージョン]`
        - `COMMAND02` : ``if [ `ibmcloud is in $INSTANCE_NAME --output json | jq -r ".status"` == "stopped" ]; then ibmcloud is instance-start $INSTANCE_NAME ; fi``
        - `INSTANCE_NAME` : `[仮想サーバーのインスタンス名]`

:::note warn
2024/3/5 `COMMAND00`を追加しました。CLIのバージョンアップを問われるので、それを無視するための実行が必要になります。
:::

先ほどと何が違うかと言われると `COMMAND02`で指定しているコマンド内容で、サーバーが停止状態の場合にのみ起動のコマンドを実行するようにしています。

# Event Subsctiptionへの登録
Event Subscriptionへの登録は次のリンク記事の途中から記載しているので、そちらを参考にしてください。

https://qiita.com/katahiro/items/68dd7609844b98925937#code-engine%E3%81%A7%E7%A8%BC%E5%83%8D%E8%A8%AD%E5%AE%9A

cron形式で起動する時間を指定できるので、夜に停止するJobを登録して、朝に起動するJobを登録すれば良いでしょう。
例えば開発環境で、夜間もう少し作業したい、というケースもあるかもしれません。夜間は例えば2時間毎に停止するJobを実行するようにしておいて、誰かが起動したとしてもまた停止されるようにするのも1つの運用方法かもしれません。

:::note warn
こちらの紹介内容だとIBM Cloud側の操作で強制的に停止されるので、サーバー停止はサーバー側でJobを組んで安全にShutdownするようにしたほうが良いかもしれません。
あくまでIBM Cloud上での操作を自動実行するものとご理解ください。
:::

# さいごに
いかがでしたでしょうか？
IBM Cloud汎用操作ツールで、VPC環境をなるべく費用節約する形で運用できる可能性が実現できました。ぜひ、このユースケースを参考にIBM Cloudで理想的な運用ができると幸いです。