Oracle Cloud Infrastructure を Terraform 管理できるようにするまで
schnell と申します. 現在 SaaS 系企業で MLOps を推進するエンジニアとして勤務しています.
本記事では、自主学習の一環として取り組んでいる Oracle Cloud Infrastructure(以下、OCI)の環境を Terraform で管理するための手順について、備忘録として共有いたします.
OCI は AWS や GCP といった有名 IaaS サービスと比べると利用社が少なく地味ですが無料枠が非常に充実しており
例えば、AWSのEC2に相当するコンピューティングリソースでは Arm 版を選択することで RAM 24GB、4 OPCU のインスタンスが無料で利用できます.
このリソースは最大 4 つの VM に分割可能で、無料枠の範疇で RAM 6GB、1 OCPU のインスタンスを4台作成することができ, 簡易的な kubernetes クラスタでさえも運用することが十分に可能なスペックとなっています.
尚、本記事ではおそらく最難関であろう OCI にサインアップするというプロセスについては省略します。
実行環境について
macOS Sonoma で実行確認をしております.
❯ sw_vers
ProductName: macOS
ProductVersion: 14.6.1
BuildVersion: 23G93
terraform は 1.10.4 を利用します.
❯ terraform -v
Terraform v1.10.4
on darwin_arm64
API キーの追加
プログラム (terraform) から OCI にアクセスするために API キーの登録を行います.
以下のコマンドをを実行することで、API キーとして登録する RSA キーを作成して、公開鍵をクリップボードにコピーできます.
mkdir ~/.oci && cd ~/.oci
openssl genrsa -out oci_rsa.pem 2048
chmod 600 oci_rsa.pem
openssl rsa -pubout -in oci_rsa.pem -out oci_rsa_pub.pem
cat oci_rsa_pub.pem | pbcopy
次にコンソールにログインして API キーの登録を行います.
こちらのリンクに飛んでいただき、「API キーの追加」->「公開キーの貼付け」を選択して先ほどクリップボードにコピーした公開鍵を追加してください.
以上で API キーの追加は完了です.
terraform の oci provider 設定に必要な情報を集める
OCI のコンソールから以下の情報を集めます
-
Tenancy OCID
ここから取得してください.
ocid1.tenancy.oc1
から始まります. -
User OCID
ここから取得してください.
ocid1.user.oc1
から始まります. -
Fingerprint
ここから取得してください.
xx:xx:xx...xx
のようなフォーマットです. -
Region
東京リージョンならap-tokyo-1
、大阪リージョンならap-osaka-1
です.
terraform ファイルを実行する環境から以下の情報を取得します.
- Private Key Path
先ほど作成した秘密鍵のパスをメモしてください、記事の通りに実行した場合は~/.oci/oci_rsa.pem
となります.
terraform のプロバイダー設定
先ほど取得した情報を使って oci provider の設定をします.
設定情報を保存する ~/.oci/config
を作成して以下のように記載してください
[DEFAULT]
tenancy_ocid="<tenancy-ocid>"
user_ocid="<user-ocid>"
private_key_path="<rsa-private-key-path>"
fingerprint="<fingerprint>"
region="<region-identifier>"
次に以下のような hcl コードを作成してください.
terraform {
required_providers {
oci = {
source = "oracle/oci"
}
}
}
provider "oci" {
config_file_profile = "DEFAULT"
}
terraform init
コマンドを実行して以下のように表示されたら設定完了です.
❯ terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of oracle/oci from the dependency lock file
- Using previously-installed oracle/oci v4.123.0
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
可用性ドメインを出力してみる
可用性ドメインを取得するためのシンプルな hcl を作成しました.
terraform {
required_providers {
oci = {
source = "oracle/oci"
}
}
}
provider "oci" {
config_file_profile = "DEFAULT"
}
locals {
oci_config_content = file("~/.oci/config")
tenancy_ocid = regex("(?m)^tenancy\\s*=\\s*(.*)$", local.oci_config_content)[0]
}
data "oci_identity_availability_domains" "ads" {
compartment_id = local.tenancy_ocid
}
output "names" {
value = [for ad in data.oci_identity_availability_domains.ads.availability_domains : ad.name]
}
実行結果
❯ terraform apply
data.oci_identity_availability_domains.ads: Reading...
data.oci_identity_availability_domains.ads: Read complete after 0s [id=IdentityAvailabilityDomainsDataSource-1575237231]
Changes to Outputs:
+ names = [
+ "ewah:AP-OSAKA-1-AD-1",
]
You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
names = [
"ewah:AP-OSAKA-1-AD-1",
]
(おまけ) nginx サーバーをシンプルな構成でデプロイしてみる
最小限のシンプルな構成で nginx サーバーをデプロイしてみます.
iptables -I INPUT -p TCP --dport 80 -j ACCEPT
を実行している点がポイントで、OCI ではデフォルトで OS のファイアウォールが設定されているため明示的に許可する必要があります.
terraform apply
すると出力される URL にアクセスすると nignx サーバーにアクセスできることが確認できます.
また、ssh の設定もしているので ssh ubuntu@<ip addr> -i ~/.ssh/<key name>
でインスタンスに ssh で接続することもできます.
terraform ファイル
terraform {
required_providers {
oci = {
source = "oracle/oci"
}
}
}
provider "oci" {
config_file_profile = "DEFAULT"
}
locals {
oci_config_content = file("~/.oci/config")
tenancy_ocid = regex("(?m)^tenancy\\s*=\\s*(.*)$", local.oci_config_content)[0]
}
# コンパートメントを作成
resource "oci_identity_compartment" "this" {
compartment_id = local.tenancy_ocid
name = "terraform"
description = "Terraform compartment"
}
# 可用性ドメインを取得
data "oci_identity_availability_domains" "this" {
compartment_id = local.tenancy_ocid
}
# VCN を作成
resource "oci_core_vcn" "this" {
cidr_block = "10.0.0.0/16"
compartment_id = oci_identity_compartment.this.id
display_name = "nginx-vcn"
}
# IGW を作成
resource "oci_core_internet_gateway" "this" {
compartment_id = oci_identity_compartment.this.id
display_name = "nginx-igw"
vcn_id = oci_core_vcn.this.id
}
# ルートテーブルを作成
resource "oci_core_route_table" "this" {
compartment_id = oci_identity_compartment.this.id
vcn_id = oci_core_vcn.this.id
display_name = "nginx-rt"
route_rules {
destination = "0.0.0.0/0"
network_entity_id = oci_core_internet_gateway.this.id
}
}
# サブネットを作成
resource "oci_core_subnet" "this" {
cidr_block = "10.0.1.0/24"
compartment_id = oci_identity_compartment.this.id
vcn_id = oci_core_vcn.this.id
route_table_id = oci_core_route_table.this.id
security_list_ids = [oci_core_security_list.nginx_security_list.id]
display_name = "nginx-subnet"
}
# セキュリティリストの更新
resource "oci_core_security_list" "nginx_security_list" {
compartment_id = oci_identity_compartment.this.id
vcn_id = oci_core_vcn.this.id
display_name = "nginx-security-list"
egress_security_rules {
destination = "0.0.0.0/0"
protocol = "all"
}
ingress_security_rules {
protocol = "6" # TCP
source = "0.0.0.0/0"
tcp_options {
max = "22"
min = "22"
}
}
ingress_security_rules {
protocol = "6" # TCP
source = "0.0.0.0/0"
tcp_options {
max = "80"
min = "80"
}
}
}
# Compute インスタンスを作成
resource "oci_core_instance" "nginx_instance" {
availability_domain = data.oci_identity_availability_domains.this.availability_domains[0].name
compartment_id = oci_identity_compartment.this.id
shape = "VM.Standard.A1.Flex"
shape_config {
ocpus = 1
memory_in_gbs = 6
}
create_vnic_details {
subnet_id = oci_core_subnet.this.id
assign_public_ip = true
}
source_details {
source_type = "image"
source_id = data.oci_core_images.ubuntu_image.images[0].id
}
metadata = {
ssh_authorized_keys = file("~/.ssh/oci-nginx.pub") # 公開鍵は事前に作成しておく
user_data = base64encode(<<-EOF
#!/bin/bash
apt-get update
apt-get install -y nginx
systemctl start nginx
systemctl enable nginx
iptables -I INPUT -p TCP --dport 80 -j ACCEPT
EOF
)
}
}
data "oci_core_images" "ubuntu_image" {
compartment_id = oci_identity_compartment.this.id
operating_system = "Canonical Ubuntu"
operating_system_version = "24.04"
shape = "VM.Standard.A1.Flex"
}
output "public_ip" {
value = "http://${oci_core_instance.nginx_instance.public_ip}"
}
Discussion