OCIインスタンス Run command機能を使用したJob管理

# 概要
Oracle Cloud Infrastructure(OCI)のインスタンスにコマンドを発行できる機能(Run command)があります。
[インスタンスでのコマンドの実行](https://docs.oracle.com/ja-jp/iaas/Content/Compute/Tasks/runningcommands.htm)
今回このRun commandを使用してWindowsおよびLinuxのインスタンスにScriptを実行します。

# 何がいいの?
Run commandによりインスタンスにログインして操作しなくてもコマンドやJobを実行できます。タスクスケジューラやCronの代わりにJob管理ツールとRun commandを組み合わせることにより外部からJobを管理できるので例えばこのような運用効率向上が期待できます。
- オペレータにてログイン不要でJob実行
- Job管理ツールとの組み合わせでJobを一元管理
- 複数のインスタンスに対して変更や配布

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/d3084f3d-36ba-e410-06b2-138fece93ac0.png">

# 構成
インスタンスに実行させるScriptやOutputはObject storageを介して行われます。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/d7ec1d99-015c-1007-ef1d-f2bbdc5a471d.png">

(1) OCI内に作成したJob管理ツール等からRun commandを作成
(2) OCI内対象インスタンスのエージェントがRun commandの内容を受信
(3) エージェントがObject Storageに保管されたScriptをダウンロード
(4) エージェントにてScriptを実行
(5) エージェントがScript実行結果(Output)をObject Storageにアップロード
(6) 必要に応じてJob管理ツール等からOutputをダウンロードして確認

# 作成
## 情報取得
以下の情報を入手します。
- コンパートメントOCID
OCIコンソールの検索窓からコンパートメント名を入力するとコンパートメントが表示されるのでクリック
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/03a79a09-6192-0a64-bbed-8caa06597e05.png">

コンパートメント内容が表示されるのでOCIDをコピー
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/b534eeb4-ccb4-a653-ef48-e32d916a4813.png">

- Object Storageのネームスペースおよびバケット名
OCIナビゲーションメニューからストレージ>>バケット名から対象バケットを選択してネームスペースをメモ、バケットOCIDをコピー

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/be04393e-7243-d8db-8539-631447fa0b2d.png">

- インスタンスOCID
Run commandを実行するインスタンスの情報を取得します。
OCIナビゲーションメニューからコンピュート>>インスタンスから対象インスタンスを選択してOCIDをコピー
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/95dff0ef-da3c-753f-c96e-42808174444d.png">

## インスタンス側Run command環境準備
- OCIナビゲーションメニューからコンピュート>>インスタンスから対象インスタンスを選択,Oracle Cloudエージェントタブを選択してコンピュートインスタンスの実行コマンドプラグインが実行中であることを確認
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/59384f95-a61d-7a2a-f5fd-a9d01dbc9edb.png">

- 管理者権限で実行する場合は以下を実行
[管理者権限でのコマンドの実行](https://docs.oracle.com/ja-jp/iaas/Content/Compute/Tasks/runningcommands.htm#administrator-privileges)
    -ユーザーOCARUNに管理者権限を付与します
    -付与後にインスタンス再起動をおすすめします

## Script準備
インスタンスで実行するScriptを準備します。
今回実施するScriptはnginxの起動と起動確認です。
<font color="Red">Script内の改行はWindowsはCR+LF, LinuxはLFで作成してください。</font>

- Script作成
Windows
```source_nginxstart_win.txt
echo %date%
echo %time%

cd c:\nginx-1.24.0
start nginx

ping 127.0.0.1
curl -s -o nul -w "%%{http_code}" http://127.0.0.1
exit /b
```

Linux
```source_nginxstart_linux.txt
date

sudo systemctl start nginx

ping -c 4 127.0.0.1
curl -s -o /dev/nul -w "%{http_code}" http://127.0.0.1
exit 0
```


- Object Storageにアップロード
OCIナビゲーションメニューからストレージ>>バケット名から対象バケットを選択してアップロード
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/9b423ece-08cb-d6f0-3805-651f03e69dca.png">

## OCIポリシー
Job管理ツール等からRun command実行可能にするためにポリシーを追加します。

- Job管理ツール等のインスタンスを含む動的グループを作成
[動的グループの管理](https://docs.oracle.com/ja-jp/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#three)

- 動的グループにObject Storageの読取/書込許可を付与
[ポリシーの作成](https://docs.oracle.com/ja-jp/iaas/Content/Identity/policymgmt/managingpolicies_topic-To_create_a_policy.htm)
```
Allow dynamic-group 【動的グループ名】 to manage objects in compartment 【コンパートメント名】
```
- 動的グループにRun command実行許可を付与
[ポリシーの作成](https://docs.oracle.com/ja-jp/iaas/Content/Identity/policymgmt/managingpolicies_topic-To_create_a_policy.htm)
```
Allow dynamic-group 【動的グループ名】 to use instance-agent-command-execution-family in compartment 【コンパートメント名】
```

参考：[Run commandのポリシー作成](https://docs.oracle.com/ja-jp/iaas/Content/Compute/Tasks/instances.htm#permissions)

## Job管理ツール等準備
Script場所、Output場所およびインスタンスを指定するJSONを作成します。
Windows
```runcommand_nginxstart_win.json
{
 "compartmentId": "【コンパートメントOCID】ocid1.compartment.oc1..*****",
 "content": {
  "output":
    {
      "bucketName": "【バケット名】",
      "namespaceName": "【ネームスペース】",
      "objectName": "runcommand/output_nginxstart_win.log",
      "outputType": "OBJECT_STORAGE_TUPLE"
    },
  "source":
    {
      "bucketName": "【バケット名】",
      "namespaceName": "【ネームスペース】",
      "objectName": "runcommand/source_nginxstart_win.txt",
      "sourceType": "OBJECT_STORAGE_TUPLE"
    },
 },
 "displayName": "nginxstart_win",
 "target": {
  "instanceId": "【インスタンスOCID】ocid1.instance.oc1.ap-tokyo-1.*****"
 },
 "timeoutInSeconds": "300"
}
```

Linux
```runcommand_nginxstart_linux.json
{
 "compartmentId": "【コンパートメントOCID】ocid1.compartment.oc1..*****",
 "content": {
  "output":
    {
      "bucketName": "【バケット名】",
      "namespaceName": "【ネームスペース】",
      "objectName": "runcommand/output_nginxstart_linux.log",
      "outputType": "OBJECT_STORAGE_TUPLE"
    },
  "source":
    {
      "bucketName": "【バケット名】",
      "namespaceName": "【ネームスペース】",
      "objectName": "runcommand/source_nginxstart_linux.txt",
      "sourceType": "OBJECT_STORAGE_TUPLE"
    },
 },
 "displayName": "nginxstart_linux",
 "target": {
  "instanceId": "【インスタンスOCID】ocid1.instance.oc1.ap-tokyo-1.*****"
 },
 "timeoutInSeconds": "300"
}
```

<details><summary>参考:JSONファイルについて</summary><div>
JSONのひな形は以下のコマンドから入手可能です。

```
[user@linux]$ oci instance-agent command create --generate-full-command-json-input
{
  "compartmentId": "string",
  "content": {
    "output": [
      "This parameter should actually be a JSON object rather than an array - pick one of the following object variants to use",
      {
        "bucketName": "string",
        "namespaceName": "string",
        "objectName": "string",
        "outputType": "OBJECT_STORAGE_TUPLE"
      },
      {
        "outputType": "OBJECT_STORAGE_URI",
        "outputUri": "string"
      },
      {
        "outputType": "TEXT"
      }
    ],
    "source": [
      "This parameter should actually be a JSON object rather than an array - pick one of the following object variants to use",
      {
        "bucketName": "string",
        "namespaceName": "string",
        "objectName": "string",
        "sourceType": "OBJECT_STORAGE_TUPLE"
      },
      {
        "sourceType": "OBJECT_STORAGE_URI",
        "sourceUri": "string"
      },
      {
        "sourceType": "TEXT",
        "text": "string",
        "textSha256": "string"
      }
    ]
  },
  "displayName": "string",
  "target": {
    "instanceId": "string"
  },
  "timeoutInSeconds": "string"
}
```
</div></details>


# 実行
Job管理ツール等のインスタンスから実行します。
Windows
```
[user@linux]$ oci instance-agent command create --auth instance_principal --endpoint https://iaas.ap-tokyo-1.oraclecloud.com --from-json file:///path/to/runcommand_nginxstart_win.json
```
Linux
```
[user@linux]$ oci instance-agent command create --auth instance_principal --endpoint https://iaas.ap-tokyo-1.oraclecloud.com --from-json file:///path/to/runcommand_nginxstart_linux.json
```
OCIコンソールナビゲーションメニュー>>インスタンスから対象インスタンスを選択して左下のリソースメニューから実行コマンドを選択すると実行コマンドの状況が確認できます。
コマンド投入時
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/053750d5-df20-d513-973d-8af3aef09113.png">
コマンド成功時
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/2c5d0535-ff22-3936-3cfe-0d7515638fce.png">

OutputはObject storageからダウンロードして確認可能です。
Windows
```
[user@linux]$ oci os object get --auth instance_principal --endpoint https://objectstorage.ap-tokyo-1.oraclecloud.com --namespace 【ネームスペース】 --bucket-name 【バケット名】 --name runcommand/output_nginxstart_win.log --file output_nginxstart_win.log
Downloading object  [####################################]  100%
```

```runcommand_output_nginxstart_win.log
C:\Windows\system32>echo Mon 04/08/2024 
Mon 04/08/2024

C:\Windows\system32>echo 16:06:48.03 
16:06:48.03

C:\Windows\system32>cd c:\nginx-1.24.0 

c:\nginx-1.24.0>start nginx 

c:\nginx-1.24.0>ping 127.0.0.1 

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

c:\nginx-1.24.0>curl -s -o nul -w "%{http_code}" http://127.0.0.1 
200
c:\nginx-1.24.0>exit /b 
```
Linux
```
[user@linux]$ oci os object get --auth instance_principal --endpoint https://objectstorage.ap-tokyo-1.oraclecloud.com --namespace 【ネームスペース】 --bucket-name 【バケット名】 --name runcommand/output_nginxstart_linux.log --file output_nginxstart_linux.log
Downloading object  [####################################]  100%
```

```runcommand_output_nginxstart_linux.log
Mon Apr  8 15:59:19 JST 2024
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.048 ms

--- 127.0.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3054ms
rtt min/avg/max/mdev = 0.046/0.048/0.051/0.002 ms
200
```
Windows,Linuxともにnginxの起動と起動確認ができました。
これらのOCI CLIコマンドをJob管理ツールに登録すれば運用に取り込むことができます。