OCI Terraform実践Vol1 コンパートメント/VCN/A1をコード化 0円IaC入門

目次

1. この記事について — OCI入門シリーズ全6巻をTerraformで再現する

OCI入門シリーズVol1・Vol3・Vol4で手動構築したコンパートメント/VCN/A1インスタンスをTerraformで再現するスコープ全体像
fig01: 本記事のスコープ全体像(コンパートメント/ネットワーク/A1インスタンスをTerraform化する範囲)
AWS実務者向け対応マップ(§3で詳述)

  • Resource Managerは、AWSのCloudFormationに近い、OCI組み込みのマネージドTerraform実行サービスです
  • Stackはスタックに、Resource Managerのジョブはスタックの更新/削除操作に、それぞれ役割として近い存在です
  • state管理は、oci backend(Object Storageへの保存)とS3 backendという2つの選択肢の発想で対比できます
  • ドリフト検出はどちらのサービスにもありますが、検出タイミングと実行単位に違いがあります
0円で完結するハンズオンの範囲(§2・§4で詳述)

  • Resource Manager自体のAlways Free上限(Stacks100・同時実行ジョブ2・プライベートエンドポイント1・テンプレート100)に十分収まる規模で設計しています
  • 作成するコンパートメント/VCN一式/A1インスタンスは、いずれもAlways Free対象リソースです
  • A1インスタンスのAlways Free上限は、月間1,500 OCPU時間・9,000 GB時間(常時稼働換算で約2 OCPU/12GB相当)です
  • 検証後はterraform destroy一発で作成したリソース一式を確実に片付けられます

1-1. 本記事のゴール

本記事を読み終えると、次の状態になることを目指しています。

  • OCI入門シリーズVol1で手動構築したコンパートメント、Vol3で手動構築したVCN・サブネット・ゲートウェイ・ルート表・NSG一式、Vol4で手動起動したAlways Free A1インスタンスを、Terraformコードとして再現できるようになります
  • Resource Manager(OCIのマネージドTerraform実行サービス)とローカルTerraform CLIという2つの実行方式を理解し、用途に応じて使い分けられるようになります
  • AWSでCloudFormationやTerraformを使ってきた経験を土台に、OCIのstate管理・ドリフト検出の考え方をAWSとの対比で説明できるようになります
  • 本記事のハンズオンをAlways Free枠の範囲内で完走し、terraform applyからterraform destroyまでを0円で一巡できます
  • OCI入門シリーズを一度手動で完走した経験と、本記事で得たTerraformコードを組み合わせて、自分専用の検証環境をチームや将来の自分のために再現可能な形で残せるようになります

本記事はここで宣言する通り、§5から§11までを1本の記事として完結させます。

  • §5: Terraform実行環境の準備(Resource Manager StackとローカルTerraform CLIの選択・provider設定・state管理)
  • §6: コンパートメント作成(oci_identity_compartment)
  • §7: ネットワーク構築(VCN/サブネット/ゲートウェイ/ルート表/NSG)
  • §8: Always Free A1インスタンス起動(oci_core_instance)
  • §9: 動作確認とドリフト検出
  • §10: クリーンアップ(terraform destroyとAlways Free枠の解放)
  • §11: まとめと次回予告

なお、本記事(Vol1)がTerraform化する範囲は、コンパートメント・ネットワーク・A1インスタンスという「OCI入門シリーズの基礎3巻分」に限定します。IAMポリシー設計・ストレージ設計・OKEクラスターといったより発展的な内容は、§4で範囲外として明示的に整理します。

また、本記事はTerraformコードの初回実行(ローカル環境またはResource Manager Stackでの単発のapply/destroy)までを扱い、CI/CDパイプラインへの組み込みや、複数人でのstate共有運用そのものについては扱いません。個人の検証・学習用途でのTerraform実行に焦点を絞ることで、Always Free枠の範囲内で完結する構成を優先しています。

本記事の構成上の注意点として、§1〜§4は概念とスコープの整理に充て、実際のTerraformコード(.tfファイルの中身)は§5以降でまとめて扱います。既刊のOCI入門シリーズやAWSとの対応関係を先に押さえたい場合はこのまま読み進め、コードを先に見たい場合は§5から読み始めても大きな支障はありません。

1-2. 読者像

本記事は、AWSでTerraformまたはCloudFormationを使ったIaC経験があり、OCIのIaCに初めて触れるエンジニアを主な読者として想定しています。

特に、次のような背景を持つ方に向けて、本記事は具体的な答えを用意しています。

  • AWSでCloudFormationスタックやTerraform stateの運用経験があり、OCIでの対応する仕組み(Resource Manager・oci backend)を知りたい方
  • OCI入門シリーズVol1・Vol3・Vol4のハンズオンをコンソール操作で完走済み、またはコンパートメント/VCN/インスタンスの概念を理解しており、次にコード化のステップへ進みたい方
  • 「OCIでTerraformを使うと、AWSと比べた共通点・相違点はどこか」を実装レベルで確認したい方
  • 資格学習やPoC検証のために、OCI入門シリーズVol1・Vol3・Vol4の環境を何度も作り直しており、コンソール操作の繰り返しを効率化したい方

AWSでの経験と、本記事を通じて得られる理解の対応関係を整理すると、次のようになります。

AWSでの経験本記事で得られる理解
CloudFormationでのスタック運用経験Resource ManagerのStack・ジョブ・ドリフト検出という、対応する概念をOCI側でどう組み立てるかが分かる(§3)
Terraform CLIでのS3 backend運用経験oci backendによるOCI Object Storageへのstate保存と、ローカルbackendとの使い分けが分かる(§5)
EC2/VPCをTerraform化した経験OCIのVCN・コンピュートインスタンスに対応するリソース(oci_core_vcnoci_core_instance)の書き方が分かる(§7・§8)

前提とするTerraformの経験レベルについても明確にしておきます。本記事は、resourceブロックの基本構造やterraform plan/apply/destroyの一連の流れなど、AWS provider(または他クラウドのprovider)でTerraformを一度は使ったことがあるレベルを前提とします。Terraform自体が完全に初めての場合は、HCLの基礎文法や状態管理の考え方を先に別途学習しておくことをお勧めします。本記事では、Terraformそのものの入門的な説明は最小限にとどめ、OCI providerに固有の書き方に焦点を当てて解説します。

前提とするAWSの経験レベルについても補足します。CloudFormationやTerraformを実務で使ったことがあれば十分で、必ずしもIaCの上級者である必要はありません。本記事の§3で扱うAWS対応マップは、AWSでのIaC運用の基本的な流れ(スタックの作成・更新・削除、stateの管理)を理解していれば読み進められる粒度に揃えています。

なお、本記事はOCI入門シリーズVol1〜Vol4のハンズオンを完了済みであることを前提とし、コンパートメント・VCN・A1インスタンスといった各リソース自体の概念説明は最小限にとどめます。各リソースの詳細な設計思想を知りたい場合は、該当する既刊(Vol1・Vol3・Vol4)を先に参照することをお勧めします。

逆に、本記事が主な対象としない読者像も明確にしておきます。OCIのコンソール操作そのものをこれから学びたい場合は、本記事より先にOCI入門シリーズVol1・Vol3・Vol4を読むことをお勧めします。また、oci_core_instanceoci_core_vcnといった個々のTerraformリソースの全引数を網羅的に知りたい場合は、本記事よりもTerraform Registryの公式リファレンス(oracle/oci provider)を直接参照する方が目的に合っています。本記事は、あくまで「既刊で手を動かした操作が、Terraformのどのリソース・どの引数に対応するか」という橋渡しに焦点を当てています。この橋渡しの役割を明確にしておくことで、本記事とTerraform Registryの公式リファレンスをどちらも併読すべきタイミングが読者にとって分かりやすくなると考えています。

具体的には、§6〜§8で各リソースの主要な引数(何を指定すれば動くか)は解説しますが、すべてのオプション引数の網羅的な説明は行いません。主要引数の解説だけでは足りない箇所に到達した場合は、その都度Terraform Registryの該当リソースページを参照する読み方を想定しています。

また、本記事はTerraform自体の入門(HCLの基本文法、resource/variable/outputの書き方など)そのものは前提知識として扱います。Terraformに初めて触れる場合は、HashiCorp公式のチュートリアルなどでHCLの基礎を先に押さえておくことをお勧めします。本記事が扱うのは、あくまで「OCIのどのリソースが、既刊のどの操作に対応するか」という、OCI×Terraformの対応関係です。

読者の理解を助けるため、本記事のTerraform化範囲を概観する早見表を示します。詳細な対応関係と対象外の理由は§4で扱います。

既刊本記事での扱い
Vol1(コンパートメント)Terraform化する(§6)
Vol3(VCN・ネットワーク)Terraform化する(§7)
Vol4(Always Free A1インスタンス)Terraform化する(§8)
Vol2(IAMポリシー設計論)対象外・既刊へ委譲(§4-2)
Vol5(ストレージ設計詳細)対象外・既刊へ委譲(§4-2)
Vol6(OKEクラスター)対象外・将来記事へ委譲(§4-2)

1-3. なぜ今これを書くか — シリーズ回収軸

OCI入門シリーズは、Vol1のテナンシ・コンパートメントから始まり、Vol6のOKEクラスターまで、コンソール操作を軸に全6巻で一巡しました。Vol6のまとめでは、シリーズを読み終えた次のステップの1つとして、TerraformなどのIaCツールを使ってVol1〜6で扱ったリソースをコード化し、再現可能な形で構築する方向性が予告されています。

本記事は、この予告を回収する記事として位置づけられます。既刊のOCI入門シリーズは手動でのコンソール操作を中心に構成されていたため、同じ環境を何度も再現したい場合や、チームで構成を共有したい場合には、コンソール操作の手順を都度なぞる必要がありました。本記事では、Vol1・Vol3・Vol4で扱ったリソースをTerraformコード化することで、再現可能な構成管理への移行ニーズに応えます。

この差分が特に効くのは、検証環境を使い捨てる場面です。コンソール操作では、環境を作り直すたびに同じクリック手順を再現する必要がありましたが、Terraformコード化後はterraform applyterraform destroyを繰り返すだけで、同じ構成の環境を何度でも再現・破棄できます。資格学習や技術検証でOCI入門シリーズの環境を何度も往復して使う場合、この再現性の高さは実務的な時短効果につながります。

OCIのIaCツールとして本記事がTerraformを選ぶ理由は、単なる知名度だけではありません。Resource Manager自体がTerraform HCLをネイティブの実行エンジンとして採用しているため、Terraformで書いたコードはローカルCLI・Resource Manager Stackのいずれでも、記述を変えることなくそのまま実行できます。他のIaCツールでもOCIリソースの操作自体は可能ですが、OCIのマネージドIaC実行サービスと最も密接に統合されているのがTerraformであるという点も、本記事がTerraformを選ぶ実務的な理由です。

なお、Vol2のIAMポリシー設計・Vol5のストレージ設計・Vol6のOKEクラスターについては、本記事のTerraform化スコープには含めません。範囲外とする理由は§4-2で明示的に整理します。

1-4. 本記事の差別化軸

OCIとTerraformを扱う記事の多くは、単一リソースの作成手順を紹介するチュートリアルにとどまるか、逆に個々のTerraformリソースの引数を網羅的に解説するリファレンス的な内容に偏りがちです。本記事は、次の2つの軸で差別化を図ります。

  1. AWS実務者向けの役割対比レンズ(§3): 「Resource ManagerはCloudFormationと同じもの」という短絡的な理解を避けるため、実行エンジンの違い(Terraform HCLをそのまま実行するか、独自テンプレート言語を使うか)まで踏み込んで対比します。state管理・ドリフト検出といった、AWS実務者がTerraform・CloudFormationのいずれでも共通して気にする観点を軸に整理する点が特徴です。
  2. OCI入門シリーズの体系的なコード化(§4): 単発のTerraformサンプルではなく、OCI入門シリーズVol1・Vol3・Vol4という「すでに手動構築で理解済みの範囲」を、既刊のどの章がどのTerraformリソースに対応するかという粒度で1対1に整理します。あわせて、あえてコード化しない範囲(Vol2・Vol5・Vol6・実践記事7本)も明示することで、本記事のスコープを読者が誤解しない形で示します。

この2軸を、OCIのTerraform記事にありがちな2つのパターンと対比すると、次のようになります。

記事のタイプスコープの示し方AWS実務者への配慮
単発チュートリアル型1つのリソース(例: コンピュートインスタンスのみ)の作成手順を紹介するにとどまる特になし、またはAWSへの言及がない
リファレンス網羅型providerが提供する引数を可能な限り列挙する特になし、またはAWSへの言及がない
AWS対応表のみ提示型サービス名の対応表を示すにとどまり、実際に手を動かすコードまでは扱わない対応表はあるが、実装レベルの検証は読者に委ねられる
本記事複数リソースを一気通貫で扱いつつ、対象範囲と対象外の範囲を§4で明示的に宣言する§3でResource Manager↔CloudFormationの役割対比を軸に据え、§5以降で実装まで一貫して扱う

いずれの軸も、単に「動くコードを貼る」だけではなく、なぜそのリソース構成を選ぶのか、なぜある範囲をあえて対象外とするのかという判断根拠まで含めて解説することを重視しています。

次の§2では、ここまで整理したゴール・読者像・差別化軸を踏まえたうえで、本記事のハンズオンを進めるための前提環境と技術スタックを整理します。§3・§4では、AWS実務者向けの対応マップとTerraform化スコープをそれぞれ深掘りし、§5以降で実装レベルのハンズオンに入ります。

本記事全体を通じて一貫させたいのは、「動くコードをそのままコピーして終わり」にしないという姿勢です。§3のAWS対応マップ、§4のTerraform化スコープの宣言、そして§5以降の各リソースの解説において、常に「なぜこの書き方を選んだのか」という判断根拠を添えることを心がけています。OCI入門シリーズ全体を通じて重視してきた、判断根拠・ハンズオン・落とし穴・AWS対比という4つの観点は、本記事でも変わらず引き継ぎます。

OCI入門シリーズ全6巻(手動構築編)を先に読む


2. 前提・環境・準備

ローカルTerraform CLIとResource Manager Stackという2つの実行方式の構成図
fig02: Terraform実行環境の構成図(ローカルCLI or Resource Manager Stack)

2-1. 前提環境

本記事のハンズオンを進めるにあたり、次の環境をあらかじめ用意しておくことを前提とします。

  • OCIテナンシへのアクセス権限(コンパートメント作成・VCN作成・コンピュートインスタンス作成が可能なIAMポリシーを持つユーザーまたはグループ)
  • OCI入門シリーズVol1〜Vol4のハンズオンを完了済み、またはコンパートメント・VCN・コンピュートインスタンスの概念を理解していること
  • ローカル環境にTerraform CLIとOCI CLIをインストール済み、またはResource Manager Stackのみで完結させる場合はブラウザからOCIコンソールにアクセスできる環境

なお、本記事はVol1〜Vol4で解説した各リソースの概念そのものは前提知識として扱い、既刊で解説済みの内容(コンパートメントの階層構造・VCNのCIDR設計・A1インスタンスの形状選定など)は本記事では繰り返しません。Terraformコードでの表現方法に焦点を絞って解説します。

前提チェックリスト

本記事のハンズオンを始める前に、次の項目を確認しておくことをお勧めします。

前提項目確認方法
OCIテナンシへのログインができるOCIコンソールにサインインし、ダッシュボードが表示される
コンパートメント・VCN・コンピュートインスタンスの作成権限がある各サービスのコンソールメニューにアクセスでき、作成ボタンが操作できる
Terraform CLIがインストール済みローカル端末でterraform versionが実行できる
OCI CLIがインストール済み(APIキー発行に使用)ローカル端末でoci --versionが実行できる
他のハンズオンでAlways Free枠のA1インスタンスを稼働させていないか確認済みテナンシ全体のコンピュートインスタンス一覧で、稼働中のA1インスタンスの合計OCPU/メモリを確認する

OCI入門シリーズVol1〜Vol4は、OCIコンソールへのアクセスだけで完走できる構成でした。本記事はこれに加えて、ローカル環境(またはCloud Shell)へのTerraform CLI・OCI CLIのセットアップが新たに必要になる点が、既刊との前提の違いです。この差分は、Terraformというコード実行の主体がコンソールの外側で生まれることに由来しており、§5-1で解説する実行方式の選択とも関係します。

前提となるIAMポリシー

本記事のハンズオンで作成するリソース(コンパートメント・VCN一式・コンピュートインスタンス)と、それを実行するResource Managerを操作するには、次のリソースタイプ(集約タイプ)に対する権限が必要です。テナンシ全体で管理者権限を持つユーザーであれば追加設定は不要ですが、権限を絞ったグループで作業する場合は、次のようなポリシーを用意します。

Allow group <グループ名> to manage compartments in tenancy
Allow group <グループ名> to manage virtual-network-family in tenancy
Allow group <グループ名> to manage instance-family in tenancy
Allow group <グループ名> to manage orm-stacks in tenancy
Allow group <グループ名> to manage orm-jobs in tenancy

virtual-network-familyには、VCN・サブネット・各種ゲートウェイ・ルート表・NSGといった、§7で作成するネットワークリソースがまとめて含まれています。instance-familyには、§8で作成するコンピュートインスタンスに加えて、ブートボリュームなど関連リソースも含まれます。orm-stacksorm-jobsは、Resource Manager StackとしてTerraformを実行する場合にのみ必要な権限で、ローカルTerraform CLIのみで完結させるなら必須ではありません。

なお、コンパートメント自体の作成権限は、テナンシ(ルートコンパートメント)にスコープを合わせる必要があります。§6で解説する通り、本記事はテナンシ直下にコンパートメントを1つ作成する構成を採るため、上記の1行目はテナンシスコープで指定しています。

OCIのポリシー検証レベルは、権限の弱い順にinspect・read・use・manageの4段階です。上記の例ではすべてmanageレベルで統一していますが、これは本記事がリソースの作成・変更・削除まで一気通貫で行うためです。実行結果の閲覧のみを行うユーザーには、readレベルで十分な場面もあります。

東京リージョンでの実行を前提とする

本記事のハンズオンは、OCI入門シリーズVol1〜Vol4と同じく、東京リージョン(ap-tokyo-1)での実行を前提とします。東京リージョンはAD数1のシングルAD構成であるため、Vol1の5-2で解説した通り、AD単位の冗長化という選択肢は本記事のハンズオンにも当てはまりません。この制約は、§7で構築するネットワーク構成やドリフト検出の解説には影響しないため、複数ADを前提とした設計判断は登場しません。

2-2. 使用技術スタック

本記事で使用する技術スタックを次の表に整理します。バージョンは高頻度でリリースが更新されるため、具体的な値ではなく存在チェック型の表記にとどめ、実行時に最新の安定版を確認することを前提とします。

項目バージョン/設定備考
Terraform CLI~> 1.12 等の存在チェック型表記実行時に最新安定版を確認
Terraform provider (oci)~> 8.0 等の存在チェック型表記具体値(例: v8.25.0等)は使用しない。Terraform Registryのoracle/oci名前空間で公式提供
OCI CLI最新安定版認証情報の準備・動作確認用。Resource Manager Stackのみで完結させる場合は必須ではない
認証方式APIキーベースのユーザープリンシパル認証(ローカルCLI実行時)Resource Manager Stackをコンソールから実行する場合は、コンソールへのログインセッション自体が認証情報として扱われるため、ローカルでのAPIキー設定は不要

技術スタックのAlways Free/課金対応状況

本記事で使用する技術スタックは、いずれも追加課金の心配がない構成です。OCIセキュリティ実践Vol1で扱ったサービス群のような「Always Freeテナンシのままでは使えない」という制約は、本記事のハンズオンには登場しません。

技術スタックの課金区分

項目課金区分備考
Terraform CLI無償(OSS)HashiCorpが提供するオープンソースのCLIツール
Terraform provider (oci)無償(OSS)Oracleが公式にメンテナンスするTerraform Registry公開provider
OCI CLI無償OCIが公式に提供するコマンドラインツール
Resource Manager(Stack・ジョブの実行)無償Stack・ジョブの実行自体に課金は発生しない。課金対象はResource Managerが作成するOCIリソース側

OCI CLIとAPIキーのセットアップ(概要)

ローカルTerraform CLI方式を選ぶ場合、事前にOCI CLIをインストールし、APIキーを発行しておく必要があります。手順の概要は次のとおりです。

  1. OCI CLIを公式のインストーラでローカル環境にインストールする
  2. oci setup configを実行し、対話形式でAPIキーペア(公開鍵・秘密鍵)を生成する(既存の鍵ペアを使う場合は手動で~/.oci/configを編集する)
  3. 生成された公開鍵を、OCIコンソールのユーザー設定画面からアップロードする
  4. ~/.oci/configに記録されたtenancyuserfingerprintkey_fileregionの各値を、§5-2で使用するTerraform変数(tenancy_ociduser_ocidfingerprintprivate_key_pathregion)にそれぞれ対応させる

この手順自体はOCI公式ドキュメントで詳しく解説されているため、本記事では概要にとどめます。すでにOCI CLIのセットアップが完了している場合は、この手順を省略して§5に進んで構いません。

ローカル作業ディレクトリの準備

Terraformコードを置く作業ディレクトリを新規に1つ作成しておくことをお勧めします。.tfファイルはこのディレクトリにまとめて配置し、terraform initもこのディレクトリ内で実行します。APIキーの秘密鍵ファイルや.tfvarsファイルなど、機密情報を含むファイルは、誤ってバージョン管理システムにコミットしないよう、.gitignoreへ追加しておくことも合わせて推奨します。

OCI Cloud Shellを使う場合のショートカット

ローカル環境の準備そのものを省略したい場合、OCI Cloud Shell(ブラウザ上で動作するOCI公式のターミナル)を使う選択肢もあります。Cloud Shellには、Terraform CLIとOCI CLIがあらかじめインストールされており、ログイン中のユーザーの認証情報を自動的に引き継ぐため、APIキーの発行や§5-2で扱う認証用変数の宣言そのものを省略できます。手元の環境を汚したくない場合や、複数の端末を行き来しながら検証したい場合に適した選択肢です。本記事では、環境準備の流れを一通り解説する目的でローカル環境を前提に進めますが、Cloud Shellでもここまでの前提の多くはそのまま満たされます。

AWS CLI/Terraform AWS providerとの設定の対比

AWSでTerraformを使ってきた実務者にとって、ここまでのセットアップ手順はAWS CLIの初期設定とほぼ同じ発想です。対応関係を整理すると、次のようになります。

AWSOCI
aws configureoci setup config
~/.aws/credentials~/.oci/config
IAMユーザーのアクセスキー/シークレットキーAPIキーペア(公開鍵をコンソールへ登録、秘密鍵をローカルに保持)
AWS_PROFILE環境変数によるプロファイル切り替えociコマンドの--profileオプション、またはTerraformのconfig_file_profile引数
Terraform AWS providerのsource = "hashicorp/aws"Terraform oci providerのsource = "oracle/oci"

この対応関係からも分かる通り、認証情報の管理方法自体はAWSとOCIで大きくは変わりません。異なるのは、AWSのアクセスキー/シークレットキーが「文字列のペア」であるのに対し、OCIのAPIキーは「公開鍵/秘密鍵のペア」であるという点です。OCI側の方が、鍵の失効や複数キーの併用といった鍵管理の柔軟性がやや高い設計になっています。

本記事の§5以降で使用するコマンド一覧

本記事の各章で実際に使用する主なコマンドを、あらかじめ一覧化しておきます。個別のオプションは各章で扱うため、ここでは「どの章でどのコマンドを使うか」の見取り図として押さえてください。

コマンド用途使用する章
terraform initproviderのダウンロードとbackendの初期化§5
terraform plan適用前の差分確認§6・§7・§8
terraform applyリソースの作成・変更§6・§7・§8
terraform plan -refresh-onlyドリフト検出(実際の状態とコードの差分確認)§9
terraform destroy作成したリソース一式の削除§10
oci iam compartment list / oci network vcn list / oci compute instance listコンソール操作の代わりに、作成済みリソースの状態をCLIから確認する補助用途§9

2-3. ゴール状態の定義

本記事を完走した時点でのゴール状態を、次のように定義します。

  • ローカルTerraform CLIまたはResource Manager Stackからterraform apply(Resource Manager上では対応するジョブの実行)を1回行うと、コンパートメント→VCN一式(サブネット/ゲートウェイ/ルート表/NSG)→Always Free A1インスタンスの順に構築が完了する
  • 構築が完了したA1インスタンスに対して、SSH接続まで確認できる
  • 検証が終わったらterraform destroy(Resource Manager上では対応するジョブの実行)で、作成した一式のリソースを確実に片付けられる

この「動作している状態」を、要素ごとに確認方法として整理すると、次のようになります。

要素確認項目確認方法
コンパートメント作成されているOCIコンソールのコンパートメント一覧、またはoci iam compartment listで表示される
VCN一式サブネット・ゲートウェイ・ルート表・NSGが想定通りに紐づいているVCNのコンソール画面でトポロジー表示を確認する
A1インスタンス起動しており、Always Free対象の表示があるインスタンスの状態が「Running」、形状に「Always Free-eligible」の表示がある
SSH接続公開鍵認証でログインできるssh -i <秘密鍵> opc@<パブリックIP>でログインが成功する
ドリフト検出コンソール外の変更を検知できる§9で意図的に発生させた変更が、terraform planの差分として表示される

AWS実務者向けに、この「動作している状態」の確認方法をCloudFormationと対比すると、次のようになります。

観点AWS(CloudFormation)OCI(本記事の構成)
リソース作成の確認スタックのイベントタブでCREATE_COMPLETEを確認terraform applyの実行結果、またはResource Managerのジョブログで成功を確認
個別リソースの状態確認各サービスのコンソールまたはawsCLI各サービスのコンソールまたはociCLI
ドリフトの確認スタックの「ドリフト検出」機能を手動実行terraform plan -refresh-only、またはResource Managerのドリフト検出機能を実行
後片付けの確認スタック削除後にDELETE_COMPLETEを確認terraform destroyの実行結果、または各コンソール画面でリソースが消えていることを確認

この対比が示す通り、「何を確認するか」自体はAWSとOCIで大きくは変わりません。CloudFormationのドリフト検出を使った経験があれば、§9で扱うResource Manager/Terraformのドリフト検出も、操作の流れとして違和感なく理解できるはずです。

想定される所要時間についても触れておきます。本記事のハンズオンは、コンパートメント作成からA1インスタンスのSSH接続確認まで、Terraformの実行時間だけで見るとおよそ5〜10分程度で完了します(A1インスタンスのプロビジョニングが律速要因になります)。ネットワーク疎通確認や、§9のドリフト検出の実演まで含めた通し作業時間としては、30分〜1時間程度を見込んでおくとよいでしょう。

§5以降では、この一連の流れを実装レベルで解説します。本章では、その前提となる環境準備とAlways Free枠の上限を先に整理します。

2-4. Always Free枠の前提 — Resource Manager自体の無料枠上限

本記事のハンズオンは、構築するOCIリソースだけでなく、それを実行するResource Manager自体もAlways Free枠に収まる規模で設計しています。OCI公式のAlways Freeページによれば、Resource ManagerのAlways Free上限は次のとおりです。

Resource Manager Always Free上限項目上限値
Stacks100
同時実行ジョブ数(concurrent jobs)2
プライベートエンドポイント1
テンプレート100

本記事で作成するスタックは1つのみであり、同時に実行するジョブも1つ(applyまたはdestroyのいずれか)にとどめるため、いずれの上限にも十分な余裕があります。プライベートエンドポイントは、パブリックにアクセスできないネットワーク(プライベートサブネットのみのVCNなど)にResource Managerがアクセスする際に必要となる機能ですが、本記事のハンズオンではResource Manager自体がテナンシ内のOCI APIエンドポイントを操作するだけであり、追加設定は不要です。

本記事のハンズオンが、この上限をどの程度消費するかを表にまとめると、次のようになります。いずれの項目も上限に対してごくわずかな消費にとどまることが分かります。

項目Always Free上限本記事での消費消費率
Stacks1001(ローカルCLI方式の場合は0)1%以下
同時実行ジョブ数2150%
プライベートエンドポイント100%
テンプレート1000(Stackを直接作成するため未使用)0%

なお、本記事のハンズオンは§5-1で後述する通りローカルTerraform CLI方式を採用するため、Resource Manager自体のStack・ジョブは実質的に消費しません。Resource Manager Stack方式に切り替えた場合でも、上記の表の通り上限にはまだ大きな余裕があるため、複数の検証環境を並行して作成しても上限超過の心配はほぼありません。

加えて、本記事で作成するコンパートメント・VCN一式(サブネット/インターネットゲートウェイ/NATゲートウェイ/サービスゲートウェイ/ルート表/NSG)・A1インスタンス(VM.Standard.A1.Flex)は、いずれもAlways Free対象リソースです。コンパートメントとVCN一式はOCIの標準機能として無償で提供されており、A1インスタンスはOCI入門シリーズVol4で解説したとおり、月間1,500 OCPU時間・9,000 GB時間分の時間クレジット(常時稼働換算でおよそ2 OCPU・メモリ12GB相当)の範囲であれば課金が発生しません。この上限は2026年6月15日にOracleが見直した後の現行値であり、ネット上でよく見られる「4 OCPU・24GBまで無料」という記述は旧仕様のため、本記事では採用しません。Resource Manager自体の実行(スタック・ジョブ)も無償のOCIサービスであるため、本記事のハンズオン全体はterraform applyからterraform destroyまで含めて0円で完結します。

0円運用のための注意点

  • A1インスタンスは、テナンシ全体でのAlways Free消費量(2 OCPU/12GB相当)を超えない範囲でOCPU数・メモリ量を指定してください。超過分は通常課金の対象になります
  • 他の検証(OCI入門シリーズVol4のハンズオンなど)ですでにA1インスタンスを起動したままにしている場合、本記事のインスタンスと合算でAlways Free枠を超える可能性があります。テナンシ全体でのA1インスタンス稼働状況を事前に確認してください
  • ハンズオンを中断・保留する場合でも、terraform destroyを実行せずに放置すると、コンパートメント・VCN一式・A1インスタンスが稼働したままになります。作業を中断する際は、都度terraform destroyで片付けることをお勧めします
  • 複数の検証環境を並行して作成する場合は、コンパートメント名やVCN名が重複しないよう、環境ごとに命名を分ける(例: 末尾に連番や日付を付与する)ことで、意図しない上書き・削除を防げます

前提環境の整理はここまでです。IAMポリシー・技術スタック・ゴール状態の定義・Always Free枠の上限という4つの観点を押さえたことで、§5以降で実際にリソースを作成していく準備が整いました。

次の§3では、ここまで整理した前提を踏まえたうえで、Resource ManagerとCloudFormationの役割対比を軸に、AWS実務者向けの対応マップを整理します。


3. AWS実務者向け対応マップ — Resource Manager と CloudFormation

本章では、AWSでCloudFormationやTerraformを使ってきた実務者が、OCIのResource Managerと関連概念をどう読み替えればよいかを、次の対応表を軸に整理します。

OCI概念AWS相当対比ポイント
Resource ManagerCloudFormation両者ともマネージドなIaC実行サービスですが、Resource ManagerはTerraform HCLをそのまま実行エンジンとして採用している点が異なります。CloudFormationは独自のテンプレート言語(JSON/YAML)を使うため、AWSでTerraformの実務経験がある方にとっては、Resource ManagerはCloudFormationよりもむしろ「マネージドなTerraform実行基盤」に近い存在です
Stackスタックどちらも「1つの構成のまとまりを表す論理リソース」という点で対応します。OCIのStackは1つのcompartment・1つのregionに紐づき、Resource Manager自体が管理するstateファイルと1対1で対応します。同一Stackで同時に実行できるジョブは1つのみという制約も、CloudFormationスタックの更新ロックと似た発想です
Resource Manager のドリフト検出CloudFormationのドリフト検出両者とも「実際のリソースの状態」と「最後に適用した構成」の差分を検出する機能です。Resource Managerはスタック単位・リソース単位のいずれでもドリフト検出レポートを実行でき、CloudFormationのドリフト検出と粒度の考え方はよく似ています。ただしResource Managerのドリフト検出は明示的な実行操作(ジョブの起動)が必要で、CloudFormationのように変更セットに連動した自動検知ではない点に注意が必要です
oci backend (state管理)S3 backend (state管理)Terraform CLIには、v1.12以降で追加されたociバックエンドがあり、tfstateファイルをOCI Object Storageバケットに保存できます。ロックはOCI Object Storageの条件付きリクエスト(If-None-Match)で実現されており、AWSでS3 backend+ロック機構を組み合わせてきた実務者にとって発想がそのまま対応します。ただしResource Manager Stackとして実行する場合はResource Manager自体がstateを管理するため、このociバックエンドの設定は不要です。ローカルTerraform CLIで直接apply/destroyしたい場合にのみ検討します

4. Terraform化スコープ — Vol1〜6の何をコード化し、何を委譲するか

4-1. Terraform化する範囲

本節では、OCI入門シリーズVol1・Vol3・Vol4で手動構築した範囲を、具体的にどのTerraformリソースへ対応させるかを整理します。

既刊該当箇所対応Terraformリソース
OCI入門シリーズ Vol1§4 コンパートメント作成oci_identity_compartment
OCI入門シリーズ Vol3§2-5 VCN/サブネット/IGW/NATGW/SGW/ルート表/NSGoci_core_vcnoci_core_subnetoci_core_internet_gatewayoci_core_nat_gatewayoci_core_service_gatewayoci_core_route_tableoci_core_network_security_groupoci_core_network_security_group_security_rule
OCI入門シリーズ Vol4§6-2 Always Free A1インスタンス起動oci_core_instance

Vol1の§4で扱ったコンパートメント作成は、oci_identity_compartmentという単一リソースにそのまま対応します。パラメータもコンソール操作でのフォーム入力(名前・説明・親コンパートメント)と1対1に近く、本記事全体の中でTerraform化の難易度が最も低い部分です。

Vol3の§2〜§5で扱ったVCN一式は、複数のTerraformリソースの組み合わせで構成します。VCN本体はoci_core_vcn、サブネットはoci_core_subnetに対応します。ゲートウェイは、インターネットゲートウェイ(oci_core_internet_gateway)・NATゲートウェイ(oci_core_nat_gateway)・サービスゲートウェイ(oci_core_service_gateway)の3種類を作成し、ルート表はoci_core_route_tableで管理します。Vol3の5-3でOracle推奨とされたNSGは、本体をoci_core_network_security_group、ルールをoci_core_network_security_group_security_ruleでそれぞれ管理します。Vol3の4-4で紹介されたDRG(Dynamic Routing Gateway)は本記事のハンズオンでは作成しないため、対応するTerraformリソース(oci_core_drg)もスコープ外です。DRGのルートテーブル・アタッチメント設計をTerraform化する場合は、DRGを実装レベルで扱う別記事の範囲として切り分けます。DRGの設計論自体は、既刊のネットワーク実践Vol1 §3(DRG設計実践)で扱っています。

OCIネットワーク実践(Production編)Vol1(DRG設計実践)を読む

Vol4の§6-2で扱ったAlways Free A1インスタンスの起動は、oci_core_instanceリソースに対応します。形状(VM.Standard.A1.Flex)・OCPU数・メモリ量・イメージOCID・SSH公開鍵といった、Vol4のハンズオンでコンソール上のフォームに入力した値が、そのままTerraformのリソース引数に対応します。

4-2. Terraform化しない範囲(既刊への委譲を明示宣言)

以下は、既刊シリーズ・実践記事群のうち、本記事のTerraform化スコープに含めない範囲を明示的に整理したものです。単なる省略ではなく意図的な範囲外であることを示すため、委譲理由と参照先を明記します。

既刊/対象委譲理由参照先
OCI入門シリーズ Vol2 (IAMポリシー設計論)設計論は既刊(Vol2)に委譲します。本記事では、Resource ManagerやA1インスタンスの実行に必要な最小限のpolicy/dynamic groupのみをTerraformコードとして扱いますOCI入門 Vol2
OCI入門シリーズ Vol5 (ストレージ3系統の設計詳細)設計詳細は既刊(Vol5)に委譲します。A1インスタンスに付随するbootボリュームはoci_core_instance作成時の暗黙作成に留め、Block/Object/File Storageそれぞれの設計判断はVol5の内容を前提としますOCI入門 Vol5
OCI入門シリーズ Vol6 (OKEクラスター)OKEクラスターのTerraform化は、ノードプール・ワーカーシェイプ・Ingress構成といった、基礎3巻より複雑な設計判断を伴うため、本記事のスコープには含めず、将来の「OKE IaC実践」回へ委譲します将来公開予定(現時点ではURL未定)
実践記事7本(ADB/HeatWave/GenAI/Functions/LB/監視/セキュリティ)このうちOCI Autonomous Database実践Vol1・MySQL HeatWave実践Vol1・Generative AIサービス実践Vol1の3本は、各記事内で『扱わない内容』としてTerraform等のIaCによるプロビジョニングをすでに明示しています(うちADB実践Vol1は「別記事で扱う可能性があります」と付記)。残る4本(Functions & API Gatewayサーバーレス実践Vol1・ネットワーク実践(Production編)Vol1・可観測性運用監視実践Vol1・セキュリティ実践Vol1)は現時点でIaC範囲への言及はありませんが、いずれもサービス個別の実装知識を要する内容であり、本記事(基礎3巻のTerraform化)のスコープには含めません。各サービスのIaC化は、将来のサービス別IaC実践回として個別に扱う想定ですADB実践Vol1HeatWave実践Vol1Generative AI実践Vol1Functions&API Gateway実践Vol1ネットワーク実践(Production編)Vol1可観測性運用監視実践Vol1セキュリティ実践Vol1

5. Terraform実行環境の準備

ローカルTerraform CLIとResource Manager Stackの2つの実行方式の比較図
fig03: 本記事で採用するローカルTerraform CLI実行方式と、代替となるResource Manager Stack方式の比較

5-1. 実行方式の選択 — Resource Manager Stack vs ローカルTerraform CLI

OCIでTerraformを実行する方法は、大きく2種類あります。ひとつはOCIが提供するマネージドサービスであるResource Managerに.tfファイル一式(Stack)をアップロードし、OCIコンソールまたはOCI CLI経由でplan/applyを実行する方式です。もうひとつは、自分のローカル端末やCI環境にTerraform CLIをインストールし、oci providerを介して直接OCI APIを呼び出す方式です。

Resource Managerを使う方式は、実行環境の管理が不要でstateファイルも自動的にOCI側で管理される点が利点です。AWSでいえばCloudFormationにTerraformコードを流し込んで実行するようなイメージに近く、後述するドリフト検出もコンソール上のボタン操作だけで実行できます。一方でローカルTerraform CLIは、手元でコードを書いてすぐにterraform planの差分を確認できる開発体験の速さが利点です。

本記事のハンズオンでは、Terraformコードそのものの構造とOCIリソースの対応関係を理解することを主目的とするため、ローカルTerraform CLI方式を採用します。plan/apply/destroyのつどコンソール操作を挟まず、コマンド一発で結果を確認できるため、手を動かしながら学ぶ用途に適しています。Resource Manager Stackへの移行は、ローカルで書いたコードをそのままZIP化してアップロードするだけで可能なため、チーム運用の段階になってから検討すれば十分です。

5-2. provider設定

まず、Terraform本体とoci providerのバージョンを固定します。バージョン番号は具体値ではなく、存在チェック型の表記(~>)で指定するのが実務上の定石です。具体値を書くと、providerの頻繁なリリースにコードが追従できなくなるためです。§5-3で扱うocibackendはTerraform 1.12以降で追加された機能のため、required_versionもこれを満たす表記にしておきます。

terraform {
  required_version = "~> 1.12"

  required_providers {
 oci = {
source  = "oracle/oci"
version = "~> 8.0"
 }
  }
}

provider "oci" {
  tenancy_ocid  = var.tenancy_ocid
  user_ocid  = var.user_ocid
  fingerprint= var.fingerprint
  private_key_path = var.private_key_path
  region  = var.region
}

認証方式は、上記の例のようにAPIキーベースの認証情報(~/.oci/config相当の値)を変数経由で渡す方法が最も一般的です。OCI CLIを事前にセットアップ済みであれば、config_file_profile引数で既存の~/.oci/configのプロファイルをそのまま参照する方法もあります。CI/CD環境やOCIコンピュートインスタンス上からTerraformを実行する場合は、APIキーを持ち出さずに済むInstance Principal認証(auth = "InstancePrincipal")を使う選択肢もありますが、本記事のハンズオンはローカル端末からの実行を前提とするため、APIキー方式を採用します。

変数は次のように宣言します。APIキーの秘密鍵ファイルパスや各種OCIDは、Gitリポジトリにコミットしない.tfvarsファイルや環境変数(TF_VAR_接頭辞)経由で渡すようにしてください。

variable "tenancy_ocid" {
  type = string
}

variable "user_ocid" {
  type = string
}

variable "fingerprint" {
  type = string
}

variable "private_key_path" {
  type = string
}

variable "region" {
  type = string
  default = "ap-tokyo-1"
}

5-3. state管理 — oci backendとS3 backendの対比

§3で触れたとおり、Terraformにはocibackendタイプが存在し、stateファイルをOCI Object Storageに保存できます。ロックはOCI Object Storageの条件付きリクエスト(If-None-Match)で実現されており、AWSでS3 backend+ロック機構を組み合わせてきた実務者にとっては、発想がそのまま対応します。

terraform {
  backend "oci" {
 namespace = "<自テナンシのnamespace>"
 bucket = "terraform-practice-state"
 key = "oci-terraform-practice-vol1/terraform.tfstate"
 region = "ap-tokyo-1"
  }
}

backendブロックはterraformブロック内という特殊な評価タイミングで読み込まれるため、var.*などの変数参照を使えません。namespaceにはOCIコンソールの「テナンシ詳細」で確認できるObject Storageネームスペースの値を、上記のようにリテラル文字列として直接記述してください。

選択肢概要備考
local backend(既定)stateファイルを実行端末上に保存本ハンズオンではこの既定設定のまま進める。1人で完結する検証用途向け
oci backendstateファイルをOCI Object Storageバケットに保存し、If-None-Matchでロックチーム共有・CI実行時に検討する構成。AWSのS3 backendに相当する正式なbackendタイプ

Resource Manager Stack方式を選んだ場合は、この節の設定自体が不要になります。stateはStack側で自動的に管理され、ユーザーがbackend設定を書く必要がないためです。この違いは、AWSでいう「CloudFormationはstateを自前で持つが、素のTerraformはbackendを自分で選ぶ必要がある」という構図とほぼ同じです。

本記事のハンズオンは1人で完結する検証用途のため、以降はlocalbackend(何も指定しない既定状態)のまま進めます。チームでstateを共有する段階に進んだら、上記のocibackendへの切り替えを検討してください。


6. コンパートメント作成 — oci_identity_compartment

OCI入門シリーズ Vol1では、コンパートメントをOCIコンソールから手動作成しました。ここでは同じ構造をoci_identity_compartmentリソースでコード化します。

OCI入門シリーズ Vol1(コンパートメント編)を先に読む

コンパートメントはテナンシ直下、またはすでにあるコンパートメント配下のどちらにも作成できます。本記事のハンズオンでは、テナンシ(ルートコンパートメント)の直下に、以降で作成するネットワーク・コンピュートリソースをまとめて格納する1つのコンパートメントを作成します。

resource "oci_identity_compartment" "handson" {
  compartment_id = var.tenancy_ocid
  name  = "terraform-practice-handson"
  description = "OCI Terraform実践ハンズオン用コンパートメント"
  enable_delete  = true
}

compartment_id引数には、作成先の親コンパートメントのOCIDを指定します。テナンシ直下に作りたい場合は、テナンシ自身のOCIDであるvar.tenancy_ocidを渡す点がポイントです。コンパートメントリソースはテナンシの子リソースとして扱われるため、AWSのOU作成でルート組織のOCIDを親IDとして指定する感覚に近いといえます。

enable_delete = trueは、Terraformの管理下でこのコンパートメントをterraform destroyできるようにするための明示フラグです。OCIのコンパートメントは、既定では誤削除防止のため簡単には削除できない仕組みになっており、Terraform側でもこのフラグを立てない限りdestroy実行時にコンパートメントの削除がスキップされます。§10のクリーンアップで無料枠を確実に片付けるために、本ハンズオンではtrueを設定しておきます。

作成後、後続のリソース(VCN・インスタンスなど)はoci_identity_compartment.handson.idを参照することで、このコンパートメント配下に配置されます。Vol1で解説したとおり、コンパートメントはIAMポリシーのスコープ単位でもあるため、実務ではこのコンパートメントに対して最小権限のポリシーを別途アタッチする設計になりますが、ポリシー設計自体はVol2に委譲済みのため、本記事では作成のみを扱います。


7. ネットワーク構築 — VCN/サブネット/ゲートウェイ/ルート表/NSG

Terraformで構築するVCNのネットワーク構成図(public/privateサブネット・IGW・NATGW・SGW・ルート表・NSGの関係)
fig04: 本節で構築するネットワーク構成(public/privateサブネット2層+IGW/NATGW/SGW+NSG)

OCI入門シリーズ Vol3では、public/privateサブネットの2層構成と、Internet Gateway・NAT Gateway・Service Gatewayの使い分け、セキュリティリストとNSGの役割分担を設計論として解説しました。ここでは、そのVol3 §6のベストプラクティスをそのままTerraformコードに落とし込みます。

OCI入門シリーズ Vol3(ネットワーク編)を先に読む

7-1. VCN/サブネット

まずVCN本体と、public/privateの2つのサブネットを作成します。publicサブネットには§8で起動するAmpere A1インスタンスを配置し、privateサブネットは将来アプリケーション層・データベース層を追加する際の受け皿として、Vol3の設計を再現する目的で構築します。

resource "oci_core_vcn" "handson" {
  compartment_id = oci_identity_compartment.handson.id
  cidr_blocks = ["10.0.0.0/16"]
  display_name= "terraform-practice-vcn"
  dns_label= "tfhandson"
}

resource "oci_core_subnet" "public" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  cidr_block  = "10.0.0.0/24"
  display_name= "public-subnet"
  dns_label= "public"
  route_table_id = oci_core_route_table.public.id
  security_list_ids = [oci_core_security_list.public.id]
  prohibit_public_ip_on_vnic = false
}

resource "oci_core_subnet" "private" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  cidr_block  = "10.0.1.0/24"
  display_name= "private-subnet"
  dns_label= "private"
  route_table_id = oci_core_route_table.private.id
  security_list_ids = [oci_core_security_list.private.id]
  prohibit_public_ip_on_vnic = true
}

cidr_blocksはVCN全体のアドレス範囲(リスト形式)、各サブネットのcidr_blockはその内側を分割した範囲です。Vol3のチェックリストで触れたとおり、将来のサブネット追加を見込んで/16のVCNに/24単位でサブネットを切る余裕を持たせています。prohibit_public_ip_on_vnicは、privateサブネット側でtrueにすることで、そのサブネットに配置したVNICへのパブリックIP割り当てをOCI側で構造的に禁止できる引数です。AWS VPCのpublic/privateサブネットの区別が「ルートテーブルにIGWへの経路があるかどうか」という運用上の慣習に留まるのに対し、OCIではこの引数によってサブネットレベルで明示的に強制できる点が特徴です。

7-2. IGW/NATGW/SGW

続いて、3種類のゲートウェイを作成します。Internet GatewayはpublicサブネットからOCI外部との双方向通信、NAT GatewayはprivateサブネットからOCI外部へのアウトバウンド専用通信、Service GatewayはprivateサブネットからOCIサービス(Object Storageなど)へのプライベート経路を担います。

resource "oci_core_internet_gateway" "handson" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "handson-igw"
  enabled  = true
}

resource "oci_core_nat_gateway" "handson" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "handson-natgw"
}

data "oci_core_services" "all" {
  filter {
 name= "name"
 values = ["All .* Services In Oracle Services Network"]
 regex  = true
  }
}

resource "oci_core_service_gateway" "handson" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "handson-sgw"

  services {
 service_id = data.oci_core_services.all.services[0].id
  }
}

oci_core_servicesデータソースは、リージョンで利用可能なOCIサービスのCIDRバンドル(「All … Services In Oracle Services Network」)を検索するためのものです。Service Gatewayのservicesブロックにこのservice_idを渡すことで、privateサブネットからObject Storage等へインターネットを経由せずアクセスできるようになります。Vol3 §6-2で触れたとおり、NAT Gateway経由よりService Gateway経由のほうが通信経路は短く、データ処理料金もかからないため、privateサブネットの設計では優先的に検討すべき経路です。

7-3. ルート表/NSG

ルート表は、public/privateそれぞれのサブネットに対して個別に用意し、通信の出口を明示的に分離します。

resource "oci_core_route_table" "public" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "public-rt"

  route_rules {
 destination = "0.0.0.0/0"
 destination_type  = "CIDR_BLOCK"
 network_entity_id = oci_core_internet_gateway.handson.id
  }
}

resource "oci_core_route_table" "private" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "private-rt"

  route_rules {
 destination = "0.0.0.0/0"
 destination_type  = "CIDR_BLOCK"
 network_entity_id = oci_core_nat_gateway.handson.id
  }

  route_rules {
 destination = data.oci_core_services.all.services[0].cidr_block
 destination_type  = "SERVICE_CIDR_BLOCK"
 network_entity_id = oci_core_service_gateway.handson.id
  }
}

privateサブネットのルート表には2つの経路を設定しています。デフォルトルート(0.0.0.0/0)はNAT Gateway向け、OCIサービスのCIDRバンドル向けの経路はService Gateway向けです。destination_type = "SERVICE_CIDR_BLOCK"と指定することで、OCIサービス宛ての通信だけを優先的にService Gateway経由に振り分けられます。

セキュリティリストは、Vol3 §6-3で解説したOracle推奨に沿って、サブネット単位の最小限のベースラインに留めます。詳細な通信制御はNSG側に寄せる設計です。

resource "oci_core_security_list" "public" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "public-sl"

  egress_security_rules {
 protocol = "all"
 destination = "0.0.0.0/0"
  }

  ingress_security_rules {
 protocol = "6"
 source= "0.0.0.0/0"

 tcp_options {
min = 22
max = 22
 }
  }
}

resource "oci_core_security_list" "private" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "private-sl"

  egress_security_rules {
 protocol = "all"
 destination = "0.0.0.0/0"
  }
}

最後に、Vol3 §6-3で解説したマイクロセグメンテーションの考え方をNSGで実装します。§8で起動するインスタンス用のNSGを1つ作成し、SSH(TCP 22番ポート)を許可する受信ルールと、全許可の送信ルールを個別リソースとして定義します。

resource "oci_core_network_security_group" "instance" {
  compartment_id = oci_identity_compartment.handson.id
  vcn_id= oci_core_vcn.handson.id
  display_name= "instance-nsg"
}

resource "oci_core_network_security_group_security_rule" "ssh_ingress" {
  network_security_group_id = oci_core_network_security_group.instance.id
  direction  = "INGRESS"
  protocol= "6"
  source  = var.admin_cidr
  source_type= "CIDR_BLOCK"

  tcp_options {
 destination_port_range {
min = 22
max = 22
 }
  }
}

resource "oci_core_network_security_group_security_rule" "egress_all" {
  network_security_group_id = oci_core_network_security_group.instance.id
  direction  = "EGRESS"
  protocol= "all"
  destination = "0.0.0.0/0"
  destination_type  = "CIDR_BLOCK"
}

var.admin_cidrは、SSH接続を許可する接続元CIDR(自宅・オフィスの固定IPなど)を指定する変数です。セキュリティリストのingress_security_rulesにも同じくTCP 22番ポートの許可を置いていますが、これはOracle推奨のとおり「サブネット単位の最小限のベースライン」として全開放気味に、実際の絞り込みはNSG側のvar.admin_cidrで行うという役割分担です。本番運用ではセキュリティリスト側の0.0.0.0/0も見直す余地がありますが、本ハンズオンでは学習用途としてVol3の構成をそのまま再現しています。

Vol3設計論とのコード対応まとめ

  • public/privateサブネット分離 → prohibit_public_ip_on_vnicで構造的に強制
  • IGW=public、NATGW/SGW=private → ルート表(oci_core_route_table)で経路を分離
  • セキュリティリスト=最小ベースライン、NSG=階層ごとの詳細制御 → 役割分担をそのままリソース分割に反映

8. Always Free A1インスタンス起動 — oci_core_instance

OCI入門シリーズ Vol4では、Always Free枠のAmpere A1インスタンスをコンソールから手動で起動しました。ここでは§7で構築したpublicサブネットとNSGを使い、同じ構成をoci_core_instanceでコード化します。

OCI入門シリーズ Vol4(コンピュート編)を先に読む

まず、インスタンス作成に必要な2つのデータソースを用意します。ひとつは配置先のアベイラビリティドメイン、もうひとつはArm(aarch64)対応のOSイメージです。Vol4 §5-2で解説したとおり、Ampere A1(Arm)形状にはArm対応ビルドのイメージを選ぶ必要があるため、data.oci_core_imagesの検索条件にshapeを指定してArm対応イメージのみを絞り込みます。

data "oci_identity_availability_domains" "ads" {
  compartment_id = var.tenancy_ocid
}

data "oci_core_images" "arm_image" {
  compartment_id  = oci_identity_compartment.handson.id
  operating_system= "Oracle Linux"
  operating_system_version = "9"
  shape  = "VM.Standard.A1.Flex"
  sort_by= "TIMECREATED"
  sort_order= "DESC"
}

shape引数でフィルタをかけることで、返却されるイメージ一覧がVM.Standard.A1.Flex(Ampere A1)で起動可能なArm対応ビルドのみに絞り込まれます。sort_by/sort_orderで作成日時の降順に並べ、images[0]で最新のイメージを選ぶのが定石です。

続いて、インスタンス本体を定義します。

resource "oci_core_instance" "a1" {
  compartment_id= oci_identity_compartment.handson.id
  availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
  display_name  = "terraform-practice-a1"
  shape = "VM.Standard.A1.Flex"

  shape_config {
 ocpus= 2
 memory_in_gbs = 12
  }

  create_vnic_details {
 subnet_id= oci_core_subnet.public.id
 nsg_ids  = [oci_core_network_security_group.instance.id]
 assign_public_ip  = true
  }

  source_details {
 source_type = "image"
 source_id= data.oci_core_images.arm_image.images[0].id
  }

  metadata = {
 ssh_authorized_keys = file(var.ssh_public_key_path)
  }
}

output "instance_public_ip" {
  value = oci_core_instance.a1.public_ip
}

Vol4 §6-1で解説したとおり、2026年8月時点のAlways Free枠は「Ampere A1で月間1,500 OCPU時間・9,000 GB時間」です。常時稼働させ続ける前提で換算すると、約2 OCPU/12GB相当のインスタンス1台分になります。shape_configocpus = 2 / memory_in_gbs = 12はこの上限いっぱいの構成であり、これを超える値を指定すると超過分が課金対象に切り替わってしまいます。無料枠の正確な数値は変更される可能性があるため、実際に構築する際は必ずOracle公式のAlways Freeページで最新値を確認してください。

create_vnic_detailsブロックで、§7-1のpublicサブネットと§7-3のNSGを紐づけ、assign_public_ip = trueでパブリックIPを割り当てます。metadatassh_authorized_keysには、Vol4 §5-1で解説したSSH公開鍵ファイルの中身をfile()関数で読み込んで渡します。

Arm/x86イメージの取り違えに注意

  • Vol4 §5-2の落とし穴と同じく、data.oci_core_imagesshapeフィルタを外すとx86向けイメージが混在して取得される場合があります。
  • Ampere A1(Arm)形状に対してx86イメージを指定すると起動エラーになるため、shape引数は必ず指定してください。

なお、Oracle Linuxイメージの既定SSHユーザーはopcです。§9の疎通確認ではssh opc@<パブリックIP>で接続します。


9. 動作確認とドリフト検出

ここまでのコードをterraform planで確認し、問題なければterraform applyで実際にリソースを作成します。

terraform init
terraform plan -out=tfplan
terraform apply tfplan

terraform initはprovider(oracle/oci)のダウンロードとbackendの初期化、terraform planは実際に作成・変更されるリソースの差分プレビューです。-out=tfplanでplan結果をファイルに保存しておくと、apply時に想定外の差分が紛れ込むことを防げます。applyが完了したら、§8で定義したoutputからパブリックIPを取得し、SSH接続で疎通確認します。

terraform output instance_public_ip
ssh opc@$(terraform output -raw instance_public_ip)

Vol4 §5-3で触れたとおり、パブリックIPが割り当てられていてもNSG・セキュリティリスト側でTCP 22番ポートが許可されていないと接続がタイムアウトします。§7-3で設定したvar.admin_cidrが、実際に接続元として使う端末のグローバルIPと一致しているかをまず確認してください。

ドリフト検出の実演

§3で対応マップとして挙げたとおり、OCIのResource ManagerにもCloudFormationのドリフト検出に相当する機能があります。ここでは、Terraformの標準機能であるterraform planを使ったドリフト検出を実演します。

まず、OCIコンソールから、Terraformが管理しているNSGのルールに手動で変更を加えます。たとえば、§7-3で作成したinstance-nsgに対し、コンソールから一時的にHTTP(TCP 80番)の受信ルールを追加してみます。この操作はTerraformコードを経由しない、いわば「手動での構成逸脱」です。

その状態で、再度terraform planを実行します。

terraform plan

Terraformはstateファイルに記録された「あるべき状態」と、OCI側の実際の状態をAPI経由で突き合わせるため、コンソールから追加したHTTP受信ルールがoci_core_network_security_group_security_rule.egress_allや関連リソースの管理範囲外に存在する差分として検出されます。具体的には、Terraformコード側に存在しないルールが実環境にだけ存在する状態(いわゆる管理外リソースのドリフト)としてplanの出力に現れます。

より厳密にドリフトの有無だけを判定したい場合は、-detailed-exitcodeオプションが便利です。

terraform plan -detailed-exitcode

このオプションを付けると、差分がない場合は終了コード0、差分がある場合は2が返るため、CI/CDパイプラインで「意図しない変更が入っていないか」を自動チェックする用途にそのまま組み込めます。

Resource Manager Stack方式を採用している場合は、OCIコンソールのStack画面に「ドリフトの検出」ボタンが用意されており、ボタン操作だけで同様の差分検出をマネージドに実行できます。CloudFormationのドリフト検出がコンソールのボタン一発で完結するのと同じ発想です。ローカルCLI方式ではterraform planをコマンドとして明示的に実行する必要がある一方、その分CI/CDへの組み込みが容易という違いがあります。

検証が終わったら、コンソールから手動追加したHTTP受信ルールは削除し、terraform planで差分が0件に戻ることを確認しておいてください。手動変更を残したまま次章のterraform destroyに進むと、意図しないリソースが残存する原因になります。


10. クリーンアップ — terraform destroy とAlways Free枠の解放

Always Free枠のリソースは課金が発生しないとはいえ、検証環境を放置せず片付けておくのがハンズオンの基本です。Terraformで構築した環境は、terraform destroy一発でapplyの逆順に削除できます。

terraform destroy

destroyを実行すると、Terraformはリソース間の依存関係グラフを参照し、インスタンス→NSGルール/セキュリティリスト→サブネット→ゲートウェイ類→VCN→コンパートメントという、作成時とは逆順の依存関係に沿って安全に削除を進めます。手動で個々のリソースを順番通りに消していく必要はありません。

§6でenable_delete = trueを設定したのは、まさにこのコンパートメント削除のためです。このフラグがない場合、コンパートメント自体はterraform destroyの対象から除外され、OCIコンソール側にコンパートメントの空箱だけが残り続けてしまいます。

destroyが失敗する場合の主な原因

  • §9のドリフト検出で手動追加したリソースを消し忘れている — Terraformコード側に定義がないリソースはdestroyの対象にならず、コンパートメント削除がブロックされる
  • コンパートメント内にTerraform管理外のリソース(コンソールから直接作成したもの等)が残っている — コンパートメントは空でないと削除できない
  • NAT Gateway・Service Gatewayなど、他リソースから参照中のネットワークコンポーネントを先に手動削除してしまった — terraform planで状態を再確認してからdestroyをやり直す

destroy完了後は、terraform planを再実行してエラーが出ないこと、およびOCIコンソール上で当該コンパートメントが削除済み(または空の状態)であることを確認してください。Always Free枠のA1インスタンスは、稼働している間だけテナンシ全体の無料枠クレジットを消費する仕組みのため、削除を確認しておくことで次回以降のハンズオンでも同じ無料枠を気兼ねなく使い続けられます。


11. まとめ — 次回予告

本記事では、OCI入門シリーズ Vol1・Vol3・Vol4でコンソール操作により手動構築したコンパートメント・ネットワーク・Ampere A1インスタンスを、Terraformコードとして再現しました。

本記事で確立した内容

  • oci_identity_compartmentによるコンパートメントのコード化(Vol1 §4回収)
  • public/privateサブネット2層構成 + IGW/NATGW/SGW + ルート表 + NSGによるVol3設計論のコード化(Vol3 §2-5回収)
  • oci_core_instance + Arm対応イメージ検索によるAlways Free A1インスタンスのコード化(Vol4 §6-2回収)
  • terraform planによるドリフト検出の実演と、terraform destroyによる確実なクリーンアップ手順

§4-2で宣言したとおり、本記事のTerraform化スコープはコンパートメント・ネットワーク・Ampere A1インスタンスまでに留めています。OCI入門シリーズ Vol6で扱ったOKE(Oracle Container Engine for Kubernetes)クラスターのコード化は、本記事では扱わず、将来の「OKE IaC実践」回へ委譲します。OKEはノードプールやKubernetesバージョン管理など、単体のコンピュートインスタンスとは異なる設計判断が数多く必要になるため、独立した記事として深掘りする方が読者にとって理解しやすいと判断したためです。

本記事で構築したコンパートメント・ネットワーク一式は、その「OKE IaC実践」回でも土台として再利用できる構成になっています。Terraformでコード化された環境は、コンソール操作による手動構築と比べて再現性・レビュー可能性の面で大きな利点があります。まずは本記事の範囲でplan/apply/destroyのサイクルに慣れておくことで、次回以降のより複雑なIaC実践にもスムーズに進めるはずです。