概要
AWS Lambdaを使ってOCIリソースのAPI操作(Computeの開始操作)を行いました。
サーバレスにすることによってEventbridge等を使った時刻起動やイベント起動等でOCIリソース操作可能になります。
また、OCI資格情報をSecret Managerを使用することによって資格情報をコード外に保存しています。
EC2を使った操作はこちらを参照ください。
AWS環境からOCIリソースのAPI操作(Secrets Managerを使用)
(トークンベース認証方法から通常のAPI認証に変更しました)
構成
設定手順
-
OCI資格情報をSecrets Managerへ配置
以下の手順についてはAWS環境からOCIリソースのAPI操作(Secrets Managerを使用)を参照下さい。
-OCI資格情報取得
-OCI Compute OCID
-Secrets Managerに資格情報を配置するための準備
-Secrets Managerに資格情報を配置 -
Container Image作成
Lambdaは250MBまでのサイズ制限があり、OCIの外部モジュールだけで250MBを超えます。
そのため、EC2にてContainer Imageを作成、ECRにPushして使用します。- EC2にSecret Managerアクセス権限追加
操作するEC2にアタッチされたIAMロールに対してポリシー"SecretsManagerReadWrite"を追加します。この作業は必須ではありませんが、ECR登録前にContainer Imageのテストを行う場合は必要です。 - EC2内に以下のディレクトリ構造でファイルを配置します。
- EC2にSecret Managerアクセス権限追加
work directory
├── Dockerfile_ocivmstart
└── app
├── app.py
└── requirements.txt
boto3
oci
import oci
import boto3
from botocore.exceptions import ClientError
import ast
# Secretmanager
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name='ap-northeast-1'
)
def handler(event, context):
# Resource Request
instance_ocid = event['instance_ocid']
instance_action = event['instance_action']
#OCI config
get_secret_value_response = client.get_secret_value(
SecretId= 'OCIuser'
)
secret_data = get_secret_value_response['SecretString']
secret = ast.literal_eval(secret_data)
fingerprint = secret['fingerprint']
oci_api_key = secret['oci_api_key']
user = secret['user']
tenancy = secret['tenancy']
region = secret['region']
pem_prefix = '-----BEGIN RSA PRIVATE KEY-----\n'
pem_suffix = '\n-----END RSA PRIVATE KEY-----'
key_content = '{}{}{}'.format(pem_prefix, oci_api_key, pem_suffix)
config = {
"user": user,
"key_content": key_content,
"fingerprint": fingerprint,
"tenancy": tenancy,
"region": region
}
oci.config.validate_config(config)
# VM action
core_client = oci.core.ComputeClient(config, service_endpoint='https://iaas.【リージョン】.oraclecloud.com')
instance_action_response = core_client.instance_action(
instance_id=instance_ocid,
action=instance_action)
print(instance_action_response.data)
参考
Docs » API Reference » Core Services » ComputeClient
oci-python-sdk/examples/configuration_example.py
FROM public.ecr.aws/lambda/python:3.8
COPY app/requirements.txt ${LAMBDA_TASK_ROOT}
RUN pip install -r requirements.txt
COPY app/app.py ${LAMBDA_TASK_ROOT}
CMD [ "app.handler" ]
準備できたらイメージ作成と実行を行います。
docker build -t ocivmstart . -f Dockerfile_ocivmstart
docker run --rm -p 9000:8080 ocivmstart
確認コマンドを実行して、OCI Computeが起動できたら成功です
curl -d '{"instance_ocid":"【ComputeのOCID】","instance_action":"START"}' http://localhost:9000/2015-03-31/functions/function/invocations
参考:
Lambda コンテナイメージをローカルでテストする
- 作成したContainer ImageをECRにPush
AWSコンソールからAmazon>リポジトリでリポジトリを作成を押下
リポジトリ名を入力してリポジトリを作成を押下
作成後プッシュコマンドの表示を押下
表示されたコマンドをEC2で実施してContainer ImageをPush
- Lambda作成
作成前にLambdaにアタッチするロールを作成します。
IAM>ロールの作成を押下
以下のポリシーを含むロールを作成
AmazonEC2ContainerRegistryReadOnly
AWSLambdaBasicExecutionRole
SecretsManagerReadWrite
Lambda>関数に移動し、関数の作成を押下
コンテナイメージを選択し、コンテナの場所を指定します。
また、実行ロールを先ほど作成したロールを指定して関数の作成を押下します。
作成完了しましたら基本設定の編集でタイムアウトを3秒から長い時間に変更します。
実行結果
正常に実行できるかLambdaのテスト機能を使って確認します。
イベントJSONに以下を入力してテストボタンを押下します。
{
"instance_ocid":"【ComputeのOCID】",
"instance_action":"START"
}
OCIコンソールも確認して対象Computeが正常にスタートしたことを確認します。
Lambdaテスト実行前
Lambdaテスト実行後
Computeスタートしました。
サンプル2
OCIのVM以外にAutonomousDBやMySQL Database Serviceのリソースを開始/停止を行うサンプルです。
work directory
├── Dockerfile_ocivmstart
└── app
├── app.py
└── requirements.txt
boto3
oci
import oci
import boto3
from botocore.exceptions import ClientError
import ast
# Secretmanager
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name='ap-northeast-1'
)
def handler(event, context):
# Resource Request
instance_type = event['instance_type']
instance_ocid = event['instance_ocid']
instance_action = event['instance_action']
#OCI config
get_secret_value_response = client.get_secret_value(
SecretId= 'OCIuser'
)
secret_data = get_secret_value_response['SecretString']
secret = ast.literal_eval(secret_data)
fingerprint = secret['fingerprint']
oci_api_key = secret['oci_api_key']
user = secret['user']
tenancy = secret['tenancy']
region = secret['region']
pem_prefix = '-----BEGIN RSA PRIVATE KEY-----\n'
pem_suffix = '\n-----END RSA PRIVATE KEY-----'
key_content = '{}{}{}'.format(pem_prefix, oci_api_key, pem_suffix)
config = {
"user": user,
"key_content": key_content,
"fingerprint": fingerprint,
"tenancy": tenancy,
"region": region
}
oci.config.validate_config(config)
# VM action
if instance_type == 'VM':
core_client = oci.core.ComputeClient(config, service_endpoint='https://iaas.【リージョン】.oraclecloud.com')
if instance_action == 'START':
get_instance_response = core_client.get_instance(instance_ocid)
if get_instance_response.data.lifecycle_state == 'STOPPED':
instance_action_response = core_client.instance_action(
instance_id=instance_ocid,
action=instance_action)
print(instance_action_response.data)
else:
print('VM START aborted')
elif instance_action == 'STOP':
get_instance_response = core_client.get_instance(instance_ocid)
if get_instance_response.data.lifecycle_state == 'RUNNING':
instance_action_response = core_client.instance_action(
instance_id=instance_ocid,
action=instance_action)
print(instance_action_response.data)
else:
print('VM STOP aborted')
# ADB action
elif instance_type == 'ADB':
database_client = oci.database.DatabaseClient(config, service_endpoint='https://database.【リージョン】.oraclecloud.com')
if instance_action == 'START':
get_autonomous_database_response = database_client.get_autonomous_database(
autonomous_database_id=instance_ocid)
if get_autonomous_database_response.data.lifecycle_state == 'STOPPED':
start_autonomous_database_response = database_client.start_autonomous_database(
autonomous_database_id=instance_ocid)
print(start_autonomous_database_response.data)
else:
print('ADB START aborted')
elif instance_action == 'STOP':
get_autonomous_database_response = database_client.get_autonomous_database(
autonomous_database_id=instance_ocid)
if get_autonomous_database_response.data.lifecycle_state == 'AVAILABLE':
stop_autonomous_database_response = database_client.stop_autonomous_database(
autonomous_database_id=instance_ocid)
print(stop_autonomous_database_response.data)
else:
print('ADB STOP aborted')
else:
pass
# MDS action
elif instance_type == 'MDS':
mysql_client = oci.mysql.DbSystemClient(config, service_endpoint='https://mysql.【リージョン】.ocp.oraclecloud.com')
if instance_action == 'START':
get_db_system_response = mysql_client.get_db_system(
db_system_id=instance_ocid)
if get_db_system_response.data.lifecycle_state == 'INACTIVE':
start_db_system_response = mysql_client.start_db_system(
db_system_id=instance_ocid)
print(start_db_system_response.headers)
else:
print('MDS START aborted')
elif instance_action == 'STOP':
get_db_system_response = mysql_client.get_db_system(
db_system_id=instance_ocid)
if get_db_system_response.data.lifecycle_state == 'ACTIVE':
stop_db_system_response = mysql_client.stop_db_system(
db_system_id=instance_ocid,
stop_db_system_details=oci.mysql.models.StopDbSystemDetails(
shutdown_type="IMMEDIATE")
)
print(stop_db_system_response.headers)
else:
print('MDS STOP aborted')
else:
pass
# Unexpected Resource action
else:
pass
イベントJSONは以下のとおりとなります。
- instance_type : VM/ADB/MDS
- instance_ocid : リソースのOCID
- instance_action : START/STOP
ADBを開始する場合
{
"instance_type":"ADB",
"instance_ocid":"【OCID】",
"instance_action":"START"
}