タグ: AWS

53ningen.com 大改修

 学生時代に適当に構築してツギハギだらけになっていた 53ningen.com が動いているサーバー gomi-old01 を良き形にしつつ gomi-web01 に移転した作業ログです。基本的にただ WordPress が動いていたサーバーを Ansible 化して、お引越ししたというだけの内容ではあります。やったことは具体的にはつぎのようなものです。

  1. DNS サーバーの Route 53 移行
  2. ドメインの Route 53 移管
  3. 稼働しているサーバーの Ansible 化
  4. データベースの引越し
  5. WordPress アプリケーションの引越し
  6. 新サーバーへ DNS 切り替え

また次のものは新規で導入しました

  • L7 レイヤーでのヘルスチェック導入
  • 障害発生時に DNS フェイルオーバーでエラー画面を表示

  • サーバーログの S3 への送出

  • elasticsearch, kibana
  • zabbix による監視, Slack 通知

1. DNS サーバーの Route 53 移行

 ドメインも Route 53 に移管しますが、その際に元のレジストラ(ムームードメイン)が提供するネームサーバーからドメインが削除されてしまうので、前もって DNS を Route 53 に切り替えておきます。

1.1. ホストゾーン(Hosted Zone)の作成

公式ドキュメント: 既存ドメインの DNS サービスを Amazon Route 53 に移行する

 ホストゾーンとはドメインに紐づくリソースレコードのセットです。おおよそゾーンファイルと対応していると考えて良いと思います。実際にゾーンファイルを取り込むこともできるようです(公式ドキュメント: ゾーンファイルをインポートしてリソースレコードセットを作成する)。

 ホストゾーンには、パブリックなものとVPC向けのプライベートなものがあります。マネジメントコンソールからドメイン名を入力すれば作成が完了しますが、今回はこのリソースを terraform で管理します。

terraform plan は以下のとおり

 terraform apply してホストゾーンを作成すると SOA レコードNS レコード も自動的に作成されます。今回はドメイン名とIPアドレスを紐づけるために A レコード の追加が必要になります。そのため、その記述を追加します。メールサーバーの移行が必要であれば MX レコード、サブドメインなどの運用をやっているのであれば CNAME レコード など適当な感じに必要なものも移行しておきましょう。ひとまず今回は A レコード のみを作ります(Route 53 が対応しているDNSリソースは サポートされる DNS リソースレコードタイプ を参照)。terraform apply を実行するとレコードが作成されます。

1.2. DNSの変更

 マネジメントコンソールの NS レコード欄の DNS サーバーを、ムームードメインのコントロールパネルで指定します。反映が有効になるまで少し(TTL分)時間がかかるため、少し待って dig で確認すると良いとおもいます。

1.3. コストの計算

公式ドキュメント: 料金

 お仕事ならこの計算作業する前にやるべきですが、個人のお遊びサーバーなので作業後に計算しました。

  • ホストゾーン
    • 0.50 USD(ホストゾーンごと)/月 – 最初の25のホストゾーン
    • 0.10 USD(ホストゾーンごと)/月 – それ以上のホストゾーン
  • 標準的クエリ
    • 0.400 USD(100 万クエリごと) – 最初の 10 億クエリ/月
    • 0.200 USD(100 万クエリごと) – 10 億クエリ以上/月

おおよそ 1ホストゾーン + 最初の10億クエリ = 0.50 + 0.40 = 0.90 USD

1.4. ヘルスチェックの設定 (Optional)

公式ドキュメント: Amazon Route 53 ヘルスチェックの作成と DNS フェイルオーバーの設定

 ヘルスチェック(L7)とDNSフェイルオーバーが利用できます。ヘルスチェックで障害を検知した場合に Cloudwatch Alarm と連携をさせたり、DNSフェイルオーバーを利用して待機系に参照を向けたりすることが可能です。

 ひとまずベーシックなウェブサーバーのヘルスチェックは以下のように設定できます。その他諸々 terraform を利用する際にオプション記述については terraform 公式ドキュメント: aws_route53_health_check を参照してください。

ヘルスチェックに関しては、

  • AWSエンドポイント
    • ヘルスチェック 1 件につき 0.50 USD*/月
    • オプション機能 1 件につき 1.00 USD/月
  • AWS以外のエンドポイント:
    • ヘルスチェック 1 件につき 0.75 USD*/月
    • オプション機能 1 件につき 2.00 USD/月
  • 任意のヘルスチェック機能は以下の通りです。
    • HTTPS
    • 文字列マッチング
    • 短インターバル
    • レイテンシー計測

となっています。

「AWS エンドポイント」とは、AWS の中で稼働するリソース(たとえば Amazon EC2 インスタンス)のうち、ヘルスチェックと同じ AWS アカウントの中でプロビジョニングされるか、ヘルスチェックと同じアカウントが請求先となっているものを指します。計算済みヘルスチェックとメトリクスベースのヘルスチェックは AWS エンドポイントのヘルスチェックとして請求されます。Elastic Load Balancing のリソースまたは Amazon S3 ウェブサイトバケットがエンドポイントであるヘルスチェックについては、お客様への請求は発生しません。Elastic Load Balancing のリソースおよび Amazon S3 ウェブサイトバケットをエンドポイントとするヘルスチェックについては、AWS によって自動的にプロビジョニングされ、Amazon Route 53 の一部として追加料金なしでご利用いただけます。

1.5 DNSフェイルオーバーの設定 (Optional)

公式ドキュメント: DNS フェイルオーバーの設定
terraform 公式ドキュメント: aws_route53_record

 ヘルスチェックを入れたついでに、障害発生時に S3 の静的ホスティング機能 + Cloudfront によるメンテナンスページのほうへ参照を向けるようなDNSフェイルオーバー設定を入れてみます。DNSフェイルオーバー設定については無料で利用することができます。最終的な構成図は以下のような形になります。


 
 ディザスタリカバリを想定した構成として、ap-northeast-1 リージョンで稼働させるアプリケーションサーバーに対して、メンテナンスページを静的ホスティングする際の S3 リージョンは地理・物理的に違う系統の適当なリージョンを選択します。今回は us-east-1 を選択しました。

 S3 の前段に置いた Cloudfront は主に S3 からの配信をキャッシュする役割と、メンテナンスを表すステータスコード 503 でリソースを返す役割を持っています。S3 バケットの作成とファイルの配置、静的ホスティング機能の有効化および Cloudfront の設定は以下のように terraform で記述することができます。

terraform 公式ドキュメント: aws_s3_bucket
terraform 公式ドキュメント: aws_cloudfront_distribution

resources/error には、適当なメンテナンス表示 html ファイルを、 policies/maintenance.53ningen.com_s3_policy.json には以下のようにバケットのファイルの読み取りを許可するポリシーを配置します。

つづいて Route 53 ホストゾーンにフェイルオーバーの設定をします。通常時は既存の A レコードが有効になるようにしつつ、ヘルスチェックに失敗した場合にメンテナンスページを静的にホスティングしている S3 のほうに参照を向けるような設定を入れます。また ttl を最初の設定より短く 60 秒に変更します。 terraform を用いて次のように記述できます。

 最後に動作確認として、動いているウェブサーバーを停止し、きちんとメンテナンス表示に切り替わるか確認します。またウェブサーバーを起動したときに、ヘルスチェックが通るようになり、きちんとアプリケーションサーバーに参照が戻るかも合わせてチェックしておきましょう。

2. ドメインの Route 53 移管

公式ドキュメント: ドメインの移管

ムームードメインで購入した 53ningen.com ドメインを Route 53 に移管します。ステップとしては以下のとおりです。

  1. WHOIS 情報としてレジストラの情報を代理公開している場合は、ムームードメインのコントロールパネルから自分のものに変更する
  2. 確認のメールが飛んでくるので踏む
  3. AUTH_CODE をメモ
  4. Route 53 の Domain registration から Transfer Domain to Route 53 に進みドメイン名を入力
  5. AUTH_CODE を入力
  6. 移管後のDNSとして先ほど作った Route 53 の Hosted Zone を指定する
  7. AWSから移管確認のメールが飛んでくるので踏む
  8. そのうち移管が完了する

Waiting for the current registrar to complete the transfer (step 7 of 14)
ドメインが移管の要件を満たしているか現在のレジストラが確認しています。このステップは、ドメインの TLD に応じて最大 10 日かかる場合があります。

結構待ったりいろんな確認メールのリンクを踏んだりする必要がありますが、あまりテクニカルな手順はないはず…。

3. 稼働しているサーバーの Ansible 化

地道に頑張るしかない。

4. データベースの引越し

まずは新サーバーで動いている MariaDB へのデータ移行と参照の切り替えを行うことにより、データベースサーバーのみを引っ越しします。手順は大まかに次のとおりです。

  1. 現行 DB の dump を取り、新 DB にインポートする
  2. アプリケーションから参照する MariaDB ユーザーに現行サーバーからの接続許可を与える
  3. TCP 3306 ポートを開ける
  4. 現行アプリケーション設定を書き換えて新 DB に向ける
  5. 動作確認

まずは現行 DB からのデータ移転作業は以下のような感じになります。

続いて、アプリケーションが接続する mysql のユーザーの作成と設定をします。現行アプリケーションサーバーからの接続を許可する設定を入れる必要があります。ansible で次のようなものを実行します。

またリモートからの接続をするために firewalld を設定して 3306 ポートを開けます。

最終的に現行アプリケーション設定 wp-config.php を書き換えて新 DB に向き先を切り替えます。

最後に動作確認をひと通りして、問題なさそうであればデータベースの引っ越しは完了となります。

5. WordPress アプリケーションの引越し

おおまかな手順は以下の通りです。

  1. 現行 WordPress の配置ディレクトリごと tar で固める
  2. 新サーバーに固めたものを展開して、適切なパスに配置する
  3. wp-config.php をの DB_HOSTlocalhost に戻す
  4. nginx の設定を更新し、外から WordPress の動作を確認できるようにする
  5. /etc/hosts を書き換え、新サーバー上の WordPress が正しく動いているか動作確認

WordPress アプリケーションの圧縮と展開は次のようなコマンドで簡単に行えます。。

 次に、直前の DB 参照切り替えで WordPress の設定を変えているので、新サーバー内に配置した WordPress の wp-config.phpDB_HOST 設定は localhost に向けなおします。これが終わったら、nginx.conf を更新して外部から動作確認できる状態にします。ざっくりと例えば次のように記述すれば OK です(その他各位適切な設定をいい感じにしてください)。

最後に、手元 /etc/hosts に以下を追記してひととおりアプリケーションの動作を確認します。

動作確認して問題がなければ WordPress の移行も完了になります。

6. DNS 切り替え

Route53 に登録している Aレコードの向き先を変更して、新サーバーに完全移行します。移行して動作に問題がなさそうであれば、MariaDB の gomi-old01 から接続できるユーザーを削除し、firewalld で 3306 ポートを閉じておきます。

Route53 で S3 バケットへ alias レコードを作った際のリダイレクトのふるまい

 Amazon S3 は、全てのリクエストをリダイレクトや、パスに応じたリダイレクトを設定できる機能を持っています。これは Static Web Hosting という設定を入れることにより実現可能です。実際の技術詳細については以下の公式ドキュメントを参照してください。

  • 公式ドキュメント: https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html

リダイレクト設定

gochiusa.53ningen.com に対して gochiusa.com へのリダイレクト設定作業は以下の 3 STEP です

  1. S3 バケットを gochiusa.53ningen.com という名前で作成する
  2. Static Web Hosting 機能を有効にして、すべてのリクエストを gochiusa.com にリダイレクトする設定を入れる
  3. Route 53 に gochiusa.53ningen.com に対して先ほど作ったバケットへのエイリアスを張る A レコードを作成する

動作確認

作業後、設定を dig で確認します

解決される 52.219.68.26 は S3 の静的配信サーバーの IP の模様で、振る舞い的には Host ヘッダと同じ名前を持つ S3 バケットへリダイレクトをかけるという形のようです。それを確認するために次のようなリクエストを送ってみます。

x-amz-error-message: Request does not contain a bucket name. というメッセージからわかるようにバケットネームの指定がないというエラーで AWS S3 のトップページに飛ばされます。次に Host ヘッダをつけるとどうなるか試してみましょう。

The specified bucket does not exist というエラーメッセージに変わりました。ではそろそろ真面目に先ほど作った gochiusa.53ningen.com という値を Host ヘッダにつけて叩いてみましょう。

正常に 301 で http://gochiusa.com/ にリダイレクトされていることが確認できました。

実験からわかること

  1. S3 バケットへの alias レコードセットの制約の理由が推測できる
    • Route53 で S3 static web hosting しているバケットに alias を張る際は、公式ドキュメントに記載されているように Record Set の Name と S3 バケット名が一致している必要がある
    • これは Host ヘッダをみて、対象の S3 静的配信コンテンツへのリダイレクトを行なっている仕組みから生まれる制約だろうということが、上記の実験から分かる
  2. S3 バケットへの alias を張っているドメインを指す CNAME を張ると正常に動作しない
    • 実際に gochiusa2.53ningen.com に対して gochiusa.53ningen.com を指すような CNAME レコードセットを作ると以下のような実験結果になる

Route53へのDNSとドメインの移行

次のものを AWS に移行しました。

  • ドメイン移管(53ningen.com): ムームードメインから Route 53 へ
  • ドメインネームサーバー移行: ムームードメインから Route 53 へ

また、もとの運用では存在しなかった、次のようなものを導入しました。

  • L7レイヤーでのヘルスチェック
  • DNSフェイルオーバー

この資料は自分向けの作業ログであるため、実際には各ステップ冒頭に記された公式ドキュメントを理解した上で読むことを強く推奨します。

手元環境

 作業は基本的には terraform を使って行いました。ただし、ドメインの移管に関しては Route 53 のマネジメントコンソールとムームードメインのコントロールパネルを操作する必要があります。

1. DNS を Route 53 へ移行

 ドメインも Route 53 に移管しますが、その際に元のレジストラ(ムームードメイン)が提供するネームサーバーからドメインが削除されてしまうので、前もって DNS を Route 53 に切り替えておきます。

1.1. ホストゾーン(Hosted Zone)の作成

公式ドキュメント: 既存ドメインの DNS サービスを Amazon Route 53 に移行する

 ホストゾーンとはドメインに紐づくリソースレコードのセットです。おおよそゾーンファイルと対応していると考えて良いと思います。実際にゾーンファイルを取り込むこともできるようです(公式ドキュメント: ゾーンファイルをインポートしてリソースレコードセットを作成する)。

 ホストゾーンには、パブリックなものとVPC向けのプライベートなものがあります。マネジメントコンソールからドメイン名を入力すれば作成が完了しますが、今回はこのリソースを terraform で管理します。

terraform plan は以下のとおり

 terraform apply してホストゾーンを作成すると SOA レコードNS レコード も自動的に作成されます。今回はドメイン名とIPアドレスを紐づけるために A レコード の追加が必要になります。そのため、その記述を追加します。メールサーバーの移行が必要であれば MX レコード、サブドメインなどの運用をやっているのであれば CNAME レコード など適当な感じに必要なものも移行しておきましょう。ひとまず今回は A レコード のみを作ります(Route 53 が対応しているDNSリソースは サポートされる DNS リソースレコードタイプ を参照)。terraform apply を実行するとレコードが作成されます。

1.2. DNSの変更

 マネジメントコンソールの NS レコード欄の DNS サーバーを、ムームードメインのコントロールパネルで指定します。反映が有効になるまで少し時間がかかるため、少し待って dig で確認すると良いとおもいます。

1.3. コストの計算

公式ドキュメント: 料金

 お仕事ならこの計算作業する前にやるべきですが、個人のお遊びサーバーなので作業後に計算しました。

  • ホストゾーン
    • 0.50 USD(ホストゾーンごと)/月 – 最初の25のホストゾーン
    • 0.10 USD(ホストゾーンごと)/月 – それ以上のホストゾーン
  • 標準的クエリ
    • 0.400 USD(100 万クエリごと) – 最初の 10 億クエリ/月
    • 0.200 USD(100 万クエリごと) – 10 億クエリ以上/月

おおよそ 1ホストゾーン + 最初の10億クエリ = 0.50 + 0.40 = 0.90 USD

1.4. ヘルスチェックの設定 (Optional)

公式ドキュメント: Amazon Route 53 ヘルスチェックの作成と DNS フェイルオーバーの設定

 ヘルスチェック(L7)とDNSフェイルオーバーが利用できます。ヘルスチェックで障害を検知した場合に Cloudwatch Alarm と連携をさせたり、DNSフェイルオーバーを利用して待機系に参照を向けたりすることが可能です。

 ひとまずベーシックなウェブサーバーのヘルスチェックは以下のように設定できます。その他諸々 terraform を利用する際にオプション記述については terraform 公式ドキュメント: aws_route53_health_check を参照してください。

ヘルスチェックに関しては、

  • AWSエンドポイント
    • ヘルスチェック 1 件につき 0.50 USD*/月
    • オプション機能 1 件につき 1.00 USD/月
  • AWS以外のエンドポイント:
    • ヘルスチェック 1 件につき 0.75 USD*/月
    • オプション機能 1 件につき 2.00 USD/月
  • 任意のヘルスチェック機能は以下の通りです。
    • HTTPS
    • 文字列マッチング
    • 短インターバル
    • レイテンシー計測

となっています。

「AWS エンドポイント」とは、AWS の中で稼働するリソース(たとえば Amazon EC2 インスタンス)のうち、ヘルスチェックと同じ AWS アカウントの中でプロビジョニングされるか、ヘルスチェックと同じアカウントが請求先となっているものを指します。計算済みヘルスチェックとメトリクスベースのヘルスチェックは AWS エンドポイントのヘルスチェックとして請求されます。Elastic Load Balancing のリソースまたは Amazon S3 ウェブサイトバケットがエンドポイントであるヘルスチェックについては、お客様への請求は発生しません。Elastic Load Balancing のリソースおよび Amazon S3 ウェブサイトバケットをエンドポイントとするヘルスチェックについては、AWS によって自動的にプロビジョニングされ、Amazon Route 53 の一部として追加料金なしでご利用いただけます。

1.5 DNSフェイルオーバーの設定 (Optional)

公式ドキュメント: DNS フェイルオーバーの設定
terraform 公式ドキュメント: aws_route53_record

 ヘルスチェックを入れたついでに、障害発生時に S3 の静的ホスティング機能 + Cloudfront によるメンテナンスページのほうへ参照を向けるようなDNSフェイルオーバー設定を入れてみます。DNSフェイルオーバー設定については無料で利用することができます。最終的な構成図は以下のような形になります。


 
 ディザスタリカバリを想定した構成として、ap-northeast-1 リージョンで稼働させるアプリケーションサーバーに対して、メンテナンスページを静的ホスティングする際の S3 リージョンは地理・物理的に違う系統の適当なリージョンを選択します。今回は us-east-1 を選択しました。

 S3 の前段に置いた Cloudfront は主に S3 からの配信をキャッシュする役割と、メンテナンスを表すステータスコード 503 でリソースを返す役割を持っています。S3 バケットの作成とファイルの配置、静的ホスティング機能の有効化および Cloudfront の設定は以下のように terraform で記述することができます。

terraform 公式ドキュメント: aws_s3_bucket
terraform 公式ドキュメント: aws_cloudfront_distribution

resources/error には、適当なメンテナンス表示 html ファイルを、 policies/maintenance.53ningen.com_s3_policy.json には以下のようにバケットのファイルの読み取りを許可するポリシーを配置します。

つづいて Route 53 ホストゾーンにフェイルオーバーの設定をします。通常時は既存の A レコードが有効になるようにしつつ、ヘルスチェックに失敗した場合にメンテナンスページを静的にホスティングしている S3 のほうに参照を向けるような設定を入れます。また ttl を最初の設定より短く 60 秒に変更します。 terraform を用いて次のように記述できます。

 最後に動作確認として、動いているウェブサーバーを停止し、きちんとメンテナンス表示に切り替わるか確認します。またウェブサーバーを起動したときに、ヘルスチェックが通るようになり、きちんとアプリケーションサーバーに参照が戻るかも合わせてチェックしておきましょう。

2. ドメインを Route 53 に移管する

公式ドキュメント: ドメインの移管

ムームードメインで購入した 53ningen.com ドメインを Route 53 に移管します。ステップとしては以下のとおりです。

  1. WHOIS 情報としてレジストラの情報を代理公開している場合は、ムームードメインのコントロールパネルから自分のものに変更する
  2. 確認のメールが飛んでくるので踏む
  3. AUTH_CODE をメモ
  4. Route 53 の Domain registration から Transfer Domain to Route 53 に進みドメイン名を入力
  5. AUTH_CODE を入力
  6. 移管後のDNSとして先ほど作った Route 53 の Hosted Zone を指定する
  7. AWSから移管確認のメールが飛んでくるので踏む
  8. そのうち移管が完了する

Waiting for the current registrar to complete the transfer (step 7 of 14)
ドメインが移管の要件を満たしているか現在のレジストラが確認しています。このステップは、ドメインの TLD に応じて最大 10 日かかる場合があります。

結構待ったりいろんな確認メールのリンクを踏んだりする必要がありますが、あまりテクニカルな手順はないはず…。

ES2015+Flowなlambda関数をApexで管理する

ES2015 + 型チェッカー flow で書かれた AWS Lambda 関数を Apex で管理する方法について、つらつらとメモ。この記事は @nagisio 先生のご指導のおかげで成立しています(謝辞)。

  • キーワード
    • AWS Lambda
    • yarn
    • ES2015
    • flow
    • Apex

記事読むの面倒くさいので、動くリポジトリよこせという方はここをcloneすべし(動かしてから理解する方が楽なのですよねー :wakaru:)

ES2015 + flow + Apex の環境構築

yarn の導入

導入はかんたん。

  1. npm initpackage.json を作る
  2. npm install yarn --dev で yarn を導入する
    • global に入れたい方はどうぞ

package.json はきっとこんな感じになっているのではなかろうか

ESS2015 + flow の環境構築

まずは必要なものを片っ端からいれていく

次に .babelrc を次のようにする

node_modules/flow-bin/cli.js init でflow の設定ファイル .flowconfig を作り、以下のような感じにする

もう多分この時点で ES2015 + flow のコードが書けるので適当に src/hello/index.js に適当なコードを書いてみよう

続いてトランスパイルして functions 下に成果物を出力してみよう

成果物は次のようになっているだろう

良い感じにハローワークに行きたいくなる良いラムダ関数ですね。さて、ここまできたらあとは Apex を導入して AWS にデプロイするだけです。

ちょっとその前に、トランスパイルするコマンドが長ったらしくてだるいのでエイリアスを張っておきましょう。package.json の script の部分をちょちょいといじるといい感じに npm run build で諸々実行できます。

Apex の導入

今回 AWS Lambda 関数の管理には Apex をつかいます。Apexの挙動は非常に単純で project.json に指定されたリソースやタイムアウト時間、IAMロールの設定で、functions直下にある各ディレクトリをそれぞれラムダ関数とみなし、デプロイしてくれます。

導入はかんたん

project.json をイカのよう設定すればよいでゲソ(各自IAMロールは適切なものを指定してください)

apex deploy でデプロイできます。apex invoke hello で実行できます。

良い

ESLint の導入(お好みで)

ESLintを入れたい方は適当に必要そうなやつをどうぞ(適当)

.eslint を適当に書く

deploy 前に uglify の処理を入れる

lambda の起動時間は多分デプロイされる成果物のサイズが小さい方がはやいので、uglifyをかけたほうがよさそう。packaage.jsonを書き換えればいい感じに実現可。

npm run build:prod で functions 下にできる成果物を確認してみるとちゃんとできてるか確認出来る。

ステージ管理

このあたりの対応が一番筋がよさそう? Lambda with Apex: 環境変数で環境別にLambda環境を整える

おわりに

ES2015 + flow + Apex で快適な AWS Lambda ライフを!

terraform を使ったAWS構成管理 ハンズオン

terrafrom は、インフラの構築や設定などをコードで表現して管理できるようにするツールです。AWS や Azure、 Heroku など様々な環境に対応しています。

この資料はラビットハウス社内で開催される、 AWS リソースを terrform で管理するためのハンズオン向けに作成した資料になります。AWS 構成管理をコードで管理したいなどと思っている方のなかにも、こういったツールが面倒臭そうだとか、すぐ使えなくなってしまいそうだとお思いの方が多いかと思いますが、 terraform の挙動はとてもシンプルで学習コストはものすごい低いツールです。また AWS 構成をコード化することでより深く AWS について理解することできる側面もあると考えています。

是非この機会に terraform に入門してみませんか…? この記事の通りにコマンドを入力していけば、きっとあなたも1時間もしないうちに terraform を使いこなせるようになっているでしょう。

1. 環境構築

このハンズオンでは terraform v0.7.4 を前提として話を進めます

Mac の場合

Windows の場合

https://www.terraform.io/downloads.html

AWS 側の準備

あらかじめterraformで用いるIAMユーザーを作成しておきましょう

  1. IAM ユーザー管理ページにアクセス
  2. 新規ユーザーの作成
  3. 必要なポリシーのアタッチ
  4. access_key, secret_key の作成

2. S3 bucket を管理する

まずは S3 bucket を作ったり変更したり壊したりして遊んでみましょう。下準備として、適当な作業用ディレクトリを作成してください。次に AWS リソースにアクセスするための設定を書きます。

2-1. S3 bucket を作る

早速 S3 bucket を作ってみましょう。次のようなファイルを作成してください。ただし bucket の名称はグローバルで一意になるように定めてください。

以上のようなファイルを作ったら、terraform validate で正しい .tf ファイルを記述できているかを確認してみましょう。きっと上記の通りに書けば問題なくコマンドが通ると思います。

つづいて terraform plan コマンドで、これからどのようなことが実行されるのかを確認します。この操作は常に安全で、AWSに対して情報の読みとり操作しか行われません。

+ aws_s3_bucket.terraform_tutorial とあるように S3 の bucket が作成されることが確認出来たので terraform apply コマンドで実際に実行してみましょう。

無事、成功したようですので、とりあえず aws cli から s3 bucket が本当に存在するのか確認してみましょう。

ちゃんと s3.tf ファイルで指定した com.github.53ningen.terraform.tutorial という名前の bucket ができていることがわかります。さて、terraform apply が無事に成功したあとには terraform.tfstate というファイルができていると思います。

このファイルの中身はリモート(今の場合AWS)の状態を保存するファイルになります。この中にはアクセスキーやシークレットキーがふくまれているため、git 管理対象外にしておきましょう。このファイルの管理についてはのちほど 「remote state の管理」の節でご説明します。とりあえず以下のような .gitignore ファイルを追加しておきましょう。

2-2. S3 bucket の状態を変更する

さきほど作った S3 bucket はバージョニングが有効になっていますが、これを無効にしてみましょう。s3.tf を次のように修正します。

続いて terraform validate コマンドで tf ファイルのシンタックスを検証し、 terraform plan で AWS リソースに対してどうのような変更が行われるか確認しましょう。

Plan: 0 to add, 1 to change, 0 to destroy. とあるので、既存の S3 は削除されず、表示されたパラメータのみが変更されることがわかります。確認をしたら apply をすれば S3 の状態の変更は完了です。

2-3. S3 bucket を破棄する

さて、いままでチュートリアルとして S3 bucket を作成してきましたが、不要なので削除しておきましょう。terraform destroy コマンドを使えば OK ですが、この操作もやはり実行する前に確認しておきたいものです。そんな場合はまず terraform plan --destroy を実行してみましょう。これで terraform destroy 時の実行計画を見ることができます。

実行計画に問題がなさそうであれば、terraform destroy を実行してみましょう。

terraform destroy を実行すると本当にリソースを削除して良いのか聞かれます。yes と入力すると、ここまでに作った S3 bucket は削除されます。

2-4. tf ファイルをフォーマットする

terrform fmt でファイルをフォーマットできます

2-5. terraform 基本コマンドのまとめ

以上で terraform の基本的な 5 コマンドは理解できたかと思います。まとめると以下のようになります。

  • terraform validate: .tf ファイルのシンタックスを検証する
  • terraform plan: terraform がこれから行う実行計画を表示する。--destroy オプションで destroy 時の実行計画を表示できる。
  • terraform apply: plan を実行する。
  • terraform destroy: terraform で作ったリソースを破棄する
  • terraform fmt: tfファイルをフォーマットする

基本的には apply の前にかならず plan で実行計画を確認することを徹底してください。 destroy は実際にはほとんど使うことはないと思います。また、terraform.tfstate を git で管理したり、他人の目に触れるような状態にすることをお忘れなく。

3. remote state を管理する

terraform.tfstate ファイルはリモートの状態を管理するファイルです。apply が成功すると、どのようなリソースがどのようなパラメータで作成されたのかを細かく記録しています。

tfstate ファイルを誤って削除すると terraform はリモートにリソースが存在しないと認識して、tf ファイルに定義された構成を新規作成しようとしてしまいます。しがって何らかの形で、このファイルを管理する必要があるのですが、秘匿情報が多分に含まれているため単純に git で管理するわけにはいきません。

管理する方法は何通りかあるのですが、ここでは private な S3 bucket を使ってこのファイルを管理する方法をご紹介します。

3-1. tfsate管理用 S3 bucket の作成

S3 bucket の作成は前節でやったのでもうきっと理解できていると思います。復習がてらやってみましょう。remote_state.tf という名前で次のようなファイルを作ってみましょう。

terraform plan で実行計画を確認したのち、terraform apply で bucket を作成します。terraform 公式ドキュメントによると versioning を有効にすることが推奨されています。

3-2. tfstate管理設定を行う

無事 S3 bucket が作成されたら terraform remote config コマンドを使って tfstate ファイルの管理設定を行います。次のコマンドの bucketaccess_key などは自分のものに適宜変更してください。

ここで key というのは S3 上でどのような名前で tfstate ファイルを管理するかという指定になります。今コマンドが無事通るとカレントディレクトリにあった terraform.tfstate はきっと .terraform 下に移動するかと思います。

3-3. remote に tfstate を push する

さて、管理設定が無事おわったら S3 に tfstate ファイルを転送しておきましょう。

リモートへの terraform apply を行った場合は必ず terraform remote push を行いましょう。

3-4. remote から tfstate を pull する

普通にいかのような感じになります。複数人での開発で、他人が apply したあとの remote state を反映させたい場合などに使います。

4. より高度なリソース定義を行う

4-1. 変数を用いる

aws の access_keysecret_keyvariable.tf に直接書き込んでいますが、変数という機能を使えば、実行時に指定することができます。

このようにした上で、terraform plan を実行すると各パラメータとしてどの値をとるかを対話式に尋ねられます。

また、次のように変数のデフォルト値を指定しておくこともできます。

4-2. 環境変数を用いる

CLIから access_keysecret_key を毎回指定するのも面倒なので、環境変数を用いると楽そうです。terraform では TF_VAR_ というプレフィックスがついた環境変数を .tf ファイルの中で用いることができます。さっそく、これを用いて access_key, secret_key を環境変数から取ってくるように変更しましょう。

続いて variable.tf を以下のように変更しましょう

terraform plan を変数指定なしで利用できるようになっていれば、無事環境変数の利用ができているということになります。

4-3. 依存管理のあるリソース定義を行う

より複雑なリソースを構成するときには、リソース同士に依存関係が生じます。たとえば terraform で作成した IAM ユーザーにポリシーをアタッチしたいときに、リソース間に依存が生じていると思います。

いま、 IAM ユーザー cocoa さんを作成し IAMReadOnlyAccess ポリシーをアタッチしたいとします。その場合の .tf ファイルは以下のように記述すればOKです。

terraform plan を実行すると依存関係が解決されていることがわかるでしょう。

4-4. 設定ファイルを使う

複雑なリソースを管理するときには設定だけをまとめた設定ファイルが使えると便利そうです。 terraform には設定ファイルを使う仕組みも備わっています。今回は AWS のリージョン指定を設定ファイルに切り出しましょう。variable.tfregion 変数から default 値を削除してください。

そして config.tfvars という名前で次のように設定を記述しましょう。

あとは terraform planterraform apply 時に設定ファイルを指定してあげればOKです。設定ファイルの指定は -var-file= オプションを使います。

4-5. 出力を行う

terrform apply 後に作成されたリソースのARNが知りたい場合などは output という機能を使うとよいでしょう。たとえば先ほど作成した cocoa ユーザーのARNを出力させるには次のようにすれば OK です。

terraform plan, terraform apply を実行してみましょう

しっかりと ARN が出力されていることが確認できます。

5. モジュールと複数のステージへの対応

terraform はカレントディレクトリに置かれている .tf ファイルを実行するというとても単純なふるまいを持っています。しかし複数ディレクトリに構造化してファイルを保存したい場合や、複数のステージを作るためにパラメータだけ変えて呼び出したいなどさまざまに理由により、異なるディレクトリ下にあるものを呼び出したいことがあるでしょう。そのときに使えるのが、モジュールという機能です。

5-1. モジュールの利用の基礎

モジュールを試すためにまずは以下のようなディレクトリ構造を作りましょう。

modules に それぞれのリソースを定義していくことになります。今回はサンプルとして dev/prod 向きそれぞれの S3 bucket を作ってみましょう。まずは modules/s3/s3.tf の中身から。

続いて dev/modules.tf, prod/modules.tf というファイルにそれぞれ、modules/s3 以下のファイルを取り込んで実行するコードを書いてみましょう。modules という新たな構文を利用します。

最後に、dev/variable.tf, prod/variable.tf に対して、AWS を操作する設定値などを記述します。

これで準備が整いました。dev ディレクトリ下から実行すると dev 環境向けの構成、prod ディレクトリ下から実行すると prod 環境向けの構成を管理することができます。 dev 環境向けのリソースを実際に作ってみましょう。 dev ディレクトリに移動して、terraform get を実行して依存モジュールのコードを取り込みを前もってやっておく以外は、いままでと基本的には同じ操作で OK です。

5-2. 複数ステージへモジュールを用いたの対応例

このようなモジュールの機能を用いて dev や production など複数のステージ向けにデプロイできるように更生する場合、ディレクトリ構造として特に決まっているものはないのですが、優れたものとして以下のような形があるので、参考にしながら進めると良いと思います。

6. 既存のAWSリソースを terraform で管理する

6-1. terraforming の導入

terraforming は既存のAWSリソースにアクセスしてterraformのコードを生成してくれたり、tfstateを生成してくれたりするツールです。導入は Gemfile に次のように書いて、bundle install すればOKです。

6-2. 既存の IAM user を terraform で管理する

AWSアカウントを持っているほぼ全ての人は、すでに IAM user などのリソースを持っていると思います。従って、まずここを terraform で管理する形にしましょう。次のようにすると現在のIAM userリソースに応じたHCLが出力されます。

これをファイルに書き出しましょう。

またリモートの状態を手元の .tfstate ファイルに反映させるなければ、terraform はリソースを新規に作成しようとしてしまいます。そのために以下のようにしておきましょう。

terraforming iamu --tfstate --profile default --merge=.terraform/terraform.tfstate

出力をみて問題なさそうであれば、このコマンドに --overwrite オプションを付加して反映させます。こののちに terraform plan をして差分がでなければ、晴れて IAM user の管理を terraform に移行できたことになります。

terraform plan 時にもしも、 destroy されるリソースが表示されたとしたら、既存のリソースやシステムが破壊される可能性がありますので、特に慎重に操作してください。また、IAM policy などについては JSON の改行位置やインデントなどが差分として出やすいので、悩んだときはそのあたりが既存のポリシー設定と食い違っていないか確認することをお勧めします。

さて、terraforming はよく使われるほとんどの AWS リソースに対応しているため、まずはこれを使ってできるところまで terraform に移行すると良いでしょう。v0.7.0 では以下のようなものに対応しています。

6-3. terraform のコードを管理するリポジトリを作成する

個人アカウントのaws構成をopenなgithub repositoryに配置するのは、はばかられるので code commit リポジトリを作成しておくと良いでしょう。

code commit 上に作成したレポジトリにアクセスするためポリシーのアタッチ、ならびに公開鍵登録も terraform を使って行うことができます。

この状態で terraform plan, terraform apply をしてみます

すると以上のように作成された ssh_public_key_id が出力されるので、あとはこいつを ~/.ssh/config に反映させれば手元のマシンから作成した code commit レポジトリに疎通がとれるようになります。

6-4. terraform import

T.B.D

7. 構成管理方法の整理

7-1. 個人開発の場合

個人のAWSリソースを管理する場合は大きく分けて次の2つの方法があるかと思います

  • .tfstate ごと git で管理して、 code commit にぶちこむ
  • .tfstate は S3 で管理、コードは code commit で管理

7-2. チーム開発の場合

  • .tfstate はセキュリティ上の理由から S3 で管理することが望ましい
  • .tfstate やアクセスキーなどを含むものをコミットせず、GitHub Enterprise, code commit, GitHub private repository に push する