Tech Sketch Bucket of Technical Chips by TIS Inc.

Terraformを使う!「Terraformからherokuアプリを操作する際のハマりどころ」

Pocket

前回はTerraformからのherokuアプリ操作をお知らせしました。
第四回はTerraformを利用してherokuアプリを操作する際にハマった所について書いて行きたいと思います。

Terraformの基本的な操作は 第一回の記事
Terraformからherokuアプリの操作は 第三回の記事
ご参照ください。

ハマりどころ①「Herokuアプリの作成とHerokuドメインの作成を同時に行うとエラーになる」

Terraformの設定ファイル(.tf)にHerokuアプリとHerokuドメインを同時に記載する場合、
Terraformに順守した書き方をしないとエラーが発生し、「Herokuアプリは作成されるがドメインが割り当てられていない」状態が発生してしまいます。

このエラーはTerraformの計画時には検出することが困難です。
実際にどのような状況になるか試してみます。

設定ファイル作成

設定ファイルを作成していきます。
設定ファイルの内容は3つに分かれていて

  • Herokuアクセス情報(Configure the Heroku provider)
  • Herokuアプリ情報(Configure a Heroku app)
  • Herokuドメイン情報(Configure a Heroku domain)

の情報が記載されています。

この例では
tis-super-app01という名前のHerokuアプリを作成し、
tis.terraform.example.comというドメインを割り当てています。

作成物(Heroku app)に対して何らかの割当て(Heroku domain)を同時に実行されるように記載がされている場合、ドメインが割り当てられずエラーとなります。

次に計画をしていきます。

計画

上記で作成した設定ファイルを計画します。

計画を見ると
20行目でHerokuアプリ名として"tis-super-app01"が割り当てられ
28行目で"tis-super-app01"に対してHerokuドメインとして"tis.terraform.example.com"に割り当てる計画内容です。

計画時にはエラーと判別出来るような情報は見えません。次に実行してみます。

実行

実際に実行してみると9行目に「Error applying plan:」と表示されエラーとなってしまいました。
「Couldn't find that app.」と出ていることからドメインを割り当てるHerokuアプリが見つからないと言われています。

ただし、実際にHerokuの管理画面を見てみるとtis-super-app01が正常に作成されています。

WS002.JPG

しかしドメインは割り当てられておりません。

WS003.JPG

エラーではHerokuアプリが見つからないと表示されていますが、
Heroku管理画面ではHerokuアプリが存在することは確認できています。
もう一度設定ファイルを変えずに計画・実行をするとどうなるのでしょうか。

実際にやってみます。

計画(2回目)

計画内容を確認すると既存のHerokuアプリ名"tis-super-app01"に対してドメインを追加しようとしています。
内容自体にはおかしな点は見当たらないので実行してみます。

実行(2回目)

8行目の"Apply complete!"メッセージから正常に処理が完了したことがわかります。
Herokuの管理画面で確認してみましょう。

WS005.JPG

無事にドメインが追加されました。
ではなぜ初回の実行時には処理がエラーになったのでしょうか。

原因を探って行きます。

エラーの確認

Heroku上に作成したアプリを削除し、設定ファイルはそのままで計画と実行を再度行います。
Terraformのソースを読むと分かりますが、実行時に「TF_LOG=」を指定することによって詳細なログを得ることが出来ます。

計画時には有用なログは得られなかったため、省略させて頂きます。

実行(ログ表示)

12行目付近でアプリの作成とドメインの作成(設定)を同じタイミングで実行していることがわかります。
今回のエラーの原因としては、アプリ・メインの作成が同時に実行されることにより、Heroku上へHerokuアプリが作成されていない状態でドメインを割り当てようとしていることが原因でした。

二回目の実行時にはHerokuアプリが既に存在しているために処理が正常終了したのであると推察できます。

解決方法

今回の原因はHerokuアプリの作成を待たずにHerokuドメインの割り当てが実行されてしまうことにありました。

解決策としては「depends_on」機能を利用しHerokuドメインにHerokuアプリとの依存関係を持たせ作成を待機するよう設定するか、Terraformが提供している書式を利用することでエラーを回避することが可能です。

依存関係を考慮した設定ファイル

「depends_on」を利用した設定ファイル

18行目に「depends_on = "heroku_app.tis_app01"」を指定しました。
設定する値は「TYPE.NAME」の形式で記載します。

依存関係を記載することによってアプリの作成を待ってからドメインの設定を行う挙動になります。
次に計画・実行を行いますが計画の出力は初回に実行した結果と相違ないため省略します。

Terraformが提供している書式を利用した設定ファイル

Heroku domainを指定する部分の値であるHeroku app名を変数で指定しています。(18行目)
このようにすることによってHeroku domainを設定する際に変数として値が入るまで待機する挙動をとります。

Terraformが提供している書式を利用する場合「depends_on」のオプションは不要です。
Heroku domain部分で変数としてHeroku appを呼んでいるので暗黙的に依存関係を考慮して動作します。

本記事では「depends_on」を利用した例で進めますが、変数を使った書式でも同様の結果が得られます。

実行

8行目でHerokuアプリが作成され、
9目でドメインが割り当てられています。

12行目に「Apply complete!」と出力されていることから処理が正常に完了したことが確認できます。

冒頭で実行した際にはエラーとなりましたが、依存関係を設定することで無事正常終了となりました。
「depends_on」はTerraformがサポートする全てのプロバイダで設定ファイルに記載できるので覚えておくと便利です。

ハマりどころ②「TerraformよりHerokuドメインの変更時にエラーが出る」

2つ目のハマりどころは変更時の挙動です。
事象としては作成したHerokuアプリと紐付いているHerokuドメインのセットに対して
Herokuドメインを変更しようとした場合にエラーになり、Herokuドメインが変更出来ないというものです。

どのような挙動になるか実際に見ていきます。

新規作成

まずは変更の元となるHerokuアプリとHerokuドメインを作成します。
ここではエラーは発生しません。

設定ファイル作成

この例では
tis-super-app01という名前のHerokuアプリを作成し、
Herokuアプリの作成完了を待ってからtis.terraform.example.comというドメインを割り当てています。

これは正常に動作しますので手短に、次に計画と実行を行います。

計画・実行

まずは計画します。

次に実行です。

無事に作成ができました。

heroku_error01.JPG heroku_error02.JPG

変更

先で作成したHerokuアプリのドメイン情報を変更します。
こちらも計画時点では発覚しづらいために注意が必要です。

変更時にエラーが発生しますので詳しく見て行きましょう。

設定ファイル編集

設定ファイルで変更した部分は「hostname」を"domain.a.example.com"から"domain.b.example.com"へと変更しました。
次に計画していきます。

計画

計画時点では18行目で「hostname」が"domain.a.example.com" から "domain.b.example.com"へ変更されると読み取れます。
その他特にエラーになることが推察出来る情報は見受けられません。

実際に実行してエラーを確認してみます。

実行

実行時にエラーが発生しました。8行目のエラー内容をみてみるとドメインが見つからないと言われています。
Heroku上はどうなっているのでしょうか、確認してみます。

heroku_error01.JPG heroku_error03.JPG

アプリは存在しているようですが、ドメインが割りあたっていません。
念のためにもう一度計画してみます。

計画(エラー後)

今度は計画もエラーとなってしまいました。
エラー内容は実行時と変わらずドメインが見つかりませんと表示されています。

この状態になると削除も変更も出来ないので手動でHerokuアプリを破棄するか
環境ファイルを削除するしかありません。

原因

このエラーの原因はTerraform側の環境ファイルとHeroku側の実態に不整合が発生しているために起こります。
今回の新規作成・変更処理で何が起きたかを説明しやすくするため図を用意しましたので御覧ください。

図1.png

既存変更

既存変更する際の流れを説明します。

Ⅰ. 設定ファイルの読み込みを行います。
  この際に新規追加時に作成されている環境ファイルとの比較を行い、追加・変更の判定がおこなれます。
Ⅱ. 変更時の挙動になりますので既存作成物を破棄する命令をHerokuへ投げます。
Ⅲ. 明示的に削除するのはHeroku appですが、紐付いているHedoku domainも同時に削除されてしまいます。
Ⅳ. 設定ファイルの記載内容にしたがってHeroku appを新たに作成する命令をHerokuへ投げます。
Ⅴ. Heroku appが作成されます。ここではまだHeroku domainは作成されません。
Ⅵ. Heroku domainを"変更"する命令をHerokuへ投げます。
Ⅶ. Heroku domain [A]をHeroku domain [B]へ変更しようとするのですが、
  Ⅴ.で作成したHeroku appしか存在しないためHeroku domain [A]を見つけることが出来ずにエラーを返します。
Ⅷ. Herokuからのエラーを受け取り、エラーで処理を終了します。
  正常に終了した場合には環境ファイルを更新しますが、途中で処理が終わるため環境ファイルは既存変更処理開始時のままです。

既存変更処理が終わった時、Heroku環境の状態とTerraform環境の設定ファイルの状態には差異が出来ています。

  • 処理終了時の差異
Heroku app 情報Heroku domain 情報
Terraform環境ファイルHeroku app [A]Heroku domain [A]
Heroku環境Heroku app [A]null

この状態になってしまうと以降計画や実行を行う時に、
Terraformが行う最初の情報比較でHeroku domain 情報部分が不一致となりエラーが返されます。

情報不一致によるロック解消法

ロックを解消するためにはTerraform環境ファイルを削除すればロックは解消されます。

環境ファイルが削除されてもHeroku上には作成されたHeroku app [A]が存在しています。
再度同じファイルで実行する時にはHeroku app [A]が存在することにより同じ名称のHeroku appを作成できません。
合わせてHeroku環境に存在しているHeroku app [A]を消しておきましょう。

エラー事前回避(終わりに)

このエラーは事前回避がとても難しいです。
それはTerraform計画時の出力でハンドリング出来ないためです。

事前回避するためには利用者がTerraformの仕組みを知っておくことが必要です。
Terraformで行う変更は既存作成物を破棄して新規作成する場合があるということを頭に入れて運用しなければなりません。

TerraformではこのようなバグのFixや新機能の追加をものすごいスピードで行なわれています。
執筆時ではVer0.1.1だったのが2014/09/08現在すでにVer0.2.1がリリースされており、いくつかの BugFixや新機能の追加 がされています。

今回ご紹介した様な気をつけなければならない部分もありますが、Terraformの改善スピードと利便性はそれを上回り利用価値があると私は思います。

エンジニア採用中!私たちと一緒に働いてみませんか?