【OCI クラウド移行ガイド】AWS SQSをOCI Queueで実装してみた_キューサービス編

# はじめに
本記事は[Oracle Cloud Infrastructure Advent Calendar 2023](https://qiita.com/advent-calendar/2023/oci) の 11 日目の記事です。
	
キューサービスはクラウドネイティブなサービスで、性能向上、コスト削減や観点でパブリッククラウド上で利用するケースも少なくないと思います。
筆者自身、キューサービスを触ったことがなかったのでAWS SQSでできる基本的な動作がOCI Queueでも実装できるか試してみました。
今回はAWS側はBoto3、OCI側はSDK for Pythonを利用しました。
タイトルはAWS SQSをOCI Queueで実装してみたとなっていますが、AWS SQSの基本的な動作/実装がOCI Queueでも問題なく動作/実装できることを主軸の紹介記事としてしていることご容赦ください。

# OCIクラウド移行ガイドとは
オンプレミスやAWSなど、複数のプラットフォームからOracle Cloud Infrastructureへの移行プロジェクトに取り組んでいるクラウドエンジニア（@araidon,@kazunishi,@yama6）による、OCI移行手順をまとめたシリーズ記事です。
各回、サンプルワークロードから対象サービスを取り上げ、移行手順をガイドいたします。

まとめ記事は以下になります。

https://qiita.com/yama6/items/b197c0fe3ec75eb02637

# 移行するサービス：AWS SQS	
冒頭記載したように今回はAWS SQSをOCI Queueを移行/同様の動作ができるか試してみようと思います。
キューサービスって何?キューサービス触ってみたいが具体的にどうやって?という方には一読いただけると幸いです。

# 作業の流れ
今回は以下図のように1台の仮想マシンからキューにメッセージの送受信を試してみようと思います。
本来であれば別インスタンスで実現することでシステムの疎結合を実現できるのがメリットですが、今回は動作検証メインなので1台で実施することご容赦ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/c2b28b95-f4cf-5ab0-5f50-94c0a3a39603.png)


①AWS EC2上にSDK(=Boto3)をセットアップ
②EC2からboto3を利用してSQSにメッセージを送受信
③OCI Compute上にSDK for pythonをセットアップ
④ComputeからSDK for pythonを利用してOCI Queueにメッセージを送受信

# ①AWS EC2上にSDK(=Boto3)をセットアップ
今回、EC2の作成手順は割愛させていただき、ssh接続した状態を前提とさせていただきます。
※OSはAmazonLinux2 / インスタンスタイプはt3.smallを利用

gitのインストール
```
sudo yum install git
```
pythonのバージョン管理をしてくれるツールpyenvをインストール
```
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```
.bashrcを編集
```
vi ~/.bashrc

<下記を追記>
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
```
編集内容を反映
```
source ~/.bashrc
```
Pathが通ったか確認
```
pyenv --version
```
インストールできるバージョンを確認
```
pyenv install -l
```
pyenvのインストールに必要なものを事前にインストール
```
sudo yum -y install gcc openssl11 openssl11-devel bzip2-devel ncurses-devel libffi-devel readline-devel sqlite-devel.x86_64 xz-devel
```
インストールしたいバージョンを指定(ここで数分かかります)
```
pyenv install 3.12.0
```
バージョン確認
```
pyenv versions
```
デフォルトバージョンの指定
```
pyenv global 3.12.0
```
pythonコマンドのバージョンを確認 ここで3.12.0になっていればOK
```
python -V
```
pipのUpgrade
```
pip install --upgrade pip
```
boto3インストール
```
pip install boto3
```
AWSCLIのインストール
```
pip install awscli
```
AWSコンソール画面 利用ユーザのIAMの"セキュリティ認証"タブよりアクセスキー/シークレットアクセスキーを取得します
※メモしておいてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/c221d246-282a-f396-c605-a2f6b2f46c2c.png)
aws configureの設定
```
aws configure

<実行イメージ>
AWS Access Key ID [None]: <アクセスキーを入力>
AWS Secret Access Key [None]: <シークレットアクセスキーを入力>
Default region name [None]: ap-northeast-1
Default output format [None]:
```

これで実行環境の準備は完了です

# ②EC2からboto3を利用してSQSにメッセージを送受信
## ②-1 キューの作成
AWSコンソール上でSQSにアクセスし、キューを作成します
標準キューを選択、任意のキュー名を入力し、他はすべてデフォルト値を利用しています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/304e45ad-21df-3326-8e6d-d19bda5e8f01.png)

キューの作成後、エンドポイントのURLをメモしておきます
こちらはキューの送受信の検証で利用します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/660afabf-7d2c-7e32-15b4-55c9b0ce3f94.png)

## ②-2 SQSにメッセージを送信	
先ほどセットアップしたEC2にssh接続し/home/ec2-userにて以下送信用のpythonプログラムを作成します
なお、コードについてはこちらを参考にさせていただきました。ありがとうございます。

https://qiita.com/sugimount-a/items/05cd853e381e6266dbbd

```
vi send-sqs.py
```
```python
import boto3

name = '作成したSQSの名称'
sqs = boto3.resource('sqs')
try:
    queue = sqs.get_queue_by_name(QueueName=name)
except:
    queue = sqs.create_queue(QueueName=name)

msg_num = 3
msg_list = [{'Id' : '{}'.format(i+1), 'MessageBody' : 'order_{}'.format(i+1)} for i in range(msg_num)]
response = queue.send_messages(Entries=msg_list)
print(response)
```
作成したPythonプログラムを実行します
```
python send-sqs.py
```
以下を実行してAWSのコンソール画面を確認します
メッセージを送受信をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/e4af35a3-cac6-9094-e19e-918807c35b70.png)

キューが入ってることが確認できました
実際に中身を確認すると想定通りのメッセージが入っていました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/12a2fbc7-c7a0-2022-ac7f-078cf9510c99.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/bbb81edd-7eab-bd84-9eef-5e6105451094.png)

## ②-3 SQSからメッセージを受信
同様に/home/user/ec2-userにて以下受信用のpythonプログラムを作成します
```
vi get-sqs.py
```
```python
import boto3

name = 'test-queue'
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName=name)
while True:
    msg_list = queue.receive_messages(MaxNumberOfMessages=10)
    if msg_list:
        for message in msg_list:
            print(message.body)
            message.delete()
    else:
        break
```
作成したPythonプログラムを実行して、キューの取り出しと同時に削除を実施します
```
python get-sqs.py

<実行結果イメージ>
[ec2-user@ip-10-1-2-232 ~]$ python get-sqs.py
order_1
order_2
order_3
```

AWSコンソール画面を確認するとキューが削除されていることが確認できます
※画面が変わっていない場合はブラウザの更新を実施してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/a56009aa-61d6-7312-f318-5be4be20daeb.png)

非常に簡易的ですが、これでAWS SQSの最も基本的な実装であるキューの送受信&削除が確認できました！

# ③OCI Compute上にSDK for pythonをセットアップ
次にAWSで実施した動作をOCIでも同様にできるか試してみます。
今回、Computeの作成手順は割愛させていただき、ssh接続した状態を前提とさせていただきます。
※OSはOracleLinux8 / シェイプはE4.Flex(1OCPU/8GBメモリ)を利用

gitのインストール
```
sudo yum install git
```
pythonのバージョン管理をしてくれるツールpyenvをインストール
```
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```
.bashrcを編集
```
vi ~/.bashrc

<下記を追記>
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
```
編集内容を反映
```
source ~/.bashrc
```
Pathが通ったか確認
```
pyenv --version
```
インストールできるバージョンを確認
```
pyenv install -l
```
pyenvのインストールに必要なものを事前にインストール
```
sudo yum -y install gcc bzip2-devel ncurses-devel libffi-devel readline-devel sqlite-devel.x86_64 xz-devel
```
インストールしたいバージョンを指定(ここで数分かかります)
```
pyenv install 3.12.0
```
バージョン確認
```
pyenv versions
```
デフォルトバージョンの指定
```
pyenv global 3.12.0
```
pythonコマンドのバージョンを確認 ここで3.12.0になっていればOK
```
python -V
```
pipのUpgrade
```
pip install --upgrade pip
```
OCI CLIとPython SDKのインストール
```
pip install oci-cli
pip install oci
```

configのセットアップ
今回はこちらの記事を参考にさせていただきました。ありがとうございます。

https://cloudii.jp/news/blog/oracle-cloud/2018-08-01-104038/

※事前に「UserのOCID」「tenancyのOCID」をメモしておきます
```
oci setup config
-------------------------

Enter a location for your config [/home/opc/.oci/config]:Enter押下
Enter a user OCID: UserのOCID入力
Enter a tenancy OCID: TenancyのOCIDを入力
Enter a region by index or name(e.g.
1: af-johannesburg-1, 2: ap-chiyoda-1, 3: ap-chuncheon-1, 4: ap-dcc-canberra-1, 5: ap-hyderabad-1,
6: ap-ibaraki-1, 7: ap-melbourne-1, 8: ap-mumbai-1, 9: ap-osaka-1, 10: ap-seoul-1,
11: ap-singapore-1, 12: ap-sydney-1, 13: ap-tokyo-1, 14: ca-montreal-1, 15: ca-toronto-1,
16: eu-amsterdam-1, 17: eu-dcc-dublin-1, 18: eu-dcc-dublin-2, 19: eu-dcc-milan-1, 20: eu-dcc-milan-2,
21: eu-dcc-rating-1, 22: eu-dcc-rating-2, 23: eu-dcc-zurich-1, 24: eu-frankfurt-1, 25: eu-frankfurt-2,
26: eu-jovanovac-1, 27: eu-madrid-1, 28: eu-madrid-2, 29: eu-marseille-1, 30: eu-milan-1,
31: eu-paris-1, 32: eu-stockholm-1, 33: eu-zurich-1, 34: il-jerusalem-1, 35: me-abudhabi-1,
36: me-dcc-muscat-1, 37: me-dubai-1, 38: me-jeddah-1, 39: mx-monterrey-1, 40: mx-queretaro-1,
41: sa-bogota-1, 42: sa-santiago-1, 43: sa-saopaulo-1, 44: sa-vinhedo-1, 45: uk-cardiff-1,
46: uk-gov-cardiff-1, 47: uk-gov-london-1, 48: uk-london-1, 49: us-ashburn-1, 50: us-chicago-1,
51: us-gov-ashburn-1, 52: us-gov-chicago-1, 53: us-gov-phoenix-1, 54: us-langley-1, 55: us-luke-1,
56: us-phoenix-1, 57: us-saltlake-2, 58: us-sanjose-1): 任意のリージョン選択（東京だと13）
Do you want to generate a new API Signing RSA key pair? (If you decline you will be asked to supply the path to an existing key.) [Y/n]: y
Enter a directory for your keys to be created [/home/opc/.oci]:Enter押下
Enter a name for your key [oci_api_key]:Enter押下
Public key written to: /home/opc/.oci/oci_api_key_public.pem
Enter a passphrase for your private key ("N/A" for no passphrase):パスワード入力
Repeat for confirmation:パスワード再入力
Private key written to: /home/opc/.oci/oci_api_key.pem
Fingerprint: d3:38:be:2d:f3:c3:31:2a:c1:dd:12:0d:7c:1e:b4:a0
Do you want to write your passphrase to the config file? (If not, you will need to enter it when prompted each time you run an oci command) [y/N]: y
Config written to /home/opc/.oci/config
```

APIキーの確認し、ローカル環境にメモしておきます

```
cd ~/.oci/
vi oci_api_key_public.pem

※表示されたパブリックキーをローカル環境にメモ※
```

OCI Webコンソール画面にて自身のユーザ詳細画面にアクセスします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/28ba9f0e-b866-bb99-3be9-1ca2624e9fbe.png)

APIキーの追加より、"公開キーの貼り付け"にて先ほど確認した文字列を貼り付け
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/edd1f305-720c-8395-f5e8-bc740ea15548.png)
これにてOCI側のセットアップは完了です

# ④ComputeからSDK for pythonを利用してOCI Queueにメッセージを送受信
## ④-1 OCI Queueの作成
OCIキューサービスにアクセスし、キューを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/2bd60ae9-c2d8-e707-517d-01f41bcb7f54.png)

名前を任意のものを入力し、その他はデフォルトでキューを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/013570d7-5893-8075-f497-06d7cd385b44.png)

作成後、"キューのOCID"と"メッセージ・エンドポイント"をメモしておきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/c0c3532f-f9cb-ef11-234c-f603a1555348.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/72471ea8-dcf2-b445-958b-5a77085516c2.png)

## ④-2 OCI Queueにメッセージを送信
先ほどセットアップしたComputeにssh接続し/home/opcにて以下送信用のpythonプログラムを作成します

```
vi send-queue.py
```
```python
import oci

from base64 import b64encode

ociMessageEndpoint = "キューのエンドポイント"
ociQueueOcid = "キューのOCID"
ociConfigFilePath = "/home/opc/.oci/config"  
ociProfileName = "DEFAULT"  

def produce_messages(client, queue_id):
    message_list = []
    for i in range(3):
        value = "Order" + str(i)
        message_list.append(oci.queue.models.PutMessagesDetailsEntry(content=value))

    print("Publishing {} messages to the stream {} ".format(len(message_list), queue_id))
    print(message_list)
    messages = oci.queue.models.PutMessagesDetails(messages=message_list)
    put_message_result = client.put_messages(queue_id, messages)

config = oci.config.from_file(ociConfigFilePath, ociProfileName)
queue_client = oci.queue.QueueClient(config, service_endpoint=ociMessageEndpoint)

produce_messages(queue_client, ociQueueOcid)
```

作成したPythonプログラムを実行してメッセージをキューに送信
```
sudo python send-queue.py
-------------------------
<実行イメージ>
[opc@instance-20231209-1624 ~]$ sudo python send-queue.py
Publishing 3 messages to the stream ocid1.queue.oc1.ap-tokyo-1.amaaaaaassl65iqajafdudfxdt7upfr2f2g7mpoi44u5hpfukihg6cyq6sja
[{
  "content": "OrderNumber 0"
}, {
  "content": "OrderNumber 1"
}, {
  "content": "OrderNumber 2"
}]
```
メッセージのポーリングをクリックすることで、OCIのWebコンソール画面でも確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/6b5aab7c-54d5-54a9-5f15-f99a4672dfc5.png)

## ④-3 OCI Queueからメッセージを受信
次にキューからの受信用のPythonプログラムを作成します
```
vi get-queue.py
```
```py
import oci

from base64 import b64decode

ociMessageEndpoint = "キューのエンドポイント"
ociQueueOcid = "キューのOCID"
ociConfigFilePath = "/home/opc/.oci/config"
ociProfileName = "DEFAULT"

config = oci.config.from_file(ociConfigFilePath, ociProfileName)
queue_client = oci.queue.QueueClient(config, service_endpoint=ociMessageEndpoint)

get_messages_response = queue_client.get_messages(ociQueueOcid,limit=10)
get_message_list = get_messages_response.data.messages
# Get the data from response

for get_message in get_message_list:
 receipt=print(get_message.content)

receipt = get_message_list[0].receipt
delete_message_entry_list = [oci.queue.models.DeleteMessagesDetailsEntry(receipt=message.receipt) for message in get_message_list]
delete_details = oci.queue.models.DeleteMessagesDetails(entries=delete_message_entry_list)
batch_delete_message_response = queue_client.delete_messages(queue_id=ociQueueOcid, delete_messages_details=delete_details)
```

作成したPythonプログラムを実行してキューの受信&削除を実施します

```
python get-queue.py
-------------------------

<実行イメージ>
[opc@instance-20231209-1624 ~]$ python get-queue.py
OrderNumber 0
OrderNumber 1
OrderNumber 2
```

OCIWebコンソール画面でもキューがないことが確認できました
（表示が変わらない場合は、ブラウザの更新をしてください)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471135/541194d9-f163-58e4-2af9-21f4c0d9dd36.png)

基本的な動作だけになりますが、こちらでOCI Queueでも問題なく、AWS SQSと同様の動作ができることを確認しました！

# 最後に
AWS SQSとOCI Queueを両方触ってみましたが、基本的な動作であれば全く問題なさそうでした。
また、自分自身、キューサービスのイメージは分かっていたものの、実際触ったことがなかったので良い勉強になりました。
疎結合なシステムを構築する際に必要になるケースが多いサービスですのでまだ触ったことがない方がいらっしゃればこの記事をきっかけに触っていただけると大変嬉しいです。