2017-12-24

terraform import heroku_appはできたけど…使い方が悩ましい

まとめ

  • とりあえず terraform init と import の使い方が分かった
  • terraform init 超重要
  • terraform v 0.11.1 で heroku_app と heroku_addon の import できた
    • 安易に import からやれば練習が早くできると思ったけどそういうわけじゃなかった
  • import はあくまで .tfstate の更新であり、これと矛盾しない .tf を書いておかないと diff が plan と apply を阻害する
  • 話題が少ないのでもしかしてと思っていたけど Heroku と Terraform は相性が悪いというか、考え方が被ってて混ぜるな危険かも
  • Heroku は heroku コマンドとか API か wrap した何かを用意した方がよさげ

目標

  • Terraform を CI で回してクラウドインフラを管理

以下、試してみた。

Provider を使うには plugin のインストールが必要

  • Provider が本体から plugin 管理されるようになった ( v 0.10 ) 
  • init した際に .tf を認識して自動的に plugin をインストールしてくれる
  • 逆に言うと import で始める前に provider の情報を理解していないといけない

↑ つらい

provider.heroku: no suitable version installed
 version requirements: "(any version)"
 versions installed: none

みたいなエラーが出たら init してあげるとよい。

initしたディレクトリ/.terraform

以下に plugin が入る。

credentialの与え方

基本的な resource 定義

HCL 全般のメモではありません。以下の import に必要な分だけ。

resource <type> <name> {
  id   = <id>
  name = <name>
  ...
}
  • <> で囲んだ部分は基本的には文字列
  • type は Provider の中で定義されている。
  • type と name の組み合わせは unique である必要がある
    • 例えば Heroku の app について扱いたければ resource type は "heroku_app"

Configuring Resources - Terraform by HashiCorp

import

terraform import TYPE.NAME ID

で import を行う。この際、

  • TYPE は Provider で決まっているが NAME は任意に設定可能
  • ID も Provider によって決まる

ので、NAME と ID を合わせておくと管理しやすそう。

Heroku

  • email と api key で動く
  • plugin があれば .tf を元に import して .tfstate を作成することはできる(v0.11.1)

terraform の heroku_app resource は dyno の定義などはできないみたい。おまけに取得した環境変数が全部入りで、add-on の定義によって自動でセットされる場合は .tfstate とぶつかっちゃう。

調べても話題が少ないのでもしかしてと思っていたけど、どうも Heroku と Terraform は相性が悪いというか、考え方が被ってて混ぜるな危険なのかもしれない。

※そうなると Heroku を含むすべてのインフラを自動管理しようと思うと Terraform 一本やりというわけにはいかず、工夫が必要。

heroku_app

heroku_app resource では heroku の app name と terraform resource の id は同じになる。

example では

resource "heroku_app" "default" {
  name   = "my-cool-app"
  region = "us"
}

こんな風になっているが、ここで resource syntax 上の name と argument の name は一致させておいた方が管理しやすいように思う。例えば

resource "heroku_app" "lt-timer" {
  name    = "lt-timer"
  resgion = "us"
}

みたいな感じにしておくと

terraform import heroku_app.lt-timer lt-timer

で import できる。コマンド打っているときは重複に見えてアレだけど、変に名前を付けて管理を複雑にするよりはマシなのではないか。

Heroku: heroku_app - Terraform by HashiCorp

ただし、add-on の追加によって自動設定される環境変数の値はともかく、リリース情報とかまで全部環境変数に乗って取得できてしまっている。例えば以下のような感じ。

"all_config_vars.%": "23",
"all_config_vars.HEROKU_RELEASE_VERSION": "vxxx",
"all_config_vars.HEROKU_SLUG_COMMIT": "xxxxxxxxxxx",
"all_config_vars.HEROKU_SLUG_DESCRIPTION": "Deploy xxxxxxx",

これはさすがに困る。仮に .tfstate をもとに次回以降の apply をするのであれば、もはや deploy すらできないことを意味するのではないか。一方で

heroku apps:info --json

では普通に取得できる Dyno の情報は .tfstate に乗ってこない。

 "dynos": [
   {
     "attach_url": null,
     "command": "bundle exec unicorn -p $PORT -c ./config/unicorn.rb",
     "created_at": xxxxxxxx,
     "id": xxxxxxx,
     "name": "web.1",
     "app": {
       "id": xxxxxx,
       "name": xxxxx
     },
     "release": {
       "id": xxxxxx,
       "version": xxxx
     },
     "size": "Standard-1X",
     "state": "up",
     "type": "web",
     "updated_at": xxxxxxxxx
   },
   {
     "attach_url": null,
     "command": "bundle exec sidekiq -C config/sidekiq.yml",
     "created_at": xxxxxx,
     "id": xxxxxxxx,
     "name": "worker.1",
     "app": {
       "id": xxxxxxxxx,
       "name": xxxxxxxx
     },

それでいて heroku_dyno という resource type があるわけでもない。つまり Dyno の管理は Terraform ではできないということになる。

以下のように Heroku と AWS S3 を使ったよくあるサイトを Terraform で作るよ、という情報はあるのだが、継続してアプリを成長させていく際のインフラ管理を Terraform 一本でやるのは難しそうに見える。

Using Terraform to Build Heroku/S3 Site - Ficksworkshop

heroku_addon

id は add-on の識別名 ( papertrail-xxxxx-xxxxx など ) になる。import の際に必要なだけだろう、たぶん。これを取得するには Web コンソールか heroku コマンドなどが必要。

heroku apps:info --json

とか。

Heroku: heroku_addon - Terraform by HashiCorp

AWS IAM Role And Policy

IAM Roleの権限不足なのか、とりあえず今回は確認できなかった。

今後

  • Herokuの管理の自動化はterraformよりはherokuコマンドやAPIを真面目に使う方がよさそう
    • 当然本家なのでなんでもできるんだけど、状態を把握しやすくし、diff だけで副作用が分かる、って状態じゃないのが課題。
  • AWSの方の準備を進める
    • 自動化用の IAM ユーザーと credential を作成
    • いったん静的サイト方面の resource を中心に
    • Terraform 用の backend bucket を作成

以上のようなところが今後の課題っぽい。自動化しようと思ったら backend を remote に用意しておかないと複数人で回す際に .tfstate が一本化されずに安定動作しないということらしい。

※ CI で回す気まんまんなんだけど、さすがに CI の cache に期待するのはスジが悪いだろうな…。

参考

About

例によって個人のなんちゃらです