Oracle Cloudのリソース・マネージャを使用したサーバーとデータベースの構築

# はじめに

最近、Oracle Masterの学習をするためにOracle Universityを見ていたところ、日本語版のOracle Cloud講義動画を発見しました。試しに「Oracle Masterの勉強したいし、ほんの少しだけ」の気持ちで視聴してみると、非常に面白く、自分でも何か作ってみたいという気持ちになりました。

OCIの講義動画やブログを読む中で、「OCIではリソース・マネージャという機能で、コンソールからTerraformを実行できる！」ということを知り、以下のような環境を作成しました。

本記事では、以下の構成の構築方法（tfファイル）について記載します。

![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/4d057dc7-9476-5d9b-4748-496be8484907.png)

※ 本当はPrivate subnet内のインスタンスからAutonomous Database に繋ぎたかったのですが、そうするとNAT Gatewayが必要($33/月くらい)みたいで、Bastionからの接続で妥協しました。


### 構築方法

開発者サービス > リソース・マネージャ > スタック >スタックの作成
から、ドラッグアンドドロップでフォルダを読み込めます。zipにしないでもフォルダで読み込めるのは楽ですね。

![リソースマネージャー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/2f1b1ced-2e7d-7a10-f20c-b9ea40511126.png)

ドラッグアンドドロップしたフォルダの構成は以下になります。
Terraformのファイルをそのまま読み込めちゃいます。
```
OCI_TF
├── provider.tf
├── vars.tf
├── network.tf
├── security.tf
├── compute.tf
├── database.tf
├── storage.tf
```


### 各 .tf ファイルの中身
ファイルの中身と作成した時の詰まったところなどのポイントを記載してます。

#### provider.tf
```provider.tf
provider "oci" {
  region = "ap-tokyo-1"
}
```

#### vars.tf

・sshキーは、私のPCのPowershellで、以下のコマンドで生成した、.pubキーを入れています。
```ssh-keygen -t rsa -b 2048 -f ~/.ssh/oci_key```

```vars.tf
variable "compartment_id" {
  description = "The OCID of the compartment within which to create resources."
  type        = string
  default     = "ocid1.compartment.oc1..aaaaaaaaXXXXXXX"
}

variable "ssh_public_key" {
  description = "Public SSH key to be used for the compute instance."
  type        = string
  default     = "ssh-rsa AAAAXXXXXXXXXXXXX"  # ssh-keygenで作成
}

variable "adb_admin_password" {
  description = "Admin password for the Oracle Autonomous Database."
  type        = string
  default     = "XXXXXX"  # DBのADMIN様のパスワード
  sensitive   = true
}

```

#### network.tf

```network.tf
# VCNの作成
resource "oci_core_vcn" "main" {
  compartment_id = var.compartment_id
  cidr_block     = "10.0.0.0/16"
  display_name   = "MainVCN"
  dns_label      = "myvcn"
}

resource "oci_core_internet_gateway" "my_igw" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main.id
  display_name   = "MyInternetGateway"
  enabled        = true
}

resource "oci_core_route_table" "public_route_table1" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main.id
  display_name   = "PublicRouteTable"

  route_rules {
    destination = "0.0.0.0/0"
    network_entity_id = oci_core_internet_gateway.my_igw.id
  }
}

# パブリックサブネット1の作成
resource "oci_core_subnet" "public_subnet1" {
  compartment_id      = var.compartment_id
  vcn_id              = oci_core_vcn.main.id
  cidr_block          = "10.0.1.0/24"
  display_name        = "PublicSubnet1"
  prohibit_public_ip_on_vnic = false
  route_table_id      = oci_core_route_table.public_route_table1.id
  dns_label      = "pub1"
}

# パブリックサブネット2の作成
resource "oci_core_subnet" "public_subnet2" {
  compartment_id      = var.compartment_id
  vcn_id              = oci_core_vcn.main.id
  cidr_block          = "10.0.2.0/24"
  display_name        = "PublicSubnet2"
  prohibit_public_ip_on_vnic = false
  dns_label      = "pub2"
}

# プライベートサブネット1の作成
resource "oci_core_subnet" "private_subnet1" {
  compartment_id      = var.compartment_id
  vcn_id              = oci_core_vcn.main.id
  cidr_block          = "10.0.3.0/24"
  display_name        = "PrivateSubnet1"
  prohibit_public_ip_on_vnic = true
  dns_label      = "priv1"
}

# プライベートサブネット2の作成
resource "oci_core_subnet" "private_subnet2" {
  compartment_id      = var.compartment_id
  vcn_id              = oci_core_vcn.main.id
  cidr_block          = "10.0.4.0/24"
  display_name        = "PrivateSubnet2"
  prohibit_public_ip_on_vnic = true
  dns_label      = "priv2"
}
```

#### security.tf
・sourceのIPアドレスは、私の端末が外に抜けるグローバルIPにしています。
・protocol は、ICMPが1,TCPが6,UDPが17のプロトコル番号での指定でした。

```security.tf
# Bastionホスト用セキュリティグループの作成
resource "oci_core_network_security_group" "nsg_bastion" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main.id
  display_name   = "BastionNSG"
}

resource "oci_core_network_security_group_security_rule" "nsg_bastion_ingress" {
  network_security_group_id = oci_core_network_security_group.nsg_bastion.id
  direction                 = "INGRESS"
  protocol                  = "6"  # TCP

  source      = "XXX.XXX.XXX.XXX/32"
  tcp_options {
    destination_port_range {
      min = 22
      max = 22
    }
  }
}
resource "oci_core_network_security_group_security_rule" "nsg_bastion_egress" {
  network_security_group_id = oci_core_network_security_group.nsg_bastion.id
  direction                 = "EGRESS"
  protocol                  = "all"  # 全てのプロトコル

  destination = "0.0.0.0/0"
}

# Computeインスタンス用セキュリティグループの作成
resource "oci_core_network_security_group" "nsg_compute" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main.id
  display_name   = "ComputeNSG"
}

resource "oci_core_network_security_group_security_rule" "nsg_compute_ingress" {
  network_security_group_id = oci_core_network_security_group.nsg_compute.id
  direction                 = "INGRESS"
  protocol                  = "6"  # TCP

  source = "10.0.1.0/24"
  tcp_options {
    destination_port_range {
      min = 22
      max = 22
    }
  }
}

resource "oci_core_network_security_group_security_rule" "nsg_compute_egress" {
  network_security_group_id = oci_core_network_security_group.nsg_compute.id
  direction                 = "EGRESS"
  protocol                  = "all"  # 全てのプロトコル

  destination = "0.0.0.0/0"
}

```
#### compute.tf (一番詰まった)

・イメージファイルのソースIDは、以下URLから調べました。SQL Plusがデフォルトで入っている方が良かったので、Oracle Linux Cloud Developerのイメージを選びました。</br>
https://docs.oracle.com/en-us/iaas/images/
・VM.Standard.A1.FlexのインスタンスタイプはARMしか選べなかったのが少し詰まったポイントでした。
・availability_domainの最初の4桁は、個別に割り振られるもので、ネットのブログなどからそのまま引っ張ってくるとエラーになりました。</br>
　正しい調べ方かわからないのですが、「インスタンス・コンピュート」 > 「インスタンス」 > 「インスタンスの作成」 からの配置の編集ボタンをクリックして確認しました。
・ケチって、1CPU,1GBのサイズにしたら、繋げたり繋げなかったり不安定でした。
・リソースマネージャーのデプロイが完了しても少し時間をおかないと接続できませんでした。

```compute.tf
# Bastionホストの作成
resource "oci_core_instance" "bastion" {
  compartment_id      = var.compartment_id
  availability_domain = "XXXX:AP-TOKYO-1-AD-1"  # 可用性ドメインAWSで言うサブネット
  shape               = "VM.Standard.A1.Flex"
  display_name        = "BastionHost"

  create_vnic_details {
    subnet_id         = oci_core_subnet.public_subnet1.id
    assign_public_ip  = true
    nsg_ids           = [oci_core_network_security_group.nsg_bastion.id]
  }

  shape_config {
    ocpus = 2
    memory_in_gbs = 8
  }

  metadata = {
    ssh_authorized_keys = var.ssh_public_key
  }

  source_details {
    source_type = "image"
    source_id    = "ocid1.image.oc1.ap-tokyo-1.aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}

# コンピュートインスタンスの作成
resource "oci_core_instance" "mytest_instance" {
  compartment_id      = var.compartment_id
  availability_domain = "XXXX:AP-TOKYO-1-AD-1"  # 可用性ドメインAWSで言うサブネット
  shape               = "VM.Standard.A1.Flex"
  display_name        = "MyTestInstance"

  create_vnic_details {
    subnet_id         = oci_core_subnet.private_subnet1.id
    assign_public_ip  = false
    nsg_ids           = [oci_core_network_security_group.nsg_compute.id]
  }

  shape_config {
    ocpus = 2
    memory_in_gbs = 8
  }

  metadata = {
    ssh_authorized_keys = var.ssh_public_key
  }


  source_details {
    source_type = "image"
    source_id    = "ocid1.image.oc1.ap-tokyo-1.aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}

```

#### database.tf
・構築した後のポイントというか作業なのですが、マネジメントコンソールから作成した、「MytestAutonomousDB」を選んで、そこから「データベース接続」からwalletファイルを落としました。繋ぎ方は、後述してます。
```database.tf
# Autonomous Databaseの作成
resource "oci_database_autonomous_database" "mytest_adb" {
  compartment_id           = var.compartment_id
  db_name                  = "mytestADB1"
  admin_password           = var.adb_admin_password
  display_name             = "MytestAutonomousDB"
  db_workload              = "OLTP"
  is_free_tier             = true
}
```

#### storage.tf
・インスタンスと同じですが、availability_domainの最初の4桁は、個別に割り振られるものです。
```storage.tf
# 50GBのブロックボリューム1を作成
resource "oci_core_volume" "mytest_volume1" {
  compartment_id      = var.compartment_id
  availability_domain = "XXXX:AP-TOKYO-1-AD-1"
  size_in_gbs         = 50
  display_name        = "MytestVolume1"
}

# 50GBのブロックボリューム2を作成
resource "oci_core_volume" "mytest_volume2" {
  compartment_id      = var.compartment_id
  availability_domain = "XXXX:AP-TOKYO-1-AD-1"
  size_in_gbs         = 50
  display_name        = "MytestVolume2"
}

# ボリューム1をコンピュートインスタンスにアタッチ
resource "oci_core_volume_attachment" "mytest_volume_attachment1" {
  instance_id = oci_core_instance.bastion.id
  volume_id   = oci_core_volume.mytest_volume1.id
  attachment_type = "paravirtualized"
}

# ボリューム2をコンピュートインスタンスにアタッチ
resource "oci_core_volume_attachment" "mytest_volume_attachment2" {
  instance_id = oci_core_instance.mytest_instance.id
  volume_id   = oci_core_volume.mytest_volume2.id
  attachment_type = "paravirtualized"
}
```

### 接続確認
以下のように、構築した、インスタンス×2とAutonomousDBに接続確認しており、AutonomousDBはコンソールから落とした、walletを使って接続します。

```
[opc@bastionhost tmp]$ chmod 400 /tmp/private-key.pem #SSH-SCPで/tmpにpemをあげてます。
[opc@bastionhost tmp]$ ssh -i /tmp/private-key.pem opc@10.0.3.102 #プライベートサブネットのインスタンスに接続できることを確認
[opc@mytestinstance ~]$ exit
logout
Connection to 10.0.3.102 closed.
[opc@bastionhost tmp]$
[opc@bastionhost tmp]$ mkdir -p /home/opc/wallet
[opc@bastionhost tmp]$ unzip /tmp/Wallet_mytestADB1.zip -d /home/opc/wallet
[opc@bastionhost tmp]$ export TNS_ADMIN=/home/opc/wallet
[opc@bastionhost tmp]$ vi /home/opc/wallet/sqlnet.ora　#WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY= /home/opc/wallet)))　に変更

[opc@bastionhost tmp]$ sqlplus ADMIN@mytestadb1_medium
SQL*Plus: Release 19.0.0.0.0 - Production on Sat Jun 15 09:58:48 2024
Version 19.10.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.

Enter password:

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.24.0.1.0

SQL> show user
USER is "ADMIN"
SQL>
SQL> quit
```

# おわりに
Oracle Cloudを初めて触ってみたのですが、すごく楽しく、Oracle UniversityのOCIの講義動画もわかりやすいので、今後も触っていきたいと思います。
次は、Oracle Functionsの記事とかFoundations Associate (1Z0-1085-23-JPN)を受けた感想とかを書こうかなぁ～ と思っています。