Terraform v0.7が誘う「Infrastructure as Code」の世界

Terraform_for_さくらのクラウド

複数のクラウドプラットフォーム上のリソース/インフラをコードで管理できるTerraformというオープンソースのプロダクトがあります。

このTerraformですが、近日中におよそ1年ぶりとなる大型アップデート(v0.7)が予定されています。
今回のアップデート(v0.7)では、すでに存在するリソース/インフラをTerraform管理下に取り込める「import」機能が追加されます。

本稿では「Terraform + さくらのクラウド」という構成で、すでに手作業で作成済みのリソース/インフラをTerraformにインポート、構成変更を行うまでを実践を通じてご紹介いたします。

ごあいさつ

みなさま、はじめまして。山本 和道(やまもと かずみち)と申します。
フリーのWeb系エンジニアをやっています。オープンソース活動として、さくらのクラウド関連ツールの開発をしております。
これまでDockerMachine さくらのクラウド用ドライバやさくらのクラウド用Go言語ライブラリ「Libsacloud」などを開発しました。
今後、主に仮想化関連ツールのご紹介をさせていただく予定です。どうぞ、よろしくお願い致します。

Terraformのご紹介

Terraformとは

Terraformとは、Hashicorp社によるオープンソースプロダクトです。
(Hashicorpといえば、Vagrant/Serf/Consulなどの開発を行っている会社です。)

Terraformは一言で言うと「インフラストラクチャのためのプロビジョニングツール」です。

Terraformの特徴

以下のような特徴があります。

  • AWS/Azure/さくらのクラウドなど、複数のプラットフォームに対し統一的な手法でプロビジョニングが行える
  • HCLというJSONライクな言語で定義を記載する
  • インフラの状態をファイルとして保持することで、あるべき姿への収束(コンバージェンス)が行える

Terrafrom全体図

利用例

簡単な例として、AWS上にEC2インスタンスを作成する場合、以下のような流れになります。

1) 定義ファイルを作成します。

provider "aws" {
    access_key = "ACCESS_KEY_HERE"
    secret_key = "SECRET_KEY_HERE"
    region = "us-east-1"
}

resource "aws_instance" "example" {
    ami = "ami-0d729a60"
    instance_type = "t2.micro"
}

2) 「terraform」コマンドを実行します。

# リソースの作成(定義の適用)
$ terraform apply

HCLというJSON風の言語で定義ファイルを作成し、「terraform」コマンドで各種操作を行います。

このように定義をコード化しておくことにより、バージョン管理、モジュール化、変数の切り出しといったコーディングのノウハウをインフラ定義(運用)に応用することが可能となってきます。

Terraformはその他にも様々な機能を持っています。
Terraformを使い始める際は公式サイトのスタートガイドを一通り試すことをお勧めいたします。

Terraform プラグインの紹介

Terraformはプラグイン機構を備えており、Terraformが未対応のプラットフォームでもプラグインを用意することで対応させることが出来ます。

さくらインターネットのサービスについては以下の2つのプラグインを開発しました。

本稿では「Terraform for さくらのクラウド」を用いた例を後述いたします。

それぞれの入門記事を以下に投稿しておりますので、こちらもあわせてご参照ください。

Terraform v0.7の新機能

本稿の執筆時点では未リリースなのですが、近日中に大型アップデートであるv0.7のリリースが予定されています。
v0.7では次のような機能追加/変更が行われています。

  • 参照専用リソースである「Data sources」の追加
  • モジュールへのList/Map変数渡し
  • state管理用のコマンド追加
  • 「import」コマンドの追加

(その他の変更や変更内容の詳細についてはGitHub上のCHANGELOGに記載されています。)

中でも「import」コマンドについては「Terraformで作成したリソースしか管理できない」という、これまでのバージョンに存在した課題を克服する、まさしく目玉といえる機能です。

以降ではTerraformとTerraform for さくらのクラウドを実際に動かしてみます。
既存のリソース/インフラに対しての「import」コマンドの実施を通じて「Infrastructure as Code」を体験してみましょう。

実践

本稿では「import」機能の紹介として、実際にさくらのクラウド上に作成済みのリソースのインポートを行っていきます。

Terraform入門的な基本操作や定義ファイル記載方法などは説明しませんので、以下の入門記事などを参考してください。

なお、以降ではMac(OSX)上での作業手順を記載しております。
Linux/Windowsでも実行可能ですので、各自の環境に合わせて適宜読み替えてください。

インストール/初期設定

まずは「Terraform」と「Terraform for さくらのクラウド」のインストールを行います。
本稿ではTerraform最新版であるv0.7を用いますが、現時点では正式リリースされていないため、
RC版を直接ダウンロードすることでインストールを行います。

Terraform v0.7 RC版のインストール

ダウンロード

ビルド済みのRC版バイナリはHashicorp社のサイトで公開されており、以下のURLからダウンロード可能です。

https://releases.hashicorp.com/terraform/

本稿の執筆時点での最新バージョンは「terraform_0.7.0-rc3」です。
プラットフォームごとにファイルが分かれておりますので、適切なzipファイルをダウンロードしてください。

展開

ダウンロードしたら、パスの通った場所に置くか、任意の場所に置いてパスを通しておいてください。

動作確認

コンソールなどから「terraform --help」と実行し、以下のような表示がされたらインストールは正常に行えています。

$terraform --help
usage: terraform [--version] [--help]  [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    destroy            Destroy Terraform-managed infrastructure
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initializes Terraform configuration from a module
    output             Read an output from a state file
    plan               Generate and show an execution plan
    push               Upload this Terraform module to Atlas to run
    refresh            Update local state file against real resources
    remote             Configure remote state storage
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version

All other commands:
    state              Advanced state management

 

Terraform for さくらのクラウドのインストール

ダウンロード

Terraform for さくらのクラウドについては以下のURLからダウンロード可能です。

https://github.com/yamamoto-febc/terraform-provider-sakuracloud/releases/

本稿の執筆時点での最新バージョンは「v0.3.5」です。
プラットフォームごとにファイルが分かれておりますので、適切なzipファイルをダウンロードしてください。

展開

ダウンロードしたら、terraformバイナリを配置しているのと同じディレクトリに配置してください。

APIキーの準備

さくらのクラウドのコントロールパネルからAPIキーを発行しておきます。
Terraform for さくらのクラウド インストールガイドを参考に発行してください。

発行したら以下のように環境変数に設定しておきましょう。

$ export SAKURACLOUD_ACCESS_TOKEN=[取得したAPIトークン]
$ export SAKURACLOUD_ACCESS_TOKEN_SECRET=[取得したAPIシークレット]
$ export SAKURACLOUD_ZONE="tk1v" # 対象ゾーンをtk1v(SandBox)に設定

ここで設定した環境変数は後ほどterraformコマンド実行時に利用されます。


TIPS:Terraformへのクレデンシャルの指定方法について

Terraformへクレデンシャルを指定する方法として以下のようなものがあります。

  • 定義ファイル(tfファイル)に直接書く
  • terraformコマンドへのオプションとして指定する
  • 環境変数を利用する

本稿では環境変数を用いています。その他の方法についてはTerraform公式ドキュメントを参照してください。


作業用ディレクトリの作成

Terraformのリソース定義ファイルを格納するディレクトリを作成しておきます。
任意の名前で作成してください。

$ mkdir ~/terraform_on_sakuracloud
$ cd ~/terraform_on_sakuracloud

以上で準備完了です。いよいよTerraformを実際に動かしてみましょう。

既存リソースのインポート

既にさくらのクラウド上に作成済み、稼働中のサーバーをTerraformにインポートします。

今回は以下のようなリソースをさくらのクラウドのコントロールパネル上から作成しておき、それをインポートしてみます。

Terraformでインポートするサンプルリソースの構成図

インポートするリソースは以下の3つです。

  • 1: スイッチ
  • 2: ディスク
  • 3: サーバー

インポート手順

インポートは以下の手順で行います。

  • 1) importコマンド実施
  • 2) 定義ファイルの作成

importコマンドが成功すると、対象のリソースがTerraform管理下に置かれます。
ただし、インポート直後は対象リソースの定義ファイルが手元にない状態です。

Terraformでは管理下のリソースを定義ファイルで定義内容へ向けて収束(コンバージェンス)させようとするため、「定義ファイルがない = 削除すべきリソース」と判断してしまいます。

このため、インポート後は現状のリソースの状態に合わせて定義ファイルを作成してあげる必要があります。


TIPS:定義ファイルの自動生成はできないの?

現状のTeraffromでは残念ながら既存のリソースから定義ファイルを自動生成する機能はありません。

外部ツールとして「Terraforming」という定義ファイルを生成してくれるツールはあるのですが、AWS限定であるため利用できる場面は限られます。

Terraformの次バージョン以降に期待しましょう。


インポート実施

1: スイッチのインポート

importコマンド実施

importコマンドは以下の書式となっています。

importコマンド書式
$ terraform import [options] ADDR ID

「terraform import」の後にリソースのアドレス(ADDR)とリソースIDを指定します。
リソースのアドレスとはTerraformドキュメント「TERRAFORM INTERNALS」に記載があるもので、「リソースのタイプ名.リソースID」の形です。

今回インポートするスイッチはリソースIDとして「switch01」を割り当てることとします。
この場合、リソースのアドレス(ADDR)は「sakuracloud_switch.switch01」となります。

IDは各リソースともコントロールパネルに記載されているものを指定します。

それでは実行してみましょう。

importコマンド実施
$ terraform import sakuracloud_switch.switch01 [スイッチのID]

エラーがなければ以下のような表示になります。

実行例

スイッチのインポート例1


TIPS:importコマンドは何をしているの?

importコマンドは以下のような処理を行っています。

  1. 指定されたリソースのアドレスとIDを元に対象プロバイダへAPI呼び出し
  2. リソースが見つかったら状態ファイル(terraform.tfstate)を作成

import後はカレントディレクトリに「terraform.tfstate」というファイルが作成されています。

このファイルは状態ファイルと呼ばれるもので、Terraformが認識しているリソースの状態を示すものです。Terraformはこのファイルと定義ファイル、実際のリソースの状態を比較することで対象リソースに対する作成/変更/削除などのどの操作をすべきか判定しています。


定義ファイル作成

続いてインポートしたスイッチ用の定義ファイルを作成します。
定義ファイルに記載するため、スイッチの情報をコントロールパネルなどから確認しておきましょう。
今回インポートするスイッチの情報は以下の通りです。

インポート対象のスイッチ情報

スイッチ用定義ファイル作成
$ vi switch.tf
スイッチ用定義ファイル(switch.tf)
# スイッチの定義
resource sakuracloud_switch "switch01"{
    name = "switch01"
    tags = ["tag1" , "tag2"]
}

各リソースの定義ファイルに記載する項目については設定リファレンスの「リソース」項目も参照してください。

インポート結果と定義ファイルの差異確認〜定義ファイル修正

インポートした結果と定義ファイルに差異がないか、「terraform plan」コマンドで確認してみましょう。

$ terraform plan
実行例(インポート結果と定義ファイルに差異がある状態)

スイッチのインポート例2

リソースが黄色表示されています。これは変更される予定のリソースがあるという表示です。

ここでは、スイッチの「description」列が

  • インポート結果では「"description1"」
  • 定義ファイルでは「""」(未定義のため空文字)

という差異があることを示しています。

定義ファイルを修正して再度確認してみましょう。

修正後スイッチ用定義ファイル(switch.tf)
# スイッチの定義
resource sakuracloud_switch "switch01"{
    name = "switch01"
    tags = ["tag1" , "tag2"]
    description = "description1" #追記
}
実行例(定義ファイル修正後)

スイッチのインポート例3

差異がなくなりましたね。

この、実際のリソース/インフラと定義ファイルとの間で差異がない状態がTerraformで目指すべき状態となります。


TIPS:実際のリソースと定義ファイルとの間に差異が出る場合とは?

以下のような場合に差異が出ます。

  • 定義ファイルを変えたのに未反映
  • 定義ファイルを変えてないのに実際のリソース/インフラが変更されている

通常時は差異がない状態を保つようにしましょう。


2: ディスクのインポート

続いてディスクのインポートを行います。

importコマンド実施

スイッチの場合と同じように「terraform import」を実施してインポートしましょう。
ディスクのリソースIDは「disk01」を割り当てます。

importコマンド実施
$ terraform import sakuracloud_disk.disk01 [ディスクのID]
実行例(ディスクのインポート)

ディスクのインポート例

定義ファイル作成

以下のように定義ファイルを作成します。

ディスク用定義ファイル作成
$ vi disk.tf
ディスク用定義ファイル(disk.tf)
# ディスクの定義
resource sakuracloud_disk "disk01"{
    name = "server01"
}

定義ファイルへの記載内容が非常に少ないですが、
先ほどのスイッチの場合と同じく、後で「terraform plan」を実行し、差異があれば追記していく形をとればOKです。

もちろん最初から定義ファイルをある程度書いても良いですが、
「terraform plan」の結果を見ながら定義ファイルを記載するのが楽だと思います。

インポート結果と定義ファイルの差異確認〜定義ファイル修正

$ terraform plan
実行例(差異の確認)

ディスクplan確認例

差異はないですね。差異がない場合はもちろん定義ファイルの修正は不要です。

3: サーバーのインポート

続いて、サーバーのインポートを行います。

importコマンド実施

サーバーもこれまで同様に「terraform import」を実施してインポートします。
サーバーのリソースIDは「server01」を割り当てます。

importコマンド実施
$ terraform import sakuracloud_server.server01 [サーバーのID]
実行例(サーバーのインポート)

サーバーインポート例

定義ファイル作成

続いて定義ファイルの作成をしましょう。定義ファイルは以下のようになります。

サーバー用定義ファイル作成
$ vi server.tf
サーバー用定義ファイル(server.tf)
# サーバーの定義
resource sakuracloud_server "server01"{
    name = "server01"
}

インポート結果と定義ファイルの差異確認〜定義ファイル修正

先ほどと同じように「terraform plan」コマンドで差異を確認してみましょう。

インポート結果の確認と差異確認
$ terraform plan
実行例(差異の確認)

サーバーplan実行例1

今回は差異がたくさん出ましたね。差異は配列要素に対してのため、要素数/要素の値それぞれで差異が表示されています。
実際には以下の3つの項目に差異があるということです。

  • additional_interfaces : 2枚目以降のNICの接続先スイッチIDを指定する項目
  • disks : サーバーに接続するディスクのIDを設定する項目
  • tags : サーバーに付与するタグを設定する項目

定義ファイルを以下のように修正しましょう。

修正後サーバー用定義ファイル(server.tf)
# サーバーの定義
resource sakuracloud_server "server01"{
    name = "server01"
    additional_interfaces = ["${sakuracloud_switch.switch01.id}"] # switch01のID
    disks = ["${sakuracloud_disk.disk01.id}"] #disk01のID
    tags = ["@virtio-net-pci"]
}

スイッチのID、ディスクのIDについては「${xxxxx}」という書き方を用いていますね。

これはTerraformでの「埋め込み記法(The interpolation syntax)」というもので、他のリソースの値や変数などの値を参照して埋め込むことが可能です。

埋め込み記法の詳細についてはTerraform公式ドキュメントを参照ください。

実行例(差異の確認)

サーバーplan実行例2

差異がなくなりました。これでインポート完了です。

ここまでで、すでにさくらのクラウド上に存在していたリソースをTerraformの管理下に置くことができました。

実際にTerraformを運用する際は、この時点で定義ファイルなどをgitなどのバージョン管理システムにコミット(チェックイン)しておくことをお勧めいたします。

では、インポートしたリソースに対し、コードを起点に構成変更してみましょう。

リソースの構成変更

構成変更は以下の手順で行います。

  • 1) 定義ファイルの変更
  • 2) 「terraform plan」で変更内容のレビュー
  • 3) 「terraform apply」で反映

今回はサーバーのCPUコア数とメモリの割り当てを増やしてみましょう。

注意:以下の手順ではサーバーの再起動が行われます。
実際に稼働中のサーバーで実施する際は十分にお気をつけください。

1) 定義ファイルの変更

定義ファイルを修正しましょう。定義ファイルは以下のようになります。

サーバー用定義ファイル作成
$ vi server.tf
サーバー用定義ファイル(server.tf)
#サーバーの定義
resource sakuracloud_server "server01"{
    name = "server01"
    additional_interfaces = ["${sakuracloud_switch.switch01.id}"] # switch01のID
    disks = ["${sakuracloud_disk.disk01.id}"] #disk01のID
    tags = ["@virtio-net-pci"]
    core = 4    #追記
    memory = 16 #追記
}

2) 「terraform plan」で変更内容のレビュー

「terraform plan」コマンドで変更内容を確認してみましょう。

変更内容の確認
$ terraform plan
実行例

リソース変更実行例

CPUコア数とメモリが変更予定となっています。

3) 「terraform apply」で反映

それでは適用してみましょう。適用は「terraform apply」コマンドです。

定義の適用
$ terraform apply
実行例(定義の適用)

リソース変更適用例

コントロールパネルからも確認してみましょう。

リソース変更をコントロールパネルからも確認

定義ファイルで記載した通りにCPUコア数とメモリが増えていました。

以上で構成変更完了です。

まとめ

本稿では以下の内容を扱いました。

  • Terraform v0.7での「import」機能が追加された
  • 手作業で作成した既存リソースでもインポートできる
  • インポートには「terraform import」コマンドを使う
  • インポートした後は定義ファイルを作成する
  • インポート後はTerraformの定義ファイルを用いて構成管理できる

これからリソース/インフラを作成する新規案件はもちろんですが、
すでに手作業で構築済みのリソース/インフラでも本稿の手順でコード化することができます。

新規案件でなくても導入しやすくなったTerraform v0.7で「Infrastructure as Code」へ是非チャレンジしてみてください。