移動しました=> mazgi.log :: S3 + CloudFrontをTerraformで設定してCircleCIで更新する
「TerraformでS3+CloudFront+SSL/TLS証明書 w/ ACMを設定してHugoで作ったstaticなWebサイトをCircleCIで自動deployする」やつができた。
できたもの
普通のいかにもHugoで作ったWebサイトができた。
もう2018年なので手オペなどせずInfrastructure as Codeで構築かつCIでコンテンツdeployです。
中身はまだない。
きっと酒とメシについての何かが書かれるのでしょう。
これはそもそも先日開催したハッカソンでやろうとして途中までしか進められなかったので、その補習も兼ねてます。
なお次回ハッカソンはGoです!
構成
図を描く気力がなかったのでテキストで。
インフラ構築編
Terraformで以下を行なっている。
- Route 53にドメインのゾーン情報を登録する
- コンテンツ更新用のIAMグループとIAMユーザーを払い出す
- コンテンツ格納用のS3バケットを作る
- ACMでSSL/TLS証明書を発行する
- CloudFront distributionを設定する(ACMの証明書使いたいので)
- CloudFront distributionをRoute 53に登録する
コンテンツ更新編
GitHubへのpushをトリガーにCircleCIで以下を行なっている。
- HugoでstaticなWebコンテンツ生成する
- 生成したWebコンテンツをS3に同期する
- CloudFrontのキャッシュをクリアする
GitHub
GitHubで以下を管理している。
- sakemeshi.terraform
- Terraformリポジトリ
- 中身はRoute 53にドメインのゾーンを登録してmoduleを呼び出しているくらい
- AWSのcredential等は
sakemeshi.terraform-secretリポジトリに置いてsubmoduleとして参照している
- terraform-aws-static-website
- 自分用Terraform module
- S3+CloudFrontでstaticなWebサイトを作るもろもろが詰まっている
- (private) sakemeshi.terraform-secret
- AWSのcredentialなどが入っている
- credential store導入とかはまた今度
- (private) sakemeshi.content
- HugoによるWebサイトの中身
- このリポジトリのmasterにpushするとCircleCIが動いてS3にdeployされる
つくりかた
コンセプトとしてはWebUIを手でぽちぽちしたくないのでTerraformでInfra as Codeします!
AWS Webコンソールぽちぽち
最初からコンセプトに反するようだが2018年時点では手でポチポチすることもまだ必要なのです。(あるいはCLI)
作るものは2つ。
Terraform 実行用 IAM User
terraform-admin という名前で AdministratorAccess をattacheしたIAMユーザーを作る。
credentialも払い出して、今回の場合は sakemeshi.terraform-secret リポジトリにpushしておく。

tfstate 格納用 S3 Bucket
Terraformは設定したクラウド環境の状態を tfstate というファイルで管理するのでそれを格納するS3バケットを作る。
バケット名は ${AWSアカウント名}-terraform としてバージョニングを有効にする。
先ほど作ったIAMユーザー terraform-admin からアクセスできれば良い。

詳しくは以下参照。
Backend Type: s3 - Terraform by HashiCorp
Infra as Terraform
インフラをコードで書く
Terraformで構築するもろもろは専用のGitHubリポジトリを作って terraform.tf に書く。
先述の通りここで公開している。
主な内容は以下の通り。
prepare.sh- terraformバイナリのダウンロードと展開
- 必要な環境変数のexport
- なお命名は職場の文化に由来する
terraform.tf- Terraformで行いたいもろもろ
- ただしほとんどはmoduleに追い出しているので、実際の内容はRoute 53のゾーン設定とmoduleの読み出し程度
terraform.tfvars- 後述のprivateなcredentialリポジトリ内へのsymlink
- AWSのACCESS_KEYやSECRET_KEYなどが書かれている
terraform.tf で参照しているmoduleは公開しているが後述のエラーやリージョンが固定などの残課題がある。
Terraform Module Registry
先述の通りTerraformを実行するIAMユーザーのcredential等は別のprivateリポジトリを作って配置している。
公開できないが中身はこの程度。

Terraform 実行
ようやくTerraformを実行できる環境が整ったので実行!
なお prepare.sh は環境変数をexportするので必ず source する。
$ source prepare.sh $ bin/terraform apply
実行すると初回はもろもろのリソースが作られ、1件のエラーが発生する。
2回目以降はこのように1件のエラーが発生する。。
後述する。

細かいことを書くと今回のドメイン自体はRoute 53で管理していないため、別途ネームサーバーをRoute 53に向けておく等の手順が必要です。
CircleCIで自動build && deploy
Terraformで空のWebサイトができたので中身を作っていく。
GitHubリポジトリを用意しておもむろに hugo new site . する。
適当なテーマをsubmoduleとして追加する。
Quick Start通り。
Hugoは今後がんばることにして今回はCircleCI 2.0をがんばる。
結論を書くとこういう .circleci/config.yml を書いた。
ハマった。
そのほかは本当に hugo new site . したまま。

何はともあれこれでCircleCIでのWebサイトのビルドとS3への同期が行えるようになった!めでたい!

おわりに
ということで(ほぼ)手でぽちぽちせずにInfrastructure as CodeでstaticなWebサイトが作れたし更新の仕組みもできた!やったね!
ポイント
以下あまり書けてないので機会があったら書く。
Terraform
- 最近のTerraformは
terraform initが必要- その作業ディレクトリでの初回実行やmoduleのバージョン上げた際など
- 最近のTerraformは
terraform applyしたあと本当に実行するか聞いてくる- そのため
terraform apply[ENTER]してコーヒーを買いにいくと何十分後に戻ってもDo you want to perform these actions?というメッセージが出迎えてくれる(もちろんあなたのクラウド環境には何も変化はない) terraform apply -auto-approveというわるいオプションがある
- そのため
- tfstate格納用S3バケット(S3 backend)を使うためには環境変数or
~/.aws内にcredentialが必要- 私は
prepare.shの中でexportしている(ので必ずsourceする)
- 私は
- ACMの検証が従来のメールだけではなくDNSでもできるようになっていてTerraformでも対応していた
- New Resources: aws_acm_certificate and aws_acm_certificate_validation by flosell · Pull Request #2813 · terraform-providers/terraform-provider-aws · GitHub
- これのおかげで
terraform applyだけで証明書発行してIssuedになるところまで実現できた - ただし
AWS provider 1.9以上が必要
CircleCI 2.0
- Docker便利だけども
- 使うDockerイメージにもよるが当然
curlもgitも入ってなかったりする - 自分用Dockerイメージ作りたくなる
- 開発環境がDocker Hubに公開できるDockerイメージで完結している場合は便利そう
- 使うDockerイメージにもよるが当然
checkoutにgit clone --recursive相当の機能がない(?)
(特に)ハマりどころ
terraform apply 時の aws_acm_certificate_validation エラー
terraform apply する際に毎回このエラーが発生する。
Error: Error applying plan: 1 error(s) occurred: * module.static-website.aws_acm_certificate_validation.website: 1 error(s) occurred: * aws_acm_certificate_validation.website: Certificate needs [VALIDATON_RECORD.YOURDOMAIN VALIDATON_RECORD.YOURDOMAIN] to be set but only [VALIDATON_RECORD.YOURDOMAIN] was passed to validation_record_fqdns
これ YOURDOMAIN と *.YOURDOMAIN でバリデーションレコードが同じで、Route 53上は1レコードしかないものをTerraformのAWS providerが2レコード返ってくることを期待しているように見えるんだけどどうしたものか。
CircleCI 2.0 で attach_workspace するために ca-certificates パッケージが必要
前フェイズで永続化したワークスペースを後フェイズで attach_workspace して取り出すために ca-certificates パッケージ必要なのはハマった。
こちらの記事に助けられた。
CircleCIでx509という証明書エラーに遭遇したときの対処
それはそうと再掲するが .circleci/config.yml がこんな長さになった。つらい。
workflowとしてbuildとdeployが分かれるのは綺麗だけども。。
ともかくこういうサイトをいくつか作りたいニーズがあったのでやっていきます。
