はじめに
circleciとterraformでreactなどで作られた静的サイトをデプロイするまでの例です。
terraformでs3とcloudfrontの構築を行い、その後circleciでbuildした静的ファイルのs3へのアップロードを行います。
route53で独自ドメインからcloudfrontへのaliasレコード作るのはここではやってないです。cloudfrontのDistributionsを作ったらデフォルトで作ってくれる *.cloudfront.net
のドメインで静的サイトが閲覧できるようにするまでがゴールです。
terraform
awsの設定
regionの指定、awsのproviderのverの固定、利用するcredentials(~/.aws/credentials)の指定をします。
provider "aws" {
region = "ap-northeast-1"
profile = "private"
version = "2.40.0"
}
terraformの設定
利用するverの固定します。
terraform {
required_version = "0.12.6"
}
s3の設定
バケットの作成です。
resource "aws_s3_bucket" "connpass-map-front" {
bucket = "connpass-map-front"
acl = "private"
region = "ap-northeast-1"
}
cloudfrontとiamの設定
一旦全体のtfファイルを載せます。
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
comment = "origin access identity for s3"
}
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = "${aws_s3_bucket.connpass-map-front.bucket_regional_domain_name}"
origin_id = "${aws_s3_bucket.connpass-map-front.id}"
s3_origin_config {
origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
}
}
enabled = true
is_ipv6_enabled = false
comment = "connpass-map-front"
default_root_object = "index.html"
default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${aws_s3_bucket.connpass-map-front.id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
data "aws_iam_policy_document" "cf_to_s3_policy" {
statement {
actions = ["s3:GetObject"]
resources = [
"${aws_s3_bucket.connpass-map-front.arn}",
"${aws_s3_bucket.connpass-map-front.arn}/*",
]
principals {
type = "AWS"
identifiers = ["${aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn}"]
}
}
}
resource "aws_s3_bucket_policy" "cf-to-s3" {
bucket = "${aws_s3_bucket.connpass-map-front.id}"
policy = "${data.aws_iam_policy_document.cf_to_s3_policy.json}"
}
Origin Access Identityの設定
cloudfrontからのみ、s3にアクセスできるようにするため、Origin Access Identityの設定をしています。
まず、cloudfrontでorigin_access_identityのリソースを作成し、
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
そのリソースが紐づいた形のポリシーを作成。
data "aws_iam_policy_document" "cf_to_s3_policy" {
作成したポリシーを作成したs3のバケットに紐付け。これでcloudfront経由でのみs3にアクセスできる状態になります。
resource "aws_s3_bucket_policy" "cf-to-s3" {
cloudfrontのdistributionの作成
resource "aws_cloudfront_distribution" "s3_distribution" {
distributionのリソースで、特筆するところとしては
s3のバケットを指定する箇所(originとか)は作成したバケットを指定するようにすること、
origin {
domain_name = "${aws_s3_bucket.connpass-map-front.bucket_regional_domain_name}"
origin_id = "${aws_s3_bucket.connpass-map-front.id}"
default_root_object
にindex.htmlを指定すること、(buildしたファイル群にindex.htmlがある前提)
default_root_object = "index.html"
viewer_certificate
は独自ドメインは利用しないのでデフォルトのままにすること
viewer_certificate {
cloudfront_default_certificate = true
}
これで terraform apply
すれば、s3とcloudfrontが作成されます。
tfstateの管理
terraform apply
するとローカルにtfstateが作成されますが、tfstateはs3かterraform cloudで管理するのが定石になってます。(チームで開発するのであれば)
ここではterraform cloudを使ってtfstateの管理をやってみます。
流れとしては以下のような感じです。
- [ブラウザ] terraform cloudでアカウント作成
- [ブラウザ] organizationの作成
- [ブラウザ] terraform cloudにアクセスするためのトークンの作成
- [ローカル] 3で作成したトークンを $HOME/.terraformrc に書く
- [ローカル] tfstateをterraform cloudに保存するように設定
- [ブラウザ] workspaceの設定でawsの操作はローカルから行うように変更
- [ローカル] terraform init
1 〜 3
1 〜 3までの流れは以下の記事に画像付きで載ってます。
https://dev.classmethod.jp/cloud/aws/manage-tfstate-terraform-cloud/
4) [ローカル] 3で作成したトークンを $HOME/terraformrc に書く
credentials "app.terraform.io" {
token = "作成したトークンをここに"
}
5) [ローカル] tfstateをterraform cloudに保存するように設定
terraform.tfに設定を追加。
terraform {
required_version = "0.12.6"
backend "remote" {
organization = "connpass-map-front"
workspaces {
name = "connpass-map-front-workspace"
}
}
}
6) [ブラウザ] workspaceの設定でawsの操作はローカルから行うように変更
ローカルでterraformを動かしている場合、awsのcredentilasはローカルの ~/.aws/credentials
をみに行きます。terraform cloudを使う場合、そのawsの操作をterraform cloudから行うか、ローカルから行うか設定できます。(workspaceの設定)
ここがremote(デフォルト値)となっていると、 terraform apply
や terraform plan
を実行した際、ローカルの ~/.aws/credentials
を見にいかなくなるので以下のエラーが発生します。
Error: No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider
Localに設定すればawsの操作はローカルから実行し、tfstateの管理のみをterraform cloudが行うようになるので上記のエラーは出なくなります。
7) [ローカル] terraform init
terraform cloudにアクセスできたらこんな感じでinitが成功します。
これで terraform apply
すればtfstateがterraform cloudにあがっていく状態になりました。
$ terraform init
Initializing the backend...
Successfully configured the backend "remote"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.40.0...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
ここまでで、環境は整いましたが、肝心のs3のバケットには何も入っていないので、バンドルされた静的ファイルをs3にアップロードする流れをcircleciで設定します。
circle ci
npm run build
でビルドしたファイルを/buildに配置するようになっている前提です。
version: 2.1
orbs:
aws-s3: circleci/aws-s3@1.0.11
executors:
default:
docker:
- image: circleci/node:12
working_directory: ~/repo
commands:
npm_install:
steps:
- restore_cache:
keys:
- v2-dependencies-{{ checksum "package.json" }}
- v2-dependencies-
- run: npm install
- save_cache:
paths:
- node_modules
key: v2-dependencies-{{ checksum "package.json" }}
jobs:
build:
executor: default
steps:
- checkout
- npm_install
- run: npm run build
- persist_to_workspace:
root: .
paths:
- "*"
- ".*"
deploy:
executor: default
steps:
- attach_workspace:
at: ~/repo
- aws-s3/sync:
from: build
to: s3://connpass-map-front
overwrite: true
workflows:
version: 2
build-deploy:
jobs:
- build
- deploy:
requires:
- build
filters:
branches:
only:
- /feature.*/
- master
aws-s3のorbsを使っているので、これでconnpass-map-frontのバケットにbuild配下のファイルがsyncされます。
- aws-s3/sync:
from: build
to: s3://connpass-map-front
overwrite: true
また、このs3のorbsを使うためには、事前にcircleciの環境変数にAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_REGIONを設定しておく必要があります。
このcircleciの設定で、masterにブランチがマージされる度にs3へ最新のバンドルファイルがアップロードされます。
アップロードが終わったあとで、作成したcloudfrontのDistributionsのドメイン(*.cloudfront.net)にアクセスすればアップロードした静的なサイトが閲覧できます。
参考
https://qiita.com/natsumisawa/items/404217208ab1c96d8719
https://dev.classmethod.jp/cloud/aws/manage-tfstate-terraform-cloud/