【最終回】静的Webサイトホスティング二重化してみる(その4)
静的Webサイトホスティングパターンの二重化、前回から半年近くが経過しました。色々と試行錯誤していてようやくCloudFormationとかDeploymentManagerとかTerraformもなれてきたので宿題だったIaC化にチャレンジしました。
前提条件としてDockerでAWS-CLIとかGoogleCloud-SDK丸ごと込々の環境を作成できていることが必要になります。とりあえずそちらはDockerでサクッと作りました。
ほんとはGitHubのところまでできたらよかったんですが、そこはスキルがなくてヨワヨワなのでここまでが限界でした。ひとまず静的Webサイトホスティングパターンはここまでで最後です。ようやく昨年からの懸案事項解決できました。
◆シリーズ
その2:GoocleCloudでLoadBaranser+GCS構成を作りDNSでフェイルオーバ
その3:S3とGCSにGitHubActions使ってコンテンツ同期
その4:TerraformでIaC化
◆設定作業編
1.Docker内初期設定
(1)AWS初期設定
#コンテナログイン $ docker exec -it terraform-dev /bin/bash #AWS認証情報 # aws configure AWS Access Key ID [None]: INPUTACCESSKEY AWS Secret Access Key [None]: INPUTSECRETACCESSKEY Default region name [None]: ap-northeast-1 Default output format [None]: json #環境変数設定 # cd ~/terraform/ # export TF_VAR_access_key="ACCESSKEY" # export TF_VAR_secret_key="SECRETACCESSKEY" # export TF_VAR_role_arn="ROLE/ARN"
(2)GCP認証情報
#初期設定
# gcloud init
Welcome! This command will take you through the configuration of gcloud.
~中略~
You must log in to continue. Would you like to log in (Y/n)? Y
~中略~
Pick cloud project to use:
~中略~
Please enter numeric choice or text value (must exactly match list
item):7
~中略~
Do you want to configure a default Compute Region and Zone? (Y/n)? Y
~中略~
Please enter numeric choice or text value (must exactly match list
item): 34
files and output formatting
#プロジェクト設定
# export GCP_PROJECT_ID=$(gcloud config get-value project)
# env | grep GCP_PROJECT_ID
G
#サービスアカウント作成
# gcloud iam service-accounts create terraform-serviceaccount --display-name "Account for Terraform"
# gcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} --member serviceAccount:terraform-serviceaccount@${GCP_PROJECT_ID}.iam.gserviceaccount.com --role roles/editor
#クレデンシャルキー発行
# gcloud iam service-accounts keys create ~/.config/gcloud/sakey.json \
--iam-account hoge@project.iam.gserviceaccount.com
#環境変数設定
# export GOOGLE_CLOUD_KEYFILE_JSON=~/.config/gcloud/sakey.json
# export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)(3)Azure認証情報
#初期設定 クレデンシャル発行
# az login
~中略~
・認証情報取得
# az account list --query "[].{name:name, subscriptionId:id, tenantId:tenantId}"
~中略~
# az account set --subscription="subscriptionID"
# az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/subscriptionID"
Creating 'Contributor' role assignment under scope '/subscriptions/subscriptionID'
The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
"appId": "appId",
"displayName": "azure-XXXX",
"name": "http://azure-XXXX",
"password": "password",
"tenant": "tenant"
}
・環境変数設定
# export ARM_SUBSCRIPTION_ID=subscriptionId
# export ARM_CLIENT_ID=appId
# export ARM_CLIENT_SECRET=password
# export ARM_TENANT_ID=tenant
# export ARM_ENVIRONMENT=public
2.Terraform
2.1.ファイル群
(1)ルート配下
#main.tf
-------------------
provider "aws" {
region = "ap-northeast-1"
}
provider "aws" {
alias = "use1"
region = "us-east-1"
}
provider "google" {
project = var.googleCloud.project
credentials = file(var.googleCloud.credentials)
}
provider "google-beta" {
project = var.googleCloud.project
credentials = file(var.googleCloud.credentials)
}
module "zone_acm" {
source = "./zone_acm"
root_domain = var.root_domain
providers = {
aws = aws.use1
}
}
module "awsstatic" {
source = "./awsstatic"
root_domain = var.root_domain
site_domain = var.site_domain
bucket_name = var.name
acm_cert = module.zone_acm.cert_arn
dns_zone = module.zone_acm.domain_zone
depends_on = [module.zone_acm]
}
module "gcpstatic" {
source = "./gcpstatic"
googleCloud = var.googleCloud
googlebucket = var.googlebucket
name = var.name
root_domain = var.root_domain
site_domain = var.site_domain
dns_zone = module.zone_acm.domain_zone
depends_on = [module.awsstatic]
}
module "failoverdns" {
source = "./failoverdns"
root_domain = var.root_domain
site_domain = var.site_domain
bucket_name = var.name
dns_zone = module.zone_acm.domain_zone
cloudfront_id = module.awsstatic.cloudfront_alias_id
cloudfront_domain = module.awsstatic.cloudfront_alias_name
gcp_ipv4_addr = module.gcpstatic.gcp_ipv4
gcp_ipv6_addr = module.gcpstatic.gcp_ipv6
depends_on = [module.gcpstatic]
}
#variables.tf
-------------------
variable "site_domain" {
default = "www.yourdomain"
}
variable "root_domain" {
default = "yourdomain"
}
variable "name" {
default = "yourdomain"
}
variable "googleCloud" {
default = {
project = "youre_GCP_projectId"
credentials = "~/.config/gcloud/sakey.json"
}
}
variable "googlebucket" {
default = {
bucket_name = "bucketname"
region = "asia"
storage_class = "MULTI_REGIONAL"
log_region = "asia-northeast1"
log_class = "NEARLINE"
}
}
-------------------(2)zoneacm配下
#main.tf
-------------------
resource "aws_acm_certificate" "cert" {
domain_name = var.root_domain
validation_method = "DNS"
subject_alternative_names = [
var.root_domain,
"*.${var.root_domain}"
]
tags = {
ManagedBy = "terraform"
Changed = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
}
lifecycle {
ignore_changes = [tags]
}
}
resource "aws_route53_zone" "zone" {
name = var.root_domain
tags = {
ManagedBy = "terraform"
Changed = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
Name = var.root_domain
}
}
resource "null_resource" "get_ns_records" {
provisioner "local-exec" {
command = "/bin/bash ./sh/get_ns_records.sh ${var.root_domain}"
}
}
resource "aws_route53_record" "validations" {
for_each = {
for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = aws_route53_zone.zone.zone_id
}
resource "aws_acm_certificate_validation" "acm_validation" {
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [for record in aws_route53_record.validations : record.fqdn]
}
-------------------
#variables.tf
-------------------
variable "root_domain" {}
-------------------
#output.tf
-------------------
output "domain_zone" {
value = aws_route53_zone.zone.zone_id
}
output "cert_arn" {
value = aws_acm_certificate.cert.arn
}
-------------------(3)awsstatic配下
#s3.tf
-------------------
data "aws_iam_policy_document" "cloudfront-logging-bucket" {
statement {
sid = ""
effect = "Allow"
principals {
identifiers = ["*"]
type = "*"
}
actions = [
"s3:ListBucket",
"s3:PutObject",
"s3:GetObject"
]
resources = [
"arn:aws:s3:::${var.bucket_name}-cloudfront-logs",
"arn:aws:s3:::${var.bucket_name}-cloudfront-logs/*"
]
}
}
resource "aws_s3_bucket" "cloudfront-logging" {
bucket = "${var.bucket_name}-cloudfront-logs"
policy = data.aws_iam_policy_document.cloudfront-logging-bucket.json
request_payer = "BucketOwner"
}
resource "aws_s3_bucket_public_access_block" "cloudfront-logging" {
bucket = aws_s3_bucket.cloudfront-logging.bucket
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket" "website-logs" {
bucket = "${var.bucket_name}-logs"
acl = "log-delivery-write"
tags = {
ManagedBy = "terraform"
Changed = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
}
lifecycle {
ignore_changes = [tags]
}
}
resource "aws_s3_bucket" "static-site" {
bucket = var.bucket_name
acl = "private"
policy = data.aws_iam_policy_document.static-site-bucket_policy.json
versioning {
enabled = true
}
logging {
target_bucket = aws_s3_bucket.website-logs.bucket
target_prefix = "${var.bucket_name}/"
}
lifecycle {
ignore_changes = [tags]
}
}
locals {
s3-origin-id-static-site = "s3-origin-id-static-site"
}
data "aws_iam_policy_document" "static-site-bucket_policy" {
statement {
sid = ""
effect = "Allow"
principals {
type = "AWS"
identifiers = [aws_cloudfront_origin_access_identity.static-site-idntity.iam_arn]
}
actions = [
"s3:GetObject"
]
resources = [
"arn:aws:s3:::${var.bucket_name}",
"arn:aws:s3:::${var.bucket_name}/*"
]
}
}
-------------------
#cloudfront.tf
-------------------
resource "aws_cloudfront_distribution" "static-site-dst" {
origin {
domain_name = aws_s3_bucket.static-site.bucket_regional_domain_name
origin_id = local.s3-origin-id-static-site
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.static-site-idntity.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
comment = var.root_domain
default_root_object = "index.html"
logging_config {
include_cookies = false
bucket = aws_s3_bucket.cloudfront-logging.bucket_regional_domain_name
prefix = "cloudfront"
}
aliases = [
var.root_domain,
"www.${var.root_domain}",
"main.${var.root_domain}"
]
viewer_certificate {
acm_certificate_arn = var.acm_cert
minimum_protocol_version = "TLSv1.2_2019"
ssl_support_method = "sni-only"
cloudfront_default_certificate = false
}
custom_error_response {
error_code = "404"
response_code = "200"
response_page_path = "/404.html"
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = local.s3-origin-id-static-site
compress = true
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
}
resource "aws_cloudfront_origin_access_identity" "static-site-idntity" {
comment = "access-identity-static-site.s3.amazonaws.com"
}
resource "aws_route53_record" "root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "A"
alias {
name = aws_cloudfront_distribution.static-site-dst.domain_name
zone_id = aws_cloudfront_distribution.static-site-dst.hosted_zone_id
evaluate_target_health = false
}
}
resource "aws_route53_record" "www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "A"
alias {
name = aws_cloudfront_distribution.static-site-dst.domain_name
zone_id = aws_cloudfront_distribution.static-site-dst.hosted_zone_id
evaluate_target_health = false
}
}
-------------------
#variables.tf
-------------------
variable "root_domain" {}
variable "site_domain" {}
variable "bucket_name" {}
variable "acm_cert" {}
variable "dns_zone" {}
-------------------
#output.tf
-------------------
output "cloudfront_alias_id" {
value = aws_cloudfront_distribution.static-site-dst.hosted_zone_id
}
output "cloudfront_alias_name" {
value = aws_cloudfront_distribution.static-site-dst.domain_name
}
output "cloudfront_dist_id" {
value = aws_cloudfront_distribution.static-site-dst.id
}
-------------------(4)gcpstatic配下
#cert.tf
-------------------
resource "google_compute_managed_ssl_certificate" "naked_lb_cert" {
name = "${var.name}-cert"
managed {
domains = [var.root_domain]
}
}
resource "google_compute_managed_ssl_certificate" "www_lb_cert" {
name = "www-${var.name}-cert"
managed {
domains = [var.site_domain]
}
}
-------------------
#gcs.tf
-------------------
resource "google_storage_bucket" "logs-bucket" {
name = "${var.googlebucket.bucket_name}-logs"
location = var.googlebucket.log_region
storage_class = var.googlebucket.log_class
force_destroy = true
labels = {
project = var.googleCloud.project
}
}
resource "google_storage_bucket_acl" "logs-bucket_iam" {
bucket = google_storage_bucket.logs-bucket.name
role_entity = [
"WRITER:group-cloud-storage-analytics@google.com",
]
default_acl = "projectprivate"
}
resource "google_storage_bucket" "bucket" {
name = var.googlebucket.bucket_name
location = var.googlebucket.region
storage_class = var.googlebucket.storage_class
force_destroy = true
labels = {
project = var.googleCloud.project
}
versioning {
enabled = true
}
website {
main_page_suffix = "index.html"
not_found_page = "404.html"
}
logging {
log_bucket = "${var.googlebucket.bucket_name}-logs"
}
uniform_bucket_level_access = true
}
resource "google_storage_bucket_iam_member" "staticweb_bucket_iam_member_object_viewer" {
bucket = google_storage_bucket.bucket.name
role = "roles/storage.legacyObjectReader"
member = "allUsers"
}
-------------------
#loadbalancer.tf
-------------------
resource "google_compute_backend_bucket" "bucket_backend" {
name = "${var.name}-backend"
bucket_name = google_storage_bucket.bucket.name
}
resource "google_compute_url_map" "urlmap" {
name = "${var.name}-https-site"
description = "URL map for ${var.name}"
default_service = google_compute_backend_bucket.bucket_backend.self_link
host_rule {
hosts = ["*"]
path_matcher = "all"
}
path_matcher {
name = "all"
default_service = google_compute_backend_bucket.bucket_backend.self_link
path_rule {
paths = ["/*"]
service = google_compute_backend_bucket.bucket_backend.self_link
}
}
}
resource "google_compute_target_https_proxy" "https_proxy" {
name = "${var.name}-proxy"
url_map = google_compute_url_map.urlmap.self_link
ssl_certificates = [
google_compute_managed_ssl_certificate.naked_lb_cert.id,
google_compute_managed_ssl_certificate.www_lb_cert.id
]
}
resource "google_compute_global_forwarding_rule" "https_ipv4" {
name = "${var.name}-v4-fwdrule"
target = google_compute_target_https_proxy.https_proxy.id
port_range = "443"
ip_address = google_compute_global_address.lb_v4_address.address
}
resource "google_compute_global_forwarding_rule" "https_ipv6" {
name = "${var.name}-v6-fwdrule"
target = google_compute_target_https_proxy.https_proxy.id
port_range = "443"
ip_address = google_compute_global_address.lb_v6_address.address
}
resource "google_compute_url_map" "http_redirect" {
name = "${var.name}-redirect"
default_url_redirect {
redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
https_redirect = true
strip_query = false
}
}
resource "google_compute_target_http_proxy" "http_default" {
name = "${var.name}-https-redirect-proxy"
url_map = google_compute_url_map.http_redirect.self_link
}
resource "google_compute_global_forwarding_rule" "http_ipv4" {
name = "${var.name}-http-v4-fwdrule"
target = google_compute_target_http_proxy.http_default.self_link
ip_address = google_compute_global_address.lb_v4_address.address
port_range = "80"
}
resource "google_compute_global_forwarding_rule" "http_ipv6" {
name = "${var.name}-http-v6-fwdrule"
target = google_compute_target_http_proxy.http_default.self_link
ip_address = google_compute_global_address.lb_v6_address.address
port_range = "80"
}
resource "null_resource" "check_complete_lb" {
provisioner "local-exec" {
command = "/bin/bash ./sh/gcp_cert_check.sh ${var.root_domain}"
}
depends_on = [
aws_route53_record.gcp_root_domain,
aws_route53_record.gcp_www_domain
]
}
-------------------
#gcpip.tf
-------------------
resource "google_compute_global_address" "lb_v4_address" {
name = "lb-v4-address"
ip_version = "IPV4"
}
resource "google_compute_global_address" "lb_v6_address" {
name = "lb-v6-address"
ip_version = "IPV6"
}
resource "null_resource" "delete_aliasrecords" {
provisioner "local-exec" {
command = "/bin/bash ./sh/alias_arecord_delete.sh ${var.root_domain}"
}
depends_on = [
google_compute_global_address.lb_v4_address,
google_compute_global_address.lb_v6_address
]
}
resource "aws_route53_record" "gcp_root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "A"
ttl = "60"
records = [google_compute_global_address.lb_v4_address.address]
depends_on = [null_resource.delete_aliasrecords]
}
resource "aws_route53_record" "gcp_www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "A"
ttl = "60"
records = [google_compute_global_address.lb_v4_address.address]
depends_on = [null_resource.delete_aliasrecords]
}
-------------------
#variables.tf
-------------------
variable "site_domain" {}
variable "root_domain" {}
variable "dns_zone" {}
variable "name" {}
variable "googleCloud" {}
variable "googlebucket" {}
-------------------
#output.tf
-------------------
output "gcp_ipv4" {
value = google_compute_global_address.lb_v4_address.address
}
output "gcp_ipv6" {
value = google_compute_global_address.lb_v6_address.address
}
-------------------(5)failoverdns配下
#main.tf
-------------------
resource "null_resource" "delete_a_records" {
provisioner "local-exec" {
command = "/bin/bash ./sh/ip_arecord_delete.sh ${var.root_domain}"
}
}
resource "aws_route53_health_check" "cdn_healthcheck" {
reference_name = "${var.bucket_name}_check"
fqdn = var.cloudfront_domain
failure_threshold = "3"
type = "HTTPS"
port = 443
request_interval = "30"
tags = {
Name = "${var.bucket_name}-web-check"
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "main_alias_ipv4" {
zone_id = var.dns_zone
name = "main.${var.root_domain}"
type = "A"
alias {
name = var.cloudfront_domain
zone_id = var.cloudfront_id
evaluate_target_health = false
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "main_alias_ipv6" {
zone_id = var.dns_zone
name = "main.${var.root_domain}"
type = "AAAA"
alias {
name = var.cloudfront_domain
zone_id = var.cloudfront_id
evaluate_target_health = false
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "A"
health_check_id = aws_route53_health_check.cdn_healthcheck.id
set_identifier = "${var.bucket_name}-ipv4-main"
failover_routing_policy {
type = "PRIMARY"
}
alias {
name = aws_route53_record.main_alias_ipv4.name
zone_id = var.dns_zone
evaluate_target_health = true
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "ipv6_root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "AAAA"
health_check_id = aws_route53_health_check.cdn_healthcheck.id
set_identifier = "${var.bucket_name}-ipv6-main"
failover_routing_policy {
type = "PRIMARY"
}
alias {
name = aws_route53_record.main_alias_ipv6.name
zone_id = var.dns_zone
evaluate_target_health = true
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "A"
health_check_id = aws_route53_health_check.cdn_healthcheck.id
set_identifier = "${var.bucket_name}-www-ipv4-main"
failover_routing_policy {
type = "PRIMARY"
}
alias {
name = aws_route53_record.main_alias_ipv4.name
zone_id = var.dns_zone
evaluate_target_health = true
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "ipv6_www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "AAAA"
health_check_id = aws_route53_health_check.cdn_healthcheck.id
set_identifier = "${var.bucket_name}-www-ipv6-main"
failover_routing_policy {
type = "PRIMARY"
}
alias {
name = aws_route53_record.main_alias_ipv6.name
zone_id = var.dns_zone
evaluate_target_health = true
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "gcp_root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "A"
ttl = "60"
records = [var.gcp_ipv4_addr]
set_identifier = "${var.bucket_name}-ipv4-sub"
failover_routing_policy {
type = "SECONDARY"
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "gcp_ipv6_root_domain" {
zone_id = var.dns_zone
name = var.root_domain
type = "AAAA"
ttl = "60"
records = [var.gcp_ipv6_addr]
set_identifier = "${var.bucket_name}-ipv6-sub"
failover_routing_policy {
type = "SECONDARY"
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "gcp_www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "A"
ttl = "60"
records = [var.gcp_ipv4_addr]
set_identifier = "${var.bucket_name}-www-ipv4-sub"
failover_routing_policy {
type = "SECONDARY"
}
depends_on = [null_resource.delete_a_records]
}
resource "aws_route53_record" "gcp_ipv6_www_domain" {
zone_id = var.dns_zone
name = var.site_domain
type = "AAAA"
ttl = "60"
records = [var.gcp_ipv6_addr]
set_identifier = "${var.bucket_name}-www-ipv6-sub"
failover_routing_policy {
type = "SECONDARY"
}
depends_on = [null_resource.delete_a_records]
}
-------------------
#variables.tf
-------------------
variable "root_domain" {}
variable "site_domain" {}
variable "bucket_name" {}
variable "dns_zone" {}
variable "cloudfront_id" {}
variable "cloudfront_domain" {}
variable "gcp_ipv4_addr" {}
variable "gcp_ipv6_addr" {}
-------------------(6)sh配下
#get_ns_records.sh
-------------------
#!/bin/bash
if [ $# != 1 ]; then
echo 'Empty CertName! Please [./get_ns_records.sh yourdomain]'
exit 1
fi
domain=$1
route53result=$(aws route53 list-hosted-zones-by-name --dns-name ${domain} | jq -r ".HostedZones[0].Id")
hz=$(echo ${route53result} | sed -e "s!/hostedzone/!!g")
if [ "$hz" = "" ]; then
echo 'Fail get HostedZoneId'
exit 1
fi
echo '*** Please Setting Your Domain Nameserve ***'
route53records=$(aws route53 list-resource-record-sets --hosted-zone-id /hostedzone/${hz})
array=$(echo ${route53records} | \
jq -c -r '.ResourceRecordSets[]| if .Type == "NS" then .ResourceRecords[].Value else empty end'
)
for i in ${array[@]}
do
echo ${i}
done
-------------------
#gcp_cert_check.sh
-------------------
#!/bin/bash
SLEEP_TIME=30
STATUS_CODE="ACTIVE"
if [ $# != 1 ]; then
echo 'Empty CertName! Please [./gcp_cert_check.sh yourdomain]'
exit 1
fi
domain=$1
# Check Cert status
certname=$(echo ${domain/./-})
echo "*** ssl cert status check ***"
while true
do
echo "Check now please wait・・・"
sleep ${SLEEP_TIME}
naked_code=$(echo $(gcloud beta compute ssl-certificates describe ${certname}-cert \
--global \
--format="get(managed.domainStatus)") | cut -d= -f2)
www_code=$(echo $(gcloud beta compute ssl-certificates describe www-${certname}-cert \
--global \
--format="get(managed.domainStatus)") | cut -d= -f2)
if [ "$naked_code" = "$STATUS_CODE" ] && [ "$www_code" = "$STATUS_CODE" ]; then
break
fi
done
echo "*** Setting Complete ***"
-------------------
#alias_arecord_delete.sh
-------------------
#!/bin/bash
SLEEP_TIME=10
BREAK_WORD="INSYNC"
JSON_FILE=`mktemp`
if [ $# != 1 ]; then
echo 'Empty Domain! Please [./alias_arecord_delete.sh yourdomain]'
exit 1
fi
domainname=$1
# Get Hostedzoneid
route53result=$(aws route53 list-hosted-zones-by-name --dns-name ${domainname})
hosted=$(echo ${route53result} | jq -r ".HostedZones[0].Id")
hz=$(echo ${hosted} | sed -e "s!/hostedzone/!!g")
# Route53 Make TargetRecords
route53records=$(aws route53 list-resource-record-sets --hosted-zone-id /hostedzone/${hz})
DELIMITA=","
RECTYPES=("A")
for (( i = 0; i < ${#RECTYPES[@]}; ++i )); do
if [ $i -gt 0 ]; then
BODY+="$DELIMITA
"
fi
route53alias=$(echo ${route53records} | jq -c -r '.ResourceRecordSets[] | if .Type == "'${RECTYPES[$i]}'" then .AliasTarget else empty end')
route53dnsname=$(echo ${route53records} | jq -c -r '.ResourceRecordSets[] | if .Type == "'${RECTYPES[$i]}'" then .Name else empty end')
RECORD_TYPE=${RECTYPES[$i]}
RESOURCE_VALUE=(`echo $route53alias`)
DNS_NAME=(`echo $route53dnsname`)
for (( j = 0; j < ${#RESOURCE_VALUE[@]}; ++j )); do
if [ $j -gt 0 ]; then
BODY+="$DELIMITA"
fi
BODY+=$(cat < $JSON_FILE
# Deleting DNS Record set
jobid=$(aws route53 change-resource-record-sets --hosted-zone-id ${hz} --change-batch file://$JSON_FILE)
JOBID=$(echo ${jobid} | jq -r ".ChangeInfo.Id" | sed -e "s!/change/!!g")
#Status check
while true
do
sleep ${SLEEP_TIME}
route53stat=$(aws route53 get-change --id /change/${JOBID})
stat=$(echo ${route53stat} | jq -r ".ChangeInfo.Status")
if [ "$stat"=${BREAK_WORD} ]; then
break
fi
done
echo "*** Setting Complete ***"
-------------------
#ip_arecord_delete.sh
-------------------
#!/bin/bash
SLEEP_TIME=10
BREAK_WORD="INSYNC"
JSON_FILE=`mktemp`
if [ $# != 1 ]; then
echo 'Empty Domain! Please [./ip_arecord_delete.sh yourdomain]'
exit 1
fi
domainname=$1
# Get Hostedzoneid
route53result=$(aws route53 list-hosted-zones-by-name --dns-name ${domainname})
hosted=$(echo ${route53result} | jq -r ".HostedZones[0].Id")
hz=$(echo ${hosted} | sed -e "s!/hostedzone/!!g")
# Route53 Make TargetRecords
route53records=$(aws route53 list-resource-record-sets --hosted-zone-id /hostedzone/${hz})
DELIMITA=","
RECTYPES=("A")
for (( i = 0; i < ${#RECTYPES[@]}; ++i )); do
if [ $i -gt 0 ]; then
BODY+="$DELIMITA
"
fi
route53resourcevalue=$(echo ${route53records} | jq -c -r '.ResourceRecordSets[] | if .Type == "'${RECTYPES[$i]}'" then .ResourceRecords[].Value else empty end')
route53dnsname=$(echo ${route53records} | jq -c -r '.ResourceRecordSets[] | if .Type == "'${RECTYPES[$i]}'" then .Name else empty end')
RECORD_TYPE=${RECTYPES[$i]}
route53ttl=$(echo ${route53records} | jq -c -r '.ResourceRecordSets[] | if .Type == "'${RECTYPES[$i]}'" then .TTL else empty end')
RESOURCE_VALUE=(`echo $route53resourcevalue`)
DNS_NAME=(`echo $route53dnsname`)
TTL=(`echo $route53ttl`)
for (( j = 0; j < ${#RESOURCE_VALUE[@]}; ++j )); do
if [ $j -gt 0 ]; then
BODY+="$DELIMITA"
fi
BODY+=$(cat < $JSON_FILE
# Deleting DNS Record set
jobid=$(aws route53 change-resource-record-sets --hosted-zone-id ${hz} --change-batch file://$JSON_FILE)
JOBID=$(echo ${jobid} | jq -r ".ChangeInfo.Id" | sed -e "s!/change/!!g")
#Status check
while true
do
sleep ${SLEEP_TIME}
route53stat=$(aws route53 get-change --id /change/${JOBID})
stat=$(echo ${route53stat} | jq -r ".ChangeInfo.Status")
if [ "$stat"=${BREAK_WORD} ]; then
break
fi
done
echo "*** Setting Complete ***"
-------------------
2.2.ディレクトリ構造
.
|-- awsstatic
| |-- cloudfront.tf
| |-- output.tf
| |-- s3.tf
| `-- variables.tf
|-- failoverdns
| |-- main.tf
| `-- variables.tf
|-- gcpstatic
| |-- cert.tf
| |-- gcpip.tf
| |-- gcs.tf
| |-- loadbalancer.tf
| |-- output.tf
| `-- variables.tf
|-- main.tf
|-- sh
| |-- alias_arecord_delete.sh
| |-- gcp_cert_check.sh
| |-- get_ns_records.sh
| `-- ip_arecord_delete.sh
|-- terraform.tfstate
|-- terraform.tfstate.backup
|-- variables.tf
`-- zone_acm
|-- main.tf
|-- output.tf
`-- variables.tf
◆参考サイト
・terraform
https://dev.classmethod.jp/articles/terraform_module_coordination/
https://kazuhira-r.hatenablog.com/entry/2020/06/07/175759
https://medium.com/hashicorp-engineering/creating-module-dependencies-in-terraform-0-13-4322702dac4a
https://dev.classmethod.jp/articles/terraform013/
https://qiita.com/takkii1010/items/082c0854fd41bc0b26c3
・terraform特定リソース削除
https://www.devopsschool.com/blog/how-to-destroy-one-specific-resource-from-tf-file-in-terraform/
https://stackoverflow.com/questions/55265203/terraform-delete-all-resources-except-one
https://christina04.hatenablog.com/entry/2015/09/07/211925
https://kaoru2012.blogspot.com/2019/09/terraform_24.html
・terraformShell呼出し
https://dev.to/sagarjadhv23/executing-shell-script-in-terraform-via-null-resource-872
https://www.terraform.io/docs/language/resources/provisioners/local-exec.html
・S3+CloudFront+ACM
https://qiita.com/keitarounakano/items/11358d6814d7e9680054
https://qiita.com/neruneruo/items/cd550894aed76c11458c
https://github.com/cloudmaniac/terraform-aws-static-website/blob/master/main.tf
https://tech.lucheholdings.com/entry/2018/09/25/220855
https://qiita.com/matsuda-hiroki/items/25686218cafff6ed0989
https://katsuya-place.com/terraform-cloudfront/
・マルチリージョン
https://medium.com/@jyotti/terraform-multi-region-79a84ce1da0c
https://fusagiko.hatenablog.jp/entry/2019/12/01/advent_calendar
・Route53
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_health_check
https://blog.manabusakai.com/2020/04/change-the-routing-policy-in-terraform/
https://gside.org/blog/2016/10/16/
https://budougumi0617.github.io/2020/11/07/define_https_subdomain_by_terraform/
https://qiita.com/zembutsu/items/85ed9061288cae11bc21
https://dev.classmethod.jp/articles/route53-hostedzone-change-by-aws-cli/
https://qiita.com/iogi/items/676b8c5cbbb6ec874c37
・ACM
https://qiita.com/y-ohgi/items/b823b6bd078ce8e11546
https://github.com/hashicorp/terraform-provider-aws/issues/8531
https://zenn.dev/shonansurvivors/articles/5ee0e50ab2c915
・CloudFront CLI操作
https://www.semicolonworld.com/question/78733/aws-cli-disable-distribution
・GCP project関連
https://cloud.google.com/community/tutorials/managing-gcp-projects-with-terraform?hl=ja
・LB
https://qiita.com/ktoshi/items/a43a54005aa73be1254d
https://qiita.com/ktoshi/items/1fd3c62b15993adce93c
https://cloud.google.com/blog/ja/products/serverless/serverless-load-balancing-terraform-hard-way
https://inside.pixiv.blog/2020/05/08/161041
・GCS
https://blog.grasys.io/post/okawa/tf-gcs-logging/
https://qiita.com/y_hideshi/items/5c8a5d5d4c7a30278378
https://kawabatas.hatenablog.com/entry/2018/08/12/114150
https://www.javaer101.com/en/article/28846055.html
・GCP IPアドレス発行
https://www.namakedame.work/terraform-gcp-static-ip/
https://github.com/terraform-google-modules/terraform-google-lb-http/issues/112
・Shell
http://psychedelicnekopunch.com/archives/2055
https://qiita.com/simarei/items/f4809314399562309e4b
https://genzouw.com/entry/2019/12/17/120057/1831/
https://qiita.com/ponsuke0531/items/a56126b8b218f74faa10
http://kodama.fubuki.info/wiki/wiki.cgi/bash/tips?lang=jp
http://amano41.hatenablog.jp/entry/bash-supports-addition-assignment-operator
https://www.appmeshworkshop.com/cleanup/route53/
https://takuya-1st.hatenablog.jp/entry/2017/03/22/144700
https://linuxfan.info/cat-string-in-shell
完成してきちんと動くのはイイのですがドメインのレジストラがTerraformからの制御に対応していないとかAPIが準備されていないとかなところが多いので、
Route53の登録後にNSレコードをレジストラ側に設定してやる必要があります。後はGoogleのLBのドメインの反映が驚くほど時間がかかるので、コマンド打ってから構築完了までに楽勝で15分ほどかかります。とりあえずこの構成だと非常にバカ高いというところがあって、どうにかして安価で抑える方法を考えたいのですがいい手立て思いつきません。ご教示いただけると幸いです。
それとRoute53のAレコード削除とかをShellスクリプトからキックしていたりするのであまりいいパターンではありません。よい子は真似をしないようにですね。
◆GitHub
いちおう上げています。(2022-07-03 Terraform v1.2.2で動作確認済)
https://github.com/Otazoman/terraform_dupulicate_staticsite/tree/main/aws_gcp
※2024年9月に少し修正して最新のterraform(1.9.5)で動作確認しました。GitHub参照してください。
コメント