1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OCI Resource Managerで既存リソースをimportしたい 〜terraform importとの違いと実践手順〜

1
Posted at

samune.png

はじめに

本記事では、OCI Resource Manager で管理している既存の Terraform Stack に対して、Terraform 管理外の OCI リソースを取り込む方法についてまとめていきます。

OCI を運用していると、以下のように Terraform 管理外のリソースが存在するケースがあります。

  • OCI コンソールから手動で作成したリソース
  • OCI CLI から作成したリソース
  • Terraform 導入以前から存在するリソース
  • 一時的に手動作成したものの、後から Terraform 管理へ移行したいリソース

まず、本記事で頻出する Terraform の用語を簡単に整理します。

用語 概要
Terraform Configuration Terraform がインフラをどのような状態にするかを記述した .tf ファイル群
Resource Block Terraform Configuration の中で、個々のリソースを定義する部分
Resource Address Terraform 上で個々のリソースを識別する名前
Terraform State Terraform が管理しているリソースと、実際のクラウドリソースとの対応関係などを保持する状態情報

例えば、以下の Terraform Configuration があるとします。

.
├── main.tf
├── variables.tf
├── outputs.tf
└── network.tf

このうち、以下のような記述が Resource Block です。

resource "oci_core_vcn" "example" {
  compartment_id = var.compartment_id
  cidr_block     = "10.0.0.0/16"
  display_name   = "example-vcn"
}

この Resource Block の Resource Address は以下になります。

oci_core_vcn.example

Terraform State では、この Resource Address と実際の OCI リソースが紐付けられています。

Terraform Configuration
        ↓
oci_core_vcn.example

Terraform State
        ↓
oci_core_vcn.example
        ↓
ocid1.vcn.oc1.ap-tokyo-1.xxxxx

OCI
        ↓
実際に存在するVCN

この関係を踏まえると、Terraform 管理外の既存 OCI リソースを Resource Manager の管理下へ取り込むには、下記の通り、両方を既存リソースに対応させる必要があります。

Terraform Configuration
        +
Terraform State

Terraform Configuration には対象リソースの Resource Block を追加し、Terraform State にはその Resource Address と実際の OCI リソースを紐付けます。

Terraform 1.5 以降では、import block を利用することで、この既存リソースの紐付けを通常の Plan / Apply フローに組み込むことができます。

Resource Block
        +
import block
        ↓
Plan
        ↓
Apply
        ↓
既存OCIリソースをTerraform Stateへ登録

OCI Resource Manager では Terraform 1.5.x がサポートされているため、この仕組みを Resource Manager の Plan / Apply Job に組み込むことができます。

今回の記事では、さらに既存 OCI リソースの Resource Block を一から記述する作業もできるだけ減らすため、Resource Discovery を利用します。

全体の流れは以下の通りです。

既存OCIリソース
      ↓
Resource Discovery
      ↓
Terraform Configuration生成
      ↓
既存Stack向けにResource Blockを調整
      ↓
import blockを追加
      ↓
Resource ManagerでPlan
      ↓
Resource ManagerでApply
      ↓
既存リソースをTerraform StateへImport
      ↓
再度Planして差分確認

なお、Resource Discovery の利用は必須ではありません。

既存リソースの Terraform Configuration は、例えば以下の方法でも用意できます。

  • Resource Block を手動で記述する
  • Cloud Shell 上で import block + terraform plan -generate-config-out を利用する
  • OCI Resource Discovery を利用する

本記事では、既存リソースの HCL 化をできるだけオフロードし、本番運用時にも同じ手順を利用しやすくするため、Resource Discovery を採用します。

本記事では以下についてまとめていきます。

  • Terraform の import block について
  • terraform import CLI との違い
  • Resource Manager に既存リソースを取り込む考え方
  • Resource Discovery を利用した Terraform Configuration の生成
  • 既存 Resource Manager Stack への Resource Block の追加
  • import block の追加
  • Resource Manager の Plan / Apply による Import
  • Import 後の差分確認

Terraform の import について

Terraform では、既存リソースを Terraform 管理下へ取り込む方法として Import が用意されています。

Terraform 1.5 以降では、Terraform Configuration に import block を記述できます。

例えば、既存の OCI VCN を取り込む場合は以下のように記述します。

import {
  to = oci_core_vcn.example
  id = "ocid1.vcn.oc1.ap-tokyo-1.xxxxx"
}

Import 先となる Resource Block も用意します。

resource "oci_core_vcn" "example" {
  compartment_id = var.compartment_id
  cidr_block     = "10.0.0.0/16"
  display_name   = "example-vcn"
}

この状態で Plan を実行すると、Terraform は新規作成ではなく、既存リソースを Import する処理として認識します。

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

その後 Apply を実行することで、既存リソースが Terraform State に登録されます。

Resource Block
      +
import block
      ↓
terraform plan
      ↓
terraform apply
      ↓
Terraform StateへImport

Terraform の公式ドキュメントでも、以下の流れが案内されています。

  1. Resource Block を定義
  2. import block を追加
  3. Plan で Import 内容を確認
  4. Apply で State へ Import


terraform import CLI との違い

従来から利用できる terraform import CLI でも、既存リソースを Terraform State に取り込めます。

例えば以下の通りです。

terraform import \
  oci_core_vcn.example \
  ocid1.vcn.oc1.ap-tokyo-1.xxxxx

terraform import を実行すると、Terraform CLI が Terraform State を更新し、

oci_core_vcn.example
        ↓
ocid1.vcn.oc1.ap-tokyo-1.xxxxx

という対応関係を State に登録します。

そのため、Terraform State ファイルを手作業で編集する必要はありません。

通常の Terraform 環境であれば、

terraform import
      ↓
Terraform CLIがStateを更新

という処理になります。

一方、OCI Resource Manager で管理している Stack に対して terraform import CLI を利用する場合は、少し手順が増えます。

Resource Manager が管理している Terraform State は Resource Manager 側に保持されているため、一度 State を取得し、その State に対して terraform import を実行したうえで、更新された State を Resource Manager へ戻す必要があります。

Resource Manager
      ↓
Terraform Stateを取得
      ↓
terraform.tfstate
      ↓
terraform import
      ↓
Terraform CLIがStateを更新
      ↓
更新済みterraform.tfstate
      ↓
Resource Managerへ戻す

つまり、terraform import CLI を利用する場合のポイントは、

Stateを手作業で編集する

ことではなく、

Resource Managerが保持しているStateを
一度外部へ取得して更新し、
再度Resource Managerへ戻す必要がある

という点です。

一方、Terraform 1.5 以降の import block を利用する場合は、Import 操作を Terraform Configuration として記述できます。

import {
  to = oci_core_vcn.example
  id = "ocid1.vcn.oc1.ap-tokyo-1.xxxxx"
}

これを Resource Block と一緒に Resource Manager Stack へ追加し、

Resource Manager Plan
        ↓
Resource Manager Apply
        ↓
Terraform StateへImport

とすることで、Resource Manager の通常の Plan / Apply フローの中で既存リソースを State へ登録できます。

そのため、import block を利用する場合は、

Stateを取得
      ↓
terraform import
      ↓
更新したStateをResource Managerへ戻す

という State ファイルの持ち出し・再Importの工程が不要になります。

この点が、Resource Manager で import block を利用する大きなメリットです。


generate-config-out について

Terraform では、Resource Block を手動で作成せず、既存リソースから Terraform Configuration を生成することもできます。

まず import block を作成します。

import {
  to = oci_core_vcn.example
  id = "ocid1.vcn.oc1.ap-tokyo-1.xxxxx"
}

そのうえで以下を実行します。

terraform plan -generate-config-out=generated.tf

Terraform は Provider から既存リソースの情報を取得し、Resource Block を生成します。

ただし、生成された Configuration はそのまま本番コードとして利用できるとは限りません。

不要な属性の削除や Variable 化、既存 Resource への参照変更など、既存 Stack に合わせた調整が必要です。


OCIでTerraform Configurationを生成する方法

OCI で既存リソースの Terraform Configuration を用意する方法はいくつかあります。

手動で Resource Block を作成

OCI Provider のドキュメントを確認しながら Resource Block を作成する方法です。

リソース数や属性が少ない場合にはシンプルですが、複雑なリソースでは記述量が多くなります。

Cloud Shellで generate-config-out を利用

Cloud Shell 上で Terraform CLI を実行し、

terraform plan -generate-config-out=generated.tf

を利用する方法です。

Code Editor を利用して Terraform ファイルを編集することもできますが、Code Editor と Cloud Shell は別の機能です。

  • Code Editor:ファイルを編集する環境
  • Cloud Shell:CLI コマンドを実行するシェル環境

Code Editor から Cloud Shell のターミナルを起動することもできます。

Resource Discoveryを利用

OCI Resource Manager には、すでにデプロイされている OCI リソースから Terraform Configuration を生成する Resource Discovery が用意されています。

Resource Manager の公式ドキュメントでも、Terraform Configuration を用意する方法として Resource Discovery が案内されています。


今回 Resource Discovery を利用する理由

今回の検証では Resource Discovery を利用します。

Resource Discovery は必須ではありませんが、手動で作成した既存 OCI リソースを Terraform 管理へ移行する場合、Resource Block を一から記述する作業を減らせます。

今回 Resource Discovery を採用する理由は以下です。

  • 既存 OCI リソースから Terraform Configuration を生成できる
  • Resource Block を一から記述する必要がない
  • 実際の OCI リソースの設定をベースに HCL を作成できる
  • 既存リソースの HCL 化を OCI 側へオフロードできる
  • 同様の Import 作業が発生した場合にも手順を再利用しやすい

なお、Resource Discovery は既存リソースをそのまま完全な Terraform コードへ変換する移行ツールではありません。

生成された Terraform Configuration は、既存 Stack に合わせて調整するためのベースとして利用します。


使用方法(デモ)

検証構成

検証構成図は以下の通りです。

なお、以下リソースは作成済みで進めていきます。

  • OCI Resource Manager Stack
  • Terraform 管理外で作成した OCI リソース

architecture.drawio.png

今回の検証では、Terraform 管理外となっているOCI リソースを、既存の Resource Manager Stack へ追加します。

実施する流れは以下です。

① Resource DiscoveryでTerraform Configurationを生成
          ↓
② Resource Blockを既存Stack向けに調整
          ↓
③ Resource Blockを既存Stackへ追加
          ↓
④ import blockを追加
          ↓
⑤ Resource ManagerでPlan
          ↓
⑥ Resource ManagerでApply
          ↓
⑦ 再度Planして差分確認
  • 環境コードは以下 GitHub にあげてますので、よかったら覗いてみてください

Resource Discovery のセットアップ

まず、Terraform 管理下へ取り込みたい OCI リソースの Terraform Configuration を生成します。
今回の検証では、Mac のローカル環境から Resource Discovery を実行します。

Resource Discovery は OCI Terraform Provider の機能として提供されているため、Resource Discovery 実行用として OCI Terraform Provider をローカル環境へ配置します。

また、Resource Discovery は内部で Terraform CLI を利用するため、Terraform CLI が実行できることも前提となります。

早速、OCI Terraform Provider をセットアップしましょう。
MAC の CPU アーキテクチャは以下の通りです。

$ uname -m
arm64

そのため、Apple Silicon 向けの darwin_arm64 を利用します。

利用する OCI Terraform Provider の情報を変数に設定します。

OCI_PROVIDER_VERSION="9.3.0"
OCI_PROVIDER_OS="darwin"
OCI_PROVIDER_ARCH="arm64"
OCI_PROVIDER_TMP_DIR="/tmp/oci-provider"

ダウンロードする ZIP ファイルのパスを設定します。

OCI_PROVIDER_ZIP="${OCI_PROVIDER_TMP_DIR}/terraform-provider-oci_${OCI_PROVIDER_VERSION}_${OCI_PROVIDER_OS}_${OCI_PROVIDER_ARCH}.zip"

一時ディレクトリを作成します。

mkdir -p "${OCI_PROVIDER_TMP_DIR}"

OCI Terraform Provider をダウンロードします。

curl -L \
  -o "${OCI_PROVIDER_ZIP}" \
  "https://releases.hashicorp.com/terraform-provider-oci/${OCI_PROVIDER_VERSION}/terraform-provider-oci_${OCI_PROVIDER_VERSION}_${OCI_PROVIDER_OS}_${OCI_PROVIDER_ARCH}.zip"

ダウンロードした ZIP ファイルを展開します。

展開に成功した場合は、不要になった ZIP ファイルを削除します。

unzip \
  "${OCI_PROVIDER_ZIP}" \
  -d "${OCI_PROVIDER_TMP_DIR}" \
  && rm -f "${OCI_PROVIDER_ZIP}"

展開結果を確認します。

ls -l "${OCI_PROVIDER_TMP_DIR}"

展開した OCI Terraform Provider を /usr/local/bin 配下へ配置します。

sudo mv \
  "${OCI_PROVIDER_TMP_DIR}"/terraform-provider-oci_* \
  /usr/local/bin/

配置された OCI Terraform Provider のパスを変数に設定します。

OCI_PROVIDER_BIN=$(ls /usr/local/bin/terraform-provider-oci*)

取得結果を確認します。

echo "${OCI_PROVIDER_BIN}"

例えば、以下のようなパスが表示されます。

/usr/local/bin/terraform-provider-oci_v9.3.0

Resource Discovery の実行を簡略化するため、OCI Terraform Provider に対して tf-oci のシンボリックリンクを作成します。

sudo ln -sfn \
  "${OCI_PROVIDER_BIN}" \
  /usr/local/bin/tf-oci

作成したシンボリックリンクを確認します。

ls -l /usr/local/bin/tf-oci

必要に応じて OCI Terraform Provider に実行権限を付与します。

sudo chmod +x "${OCI_PROVIDER_BIN}"

Resource Discovery が利用できることを確認します。

Resource Discovery に対応している OCI サービスの一覧を表示します。

tf-oci -command=list_export_services

Resource Discovery に対応している Terraform Resource の一覧を表示します。

tf-oci -command=list_export_resources

list_export_services および list_export_resources は、OCI Provider が対応している Resource Discovery のサービス・リソース一覧を表示するため、この時点では OCI への認証設定は不要です。

実際に OCI 上のリソースを取得する -command=export を実行する際には、別途 OCI の認証設定が必要になります。

Terraform Configuration 生成

Resource Discovery のセットアップが完了したら、実際に OCI 上の既存リソースを検出します。

今回の検証では、OCI CLI のセッション認証を利用します。詳細は以下記事を参考にしてみてください。

今回は、Subnetをインポートします。
OCIDを変数に格納しておきます。

SUBNET_OCID="<subnet-ocid>"

OCI Terraform Provider では、Subnet は以下の Resource Type で管理します。

oci_core_subnet

Subnet は OCID を Import ID として利用できます。

Resource Discovery では複数の Terraform Configuration が生成されます。
そのため、別途出力先ディレクトリを作成しておくと安全です。

DISCOVERY_OUTPUT_DIR="$(pwd)/resource-discovery"

既存の出力が残っている場合に備えて、一度削除してから作成します。

rm -rf "${DISCOVERY_OUTPUT_DIR}" \
  && mkdir -p "${DISCOVERY_OUTPUT_DIR}"

続いて、Resource Discovery がセッション認証を利用できるように環境変数を設定します。

export OCI_AUTH="SecurityToken"
export OCI_CONFIG_FILE_PROFILE="ADMIN"
export TF_VAR_region="ap-tokyo-1"

プロファイル名及びリージョンは適宜変更してください

Resource Discovery では、-ids オプションを利用することで対象リソースを個別に指定できます。

-ids は以下の形式で指定します。

Terraform Resource Type:Resource ID

今回は Subnet のため、以下となります。

oci_core_subnet:<SUBNET_OCID>

準備が整ったので、以下コマンドを実行して Terraform Configuration を生成します。

tf-oci \
  -command=export \
  -ids="oci_core_subnet:${SUBNET_OCID}" \
  -output_path="${DISCOVERY_OUTPUT_DIR}"

生成された Terraform Configuration の確認

Resource Discovery の実行が完了したら、生成された Terraform Configuration を確認します。

今回指定した出力先は以下です。

DISCOVERY_OUTPUT_DIR="$(pwd)/resource-discovery"

生成されたファイルを確認します。

find "${DISCOVERY_OUTPUT_DIR}" -type f

今回 Import 対象として指定した Subnet の Resource Block は、生成された resources.tf から確認できます。

cat "${DISCOVERY_OUTPUT_DIR}/resources.tf"

例えば、以下のような Resource Block が生成されます。

resource "oci_core_subnet" "export_subnet" {
  cidr_block                 = "10.0.1.0/24"
  compartment_id             = "ocid1.compartment.oc1..xxxxx"
  display_name               = "private-subnet"
  prohibit_public_ip_on_vnic = true
  vcn_id                     = "ocid1.vcn.oc1.ap-tokyo-1.xxxxx"
}

生成される属性は、実際の Subnet の設定内容によって異なります。

Resource Block を既存 Stack 向けに調整

Resource Discovery で生成された Resource Block は、そのまま既存 Stack に追加するのではなく、既存 Stack の Terraform Configuration に合わせて調整します。

例えば、Resource Discovery では以下のように OCID が直接記述される場合があります。

resource "oci_core_subnet" "export_subnet" {
  compartment_id = "ocid1.compartment.oc1..xxxxx"
  vcn_id         = "ocid1.vcn.oc1.ap-tokyo-1.xxxxx"

  # ...
}

既存 Stack で Compartment や VCN を Variable や Resource Reference で管理している場合は、それに合わせて変更します。

resource "oci_core_subnet" "private" {
  cidr_block                 = "10.0.1.0/24"
  compartment_id             = var.compartment_id
  display_name               = "private-subnet"
  prohibit_public_ip_on_vnic = true

  vcn_id = oci_core_vcn.main.id
}

このように、Resource Discovery で生成された Terraform Configuration は、完成したコードとしてそのまま利用するのではなく、既存 Stack に取り込むためのベースとして利用します。

主に以下を確認します。

  • Resource Name
  • Compartment の参照方法
  • VCN の参照方法
  • Route Table の参照方法
  • Security List の参照方法
  • Variable
  • Local Values
  • Tag
  • Public / Private Subnet の設定

既存 Stack へ Resource Block を追加

調整した Subnet の Resource Block を、既存 Resource Manager Stack の Terraform Configuration に追加します。

例えば、以下のように main.tf へ追加します。

resource "oci_core_subnet" "private" {
  cidr_block                 = "10.0.1.0/24"
  compartment_id             = var.compartment_id
  display_name               = "private-subnet"
  prohibit_public_ip_on_vnic = true

  vcn_id = oci_core_vcn.main.id
}

Resource Discovery で生成された Resource Block を既存 Stack へ転記したら、resource-discovery 配下の生成ファイルは不要になるため削除します。

rm -rf "${DISCOVERY_OUTPUT_DIR}"
  • 今回は Terraform 実行ディレクトリ配下に resource-discovery ディレクトリを作成しています
  • Resource Discovery の生成物をそのまま Terraform Configuration として利用しない場合は、既存 Stack へ必要な定義を転記した後に削除しておきます

この時点では、Terraform Configuration に Subnet の定義を追加しただけであり、Terraform State には既存 Subnet は登録されていません。

そのため、このまま Plan を実行すると、新規作成対象として認識される可能性があります。

Plan: 1 to add, 0 to change, 0 to destroy.

既存 Subnet を新規作成せずに Terraform 管理下へ取り込むため、次に import block を追加します。

import block を追加

既存 Subnet と、先ほど追加した Resource Block を紐付けます。

import {
  to = oci_core_subnet.private
  id = "ocid1.subnet.oc1.ap-tokyo-1.xxxxx"
}

to には、Import 先となる Resource Address を指定します。

oci_core_subnet.private

id には、既存 Subnet の OCID を指定します。

Subnet は OCID を Import ID として利用できます。

Resource Block と import block を合わせると、以下のようになります。

import {
  to = oci_core_subnet.private
  id = "ocid1.subnet.oc1.ap-tokyo-1.xxxxx"
}

resource "oci_core_subnet" "private" {
  cidr_block                 = "10.0.1.0/24"
  compartment_id             = var.compartment_id
  display_name               = "private-subnet"
  prohibit_public_ip_on_vnic = true

  vcn_id = oci_core_vcn.main.id
}

Resource Manager Stack を更新

Resource Block と import block の追加が完了したら、Terraform Configuration を既存 Resource Manager Stack へ反映します。

Stack の更新後、通常通り Plan Job を実行します。

Plan では、対象の Subnet が新規作成ではなく Import 対象として認識されていることを確認します。

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

意図しない変更や削除、再作成が発生していないことを確認したうえで、Apply Job を実行します。

Apply が完了すると、既存 Subnet が Resource Manager の Terraform State に登録されます。

oci_core_subnet.private
        ↓
ocid1.subnet.oc1.ap-tokyo-1.xxxxx

最後に再度 Plan を実行し、差分がないことを確認します。

Plan: 0 to add, 0 to change, 0 to destroy.

これで、Terraform 管理外で作成した既存 Subnet を、OCI Resource Manager の管理下へ取り込むことができました。


おわりに

今回は、OCI Resource Manager で管理している既存 Stack に対して、Terraform 管理外の OCI リソースを取り込む方法について整理しました。

今回のポイントは、Terraform 1.5 以降の import block を利用することで、既存リソースの Import を Resource Manager の通常の Plan / Apply フローに組み込めること です。

従来の terraform import CLI でも既存リソースを State へ登録できます。

この場合、State ファイルそのものを手作業で編集する必要はなく、terraform import が State を更新します。

ただし、Resource Manager で管理している Stack に対して利用する場合は、

Resource ManagerのStateを取得
        ↓
terraform import
        ↓
Terraform CLIがStateを更新
        ↓
更新したStateをResource Managerへ戻す

という State の持ち出し・再Importが必要になります。

一方、import block を利用すれば、

Resource Block
        +
import block
        ↓
Resource Manager Plan
        ↓
Resource Manager Apply

という通常の Terraform ワークフローで既存リソースを管理下へ取り込めます。

さらに今回は Resource Discovery を組み合わせることで、

既存OCIリソース
      ↓
Resource Discovery
      ↓
Terraform Configuration生成
      ↓
既存Stack向けに調整
      ↓
import block
      ↓
Resource Manager Plan / Apply

という形にしました。

Resource Discovery は必須ではありませんが、手動作成された既存 OCI リソースを Terraform 化する際の HCL 記述を省力化できます。

既存環境を Terraform 管理へ移行する場合は、Import そのものだけでなく、Import 後に Terraform Configuration・Terraform State・実リソースの状態を一致させることが重要です。

Apply 前後の Plan を確認し、意図しない変更・削除・再作成が発生しないことを確認しながら進めるのがよいと思います。


🌟この記事が誰かの役に立てば幸いです!
また、ご質問やフィードバックもお待ちしています。


番外編

import block と terraform import の違い

項目 import block terraform import
Import の定義場所 Terraform Configuration CLI
Stateの更新 Apply 時に Terraform が更新 terraform import 実行時に Terraform CLI が更新
Stateの手動編集 不要 不要
Plan で Import 内容を事前確認 可能 Import 自体は CLI から直接実行
Import 定義をGit管理 可能 不可
Resource Managerでの利用 通常の Plan / Apply フローに載せられる Resource Manager の State を取得・更新・再Importする必要がある

Terraform Configurationを用意する方法の違い

方法 特徴
手動でResource Blockを作成 シンプルだが、複雑なリソースでは記述負荷が高い
Cloud Shell + -generate-config-out Terraform標準機能で既存リソースからHCLを生成できる
Resource Discovery OCIの既存リソースからTerraform Configurationを生成できる

本記事では Resource Discovery を利用しています。

Code EditorとCloud Shellの違い

項目 Code Editor Cloud Shell
主な用途 コード編集 CLI実行
Terraformファイル編集 ○ ○
terraform コマンド実行 ターミナルとしてはCloud Shellを利用 ○
oci コマンド実行 ターミナルとしてはCloud Shellを利用 ○

参考資料

リファレンス

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?