Packer x Terraform x StaticPress で静的コンテンツ配信システムをテンプレート化してみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、中山です。

StaticPressを利用した静的コンテンツの配信システムをPacker/Terraformを利用してテンプレート化してみました。以下のようなことができるシステムを作れます。

  • WordPressで記事を作成
  • StaticPress S3プラグインでS3にアップロード
  • CloudFrontで配信
  • Route53で名前解決

WordPressを使いたいけど静的サイトも興味がある。でも、HugoとかJekllyはよう分からん。あとCDNよろ。そんなわがままボディなお悩みを解決できるかと思います。

作成するAWSリソースは以下のとおりです。

AWSリソース 用途
VPC環境 EC2インスタンスを起動させるため
EC2 WordPressで記事を作成後S3にアップロードさせるため
S3 静的コンテンツを配信するため
Route53 EC2/S3/CloudFrontの名前解決を実施するため
CloudFront S3上のオリジンコンテンツをキャッシュさせるため

構成図

aws

テンプレートのソースコード

作成したコードはGitHubに上げておきました。本エントリで参照しているコミットハッシュ値は 7ae5b1b01bf261fdd447d7fd3f89dd655fbb85d0 です。HEADが更新された場合は内容に差異が発生している可能性があるのでご注意ください。

使い方

以下にテンプレートの使用方法を記載します。

KeyPairの作成

EC2インスタンスにSSHでログインするためのKeyPairを作成します。 <key-name> は任意の名前に変更してください。

$ aws ec2 create-key-pair --key-name <key-name> --query 'KeyMaterial' --output text > ~/.ssh/<key-name> && chmod 400 ~/.ssh/<key-name>

ツールのインストール

このリポジトリで利用している各種ツールを事前にインストールしてください。

$ gem install bundler
$ pip install cookiecutter
$ brew cask install packer terraform

リポジトリのclone

cookiecutterでリポジトリをcloneします。cloneするとサイトのドメイン名などを聞かれるので今回の構成に合うよう入力してください。何も入力しない場合はデフォルト値が利用されます。

$ cookiecutter gh:knakayama/static-site-template
Cloning into 'static-site-template'...
remote: Counting objects: 86, done.
remote: Compressing objects: 100% (62/62), done.
remote: Total 86 (delta 3), reused 86 (delta 3), pack-reused 0
Unpacking objects: 100% (86/86), done.
Checking connectivity... done.
project_slug [static-site-template]:
region [ap-northeast-1]:
profile [default]:
keypair_path [~/.ssh/static_site_key_pair]:
base_ami_id [ami-f80e0596]:
site_domain [example.com]: ***.com
wp_sub_domain [wp]:
static_site_sub_domain [static]:
wp_domain_ttl [60]:
static_site_domain_ttl [60]:
wp_db_name [wordpress]:
wp_db_user [wordpress]:
wp_db_pass [pAssw0rd]:
wp_site_title [static-site]:
wp_site_admin_user [wp-site-admin]:
wp_site_admin_password [wp-site-admin-pass]:
wp_site_admin_email [wp-site-email@example.com]: ***@***.com
wp_instance_type [t2.micro]:
wp_volume_size [100]:
wp_volume_type [gp2]:
cloudfront_price_class [PriceClass_200]:
ssh_cidr_blocks [0.0.0.0/0]:
stg_source_ip [0.0.0.0/0]:
$ cd static-site-template

gemのインストール

PackerとTerraformの実行はコマンドを直接指定するのではなくRakeでタスク化しています。bundlerでRakeなどのgemをインストールしてください。

$ bundle install --path vendor/bundle
<snip>
Bundle complete! 3 Gemfile dependencies, 9 gems now installed.
Bundled gems are installed into ./vendor/bundle.

Rakeのタスクには以下のものがあります。

$ bundle exec rake -T
rake packer:build                     # Build AMI
rake packer:validate                  # Validate Packer template
rake terraform:global:apply           # Apply Terraform to create IAM Group and Users
rake terraform:global:destroy         # Destroy IAM Resources
rake terraform:global:output          # Outpute IAM Resources
rake terraform:global:plan            # Plan Terraform to create IAM Group and Users
rake terraform:global:remote:disable  # Disable S3 backend to store IAM tfstate locally
rake terraform:global:remote:enable   # Enable S3 backend to store IAM tfstate
rake terraform:prod:apply             # Apply Terraform to create AWS Resources on prod
rake terraform:prod:destroy           # Destroy AWS Resources on prod
rake terraform:prod:output            # Outpute AWS Resources on prod
rake terraform:prod:plan              # Plan Terraform to create AWS Resources on prod
rake terraform:prod:remote:disable    # Disable S3 backend to store AWS tfstate locally
rake terraform:prod:remote:enable     # Enable S3 backend to store AWS tfstate

AMIの作成

Packerを使用してAMIを作成します。まずはテンプレートが正しいか確認します。

$ bundle exec rake packer:validate -t
** Invoke packer:validate (first_time)
** Execute packer:validate
cd packer && AWS_PROFILE=default packer validate wp.json
Template validated successfully.

続いてAMIを作成します。

$ bundle exec rake packer:build -t
<snip>
==> wp-ami: No volumes to clean up, skipping
==> wp-ami: Deleting temporary security group...
==> wp-ami: Deleting temporary keypair...
Build 'wp-ami' finished.

==> Builds finished. The artifacts of successful builds are:
--> wp-ami: AMIs were created:

ap-northeast-1: ami-********

Packerが正常に終了するとAMIのIDが表示されるので properties.yml に追記してください。

$ $EDITOR properties.yml
:wp_ami_id: "" <- AMI IDを追記

IAMグループとユーザの作成

StaticPress S3プラグインを利用してS3にコンテンツをアップロードするためのIAMグループとユーザを作成します。まずは plan を実行してTerraformが作成するAWSリソースを確認します。

$ bundle exec rake terraform:global:plan -t
<snip>
Plan: 8 to add, 0 to change, 0 to destroy.

上記の例では8つのAWSリソースが新たに作成されることが確認できます。続いて apply で実際にAWSリソースを作成します。

$ bundle exec rake terraform:global:apply -t
<snip>
State path: terraform.tfstate

Outputs:

  config                =
Admin IAM:
  Admin Users: static-site-admin
  Access IDs:  ********************
  Secret Keys: ****************************************

  iam_admin_access_ids  = ********************
  iam_admin_secret_keys = ****************************************
  iam_admin_users       = static-site-admin
  remote_state_bucket   = *************************************

tfstateS3 Backendを利用してS3上に設置します。

$ bundle exec rake terraform:global:remote:enable -t
<snip>
Remote state management enabled
Remote state configured and pulled.

もしローカルに設置したい場合は以下のようにコマンドを実行してください。

$ bundle exec rake terraform:global:remote:disable -t
** Invoke terraform:global:remote:disable (first_time)
** Execute terraform:global:remote:disable
cd terraform/global && AWS_PROFILE=default terraform remote config -disable

続いて、EC2などのAWSリソースを構築します。先程と同じくまずは plan を実行して作成されるAWSリソースを確認します。

$ bundle exec rake terraform:prod:plan -t
<snip>
Plan: 28 to add, 0 to change, 0 to destroy.

上記の例では28つのAWSリソースが新たに作成されることが確認できます。続いて apply で実際にAWSリソースを作成します。

$ bundle exec rake terraform:prod:apply -t
<snip>
Outputs:

  cloudfront_domain_name      = **************.cloudfront.net
  remote_state_bucket         = static-site-prod-tfstate-****-**-**
  static_site_cloudfront_fqdn = static.*********.com
  static_site_prod_fqdn       = prod.static.*********.com
  website_endpoint_prod       = prod.static.*********.com.s3-website-ap-northeast-1.amazonaws.com
  website_endpoint_stg        = stg.static.*********.com.s3-website-ap-northeast-1.amazonaws.com
  wp_fqdn                     = wp.*********.com
  wp_public_ip                = **.***.*.***

こちらも同様 tfstate はS3に設置可能です。

$ bundle exec rake terraform:prod:remote:enable -t
<snip>
Remote state management enabled
Remote state configured and pulled.

StaticPressの設定

wp_fqdn で設定されているドメインの/wordpressにアクセスするとWordPressが表示されます。ログイン後StaticPressとStaticPress S3の設定してください。設定の仕方は参考リンクを参照してください。

StaticPress S3プラグインで指定するAWSクレデンシャルは以下のコマンドで確認できます。

$ bundle exec rake terraform:global:output -t

WordPressにログインする際のクレデンシャルは wp.json に書いてあります。ちょっと微妙です。

まとめ

いかがだったでしょうか。

インフラをコード化すると一瞬で思い通りのシステムが構築できるのでとても便利ですね。

本エントリがみなさんの参考になったら幸いに思います。

参考リンク