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 です!
DeNA Techathon: 著者と学ぶ「Go ならわかるシステムプログラミング」黙々会 - connpass
構成
図を描く気力がなかったのでテキストで。
インフラ構築編
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 | mazgi/static-website/aws
先述の通り 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
- これのおかげで
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 という証明書エラーに遭遇したときの対処 - Qiita
それはそうと再掲するが .circleci/config.yml
がこんな長さになった。つらい。
workflow として build と deploy が分かれるのは綺麗だけども。。
ともかくこういうサイトをいくつか作りたいニーズがあったのでやっていきます。