(続)静的Webサイトホスティング二重化してみる(その1)
以前、AWSとGCPで静的Webサイトホスティングを冗長化していました。
けどGCPじゃなくてAzurなんだよAzureとか言われそうなところもあるのでAzureでできないものかと悶々としておりました。
そんな中AzureにもApplicationGatewayなるものが存在しバックエンドにAzureBlobの静的サイトホスティングを配置しIPアドレスも割当可能とのことから、これ行けるんじゃなかろうかと思って少し取り組んでみようと思いました。
まずは前回はマネジメントコンソールからスタートしたので、思い切って今回はAWS-CLIv2でやってみます。なんかAWSで静的Webサイトホスティングやるの久しぶりだな。
何回かシリーズになるかどうか謎ですが、気が向いたらお付き合いいただけると幸いです。ドメインはfreenomで取得しています。(お約束の無料ドメイン)
◆シリーズ
その1:AWSでCloudFront+S3構成を作る(今回)
その2:AzureでApplicationGateway+Blob構成を作る
その4:S3とBlobにGitHubActions使ってコンテンツ同期
◆環境
aws-cli/2.4.27 Python/3.8.8 Linux/5.4.0-104-generic exe/x86_64.ubuntu.20 prompt/off Python 3.10.3 Ubuntu20.04.4LTS
◆作業内容
1.事前準備
# 1.AWS-CLIのv1系アンインストール $ pip uninstall awscli Proceed (y/n)?y Successfully uninstalled awscli-1.18.39 # 2.AWS-CLIのv2系インストール $ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" $ unzip awscliv2.zip $ sudo ./aws/install --update $ /usr/local/bin/aws --version aws-cli/2.4.27 Python/3.8.8 Linux/5.4.0-104-generic exe/x86_64.ubuntu.20 prompt/off $ rm awscliv2.zip $ rm -Rf aws/ $ vi .bashrc ※追記 ------------------------ export PATH="/usr/local/bin:$PATH" ------------------------ $ source .bashrc $ aws --version # 3.インストール済みツール群バージョンアップ #(1)pyenvバージョンアップ $ pyenv update #(2)python追加版インストール $ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \ libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ xz-utils tk-dev libffi-dev liblzma-dev python-openssl git $ pyenv install 3.10.3 $ pyenv global 3.10.3 $ vi .bashrc ------------------------------------ export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/shims:$PATH" #shimsに書替 #pyenv initは削除する ------------------------------- $ source .bashrc $ pyenv versions $ sed -i -e 's/3.7.7/3.10.3/g' /home/matarain/.python-version $ python --version #(3)nパッケージ最新化 $ sudo n latest $ node -v $ npm -v
2.静的Webサイトホスティング構築用コマンド
${YOUR_DOMAIN}と${YOUR_LOG_BUCKET}と${HOSTED_ZONE_ID}は自分の環境のものに置き換えて実行
# 1.S3設定
# 静的ホスティング用バケット作成
$ aws s3 mb s3://${YOUR_DOMAIN}
$ aws s3 cp html/dist/ s3://${YOUR_DOMAIN}/ --recursive
#・ログ用のS3バケット作成
$ aws s3 mb s3://${YOUR_LOG_BUCKET}
$ mkdir clistatic
$ cd clistatic
$ cat << EOF > logging.json
{
"LoggingEnabled": {
"TargetBucket": "${YOUR_LOG_BUCKET}",
"TargetPrefix": "${YOUR_DOMAIN}/"
}
}
EOF
$ aws s3api put-bucket-acl --bucket ${YOUR_LOG_BUCKET} --grant-write URI=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-read-acp URI=http://acs.amazonaws.com/groups/s3/LogDelivery
$ aws s3api put-bucket-logging --bucket ${YOUR_DOMAIN} --bucket-logging-status file://logging.json
# 2.Route53でホストゾーン追加
$ aws route53 create-hosted-zone --name ${YOUR_DOMAIN} --caller-reference `date +%Y-%m-%d_%H-%M-%S`
※"DelegationSet": {"NameServers": のNSを登録する
# 3.ACM設定(Shell)
$ cat <<"EOF" >issue-certificate.sh
#!/bin/bash
set -e
if [ $# != 3 ] || [ $1 = "" ] || [ $2 = "" ] || [ $3 = "" ]; then
echo -e "Three parameters are required
1st - string: Hosted Domain Name on Route 53 (e.g. example.com)
2nd - string: Domain Name for Certificate (e.g. sub.mexample.com)
3rd - string: Target Region (e.g. us-east-1)
example command
\t sh ./issue-certificate.sh example.com sub.example.com"
exit
fi
HOSTED_DOMAIN=$1
TARGET_DOMAIN=$2
REGION=$3
NONE="None"
# request certificate
echo "Request certificate for '${TARGET_DOMAIN}' to ACM."
CERT_ARN=$( \
aws acm request-certificate \
--domain-name ${TARGET_DOMAIN} \
--validation-method DNS \
--region ${REGION} \
--output text) \
&& sleep 5 \
&& echo -e "\t CERT_ARN = ${CERT_ARN}"
# create domain validation record set
echo "Create record set to validate domain in Route 53."
VALIDATION_RECORD_NAME=$( \
aws acm describe-certificate \
--certificate-arn ${CERT_ARN} \
--query "Certificate.DomainValidationOptions[0].ResourceRecord.Name" \
--region ${REGION} \
--output text) \
&& echo -e "\t VALIDATION_RECORD_NAME = ${VALIDATION_RECORD_NAME}"
VALIDATION_RECORD_VALUE=$( \
aws acm describe-certificate \
--certificate-arn ${CERT_ARN} \
--query "Certificate.DomainValidationOptions[0].ResourceRecord.Value" \
--region ${REGION} \
--output text) \
&& echo -e "\t VALIDATION_RECORD_VALUE = ${VALIDATION_RECORD_VALUE}"
HOSTED_ZONE_ID=$( \
aws route53 list-hosted-zones \
--query "HostedZones[?Name=='${HOSTED_DOMAIN}.'].Id" \
--output text) \
&& echo -e "\t HOSTED_ZONE_ID = ${HOSTED_ZONE_ID}"
if [ $VALIDATION_RECORD_NAME == $NONE ] || [ $VALIDATION_RECORD_VALUE == $NONE ] || [ $HOSTED_DOMAIN == $NONE ]; then
echo "Failed to get the parameters required for domain validation."
exit
fi
CHANGE_ID=$( \
aws route53 change-resource-record-sets \
--hosted-zone-id ${HOSTED_ZONE_ID} \
--change-batch \
"{
\"Changes\": [
{
\"Action\": \"CREATE\",
\"ResourceRecordSet\": {
\"Name\": \"${VALIDATION_RECORD_NAME}\",
\"Type\": \"CNAME\",
\"TTL\": 300,
\"ResourceRecords\": [{\"Value\": \"${VALIDATION_RECORD_VALUE}\"}]
}
}
]
}" \
--query "ChangeInfo.Id" \
--output text) \
&& echo -e "\t Change ID : ${CHANGE_ID}\n"
if [ $? == 0 ]; then
echo -e "\nFinished to request certificate and create record set to validate domain.
Please run command bellow to check validation status.
aws acm describe-certificate \\
--certificate-arn ${CERT_ARN} \\
--query \"Certificate.DomainValidationOptions[0].ValidationStatus\" \\
--region ${REGION} \\
--output text"
else
echo -e "\nFailed to issue certificate."
fi
EOF
$ chmod 755 issue-certificate.sh
$ sh issue-certificate.sh ${YOUR_DOMAIN} ${YOUR_DOMAIN} us-east-1
#・ARN取得
$ aws acm list-certificates \
--query "CertificateSummaryList[?DomainName=='${YOUR_DOMAIN}'].CertificateArn" \
--region us-east-1 \
--output text
$ CERT_ARN=$(aws acm list-certificates \
--query "CertificateSummaryList[?DomainName=='{YOUR_DOMAIN}'].CertificateArn" \
--region us-east-1 \
--output text \
) && echo $CERT_ARN
#・ACM発行状況確認
$ aws acm describe-certificate \
--certificate-arn $CERT_ARN \
--query "Certificate.DomainValidationOptions[0].ValidationStatus" \
--region us-east-1 \
--output text
# 4.CloudFront設定
$ CALLERREFERENCE=`date +%Y%m%d%H%M%S`
$ cat << EOF > aws-cloudfront-distribution.json
{
"DistributionConfig": {
"CallerReference": "$CALLERREFERENCE",
"Aliases": {
"Quantity": 1,
"Items": [
"${YOUR_DOMAIN}"
]
},
"DefaultRootObject": "index.html",
"Origins": {
"Quantity": 1,
"Items": [
{
"Id": "S3-${YOUR_DOMAIN}",
"DomainName": "${YOUR_DOMAIN}.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
},
"OriginPath": "",
"CustomHeaders": {
"Quantity": 0
}
}
]
},
"OriginGroups": {
"Quantity": 0
},
"DefaultCacheBehavior": {
"TargetOriginId": "S3-${YOUR_DOMAIN}",
"TrustedSigners": {
"Enabled": false,
"Quantity": 0
},
"TrustedKeyGroups": {
"Enabled": false,
"Quantity": 0
},
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": [
"HEAD",
"GET"
],
"CachedMethods": {
"Quantity": 2,
"Items": [
"HEAD",
"GET"
]
}
},
"SmoothStreaming": false,
"Compress": false,
"LambdaFunctionAssociations": {
"Quantity": 0
},
"FunctionAssociations": {
"Quantity": 0
},
"FieldLevelEncryptionId": "",
"ForwardedValues": {
"QueryString": false,
"Cookies": {
"Forward": "none"
},
"Headers": {
"Quantity": 0
},
"QueryStringCacheKeys": {
"Quantity": 0
}
},
"MinTTL": 0,
"DefaultTTL": 3600,
"MaxTTL": 3600
},
"CacheBehaviors": {
"Quantity": 0
},
"CustomErrorResponses": {
"Quantity": 1,
"Items": [
{
"ErrorCode": 403,
"ResponsePagePath": "/404.html",
"ResponseCode": "404",
"ErrorCachingMinTTL": 300
}
]
},
"Comment": "",
"Logging": {
"Enabled": true,
"IncludeCookies": false,
"Bucket": "${YOUR_LOG_BUCKET}.s3.amazonaws.com",
"Prefix": "cf-web"
},
"PriceClass": "PriceClass_All",
"Enabled": true,
"ViewerCertificate": {
"CloudFrontDefaultCertificate": false,
"ACMCertificateArn": "$CERT_ARN",
"SSLSupportMethod": "sni-only",
"MinimumProtocolVersion": "TLSv1.2_2019",
"Certificate": "$CERT_ARN",
"CertificateSource": "acm"
},
"Restrictions": {
"GeoRestriction": {
"RestrictionType": "none",
"Quantity": 0
}
},
"WebACLId": "",
"HttpVersion": "http2",
"IsIPV6Enabled": true
}
}
EOF
$ aws cloudfront create-distribution --cli-input-json file://aws-cloudfront-distribution.json
※OAIは手動更新(マネジメントコンソールのオリジンの箇所から更新できる)
# 5.Aレコードへのエイリアス追加
#・クラウドフロント情報取得
$ CLOUDFRONT_URL=$(aws cloudfront list-distributions \
--query "DistributionList.Items[].{DomainName: DomainName, OriginDomainName: Aliases.Items[0]}[? OriginDomainName == '${YOUR_DOMAIN}'] | [0].DomainName"\
--output=text \
) && echo $CLOUDFRONT_URL
$ cat << EOF > createarecode.json
{
"Comment": "Creating Alias resource record sets in Route 53",
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "${YOUR_DOMAIN}",
"Type": "A",
"AliasTarget":{
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "$CLOUDFRONT_URL",
"EvaluateTargetHealth": false
}}
}]
}
EOF
#・Aレコードを登録
$ HOSTED_ZONE_ID=$( \
aws route53 list-hosted-zones \
--query "HostedZones[?Name=='${YOUR_DOMAIN}.'].Id" \
--output text)
$ aws route53 change-resource-record-sets --hosted-zone-id ${HOSTED_ZONE_ID} --change-batch file://createarecode.json
・OAIの設定箇所
◆参考サイト
・AWS-CLIバージョンアップ
https://yatta47.hateblo.jp/entry/2021/01/23/112931
https://cloud5.jp/aws-cli-versionup-linux/
・Route53
・ACM設定
・CloudFront関連
次回はAzureの方をやりたいと思います。AzureもGUIではなく、できればコマンドラインでやっちゃいたいものですな。手順はこんな感じです。
1.Blobストレージ静的サイト作成
・ストレージアカウント作成
・Blob作成
・静的サイトホスティング有効
2.ZeroSSLで証明書作成
・DNS検証で設定
・PFXファイルに変換
3.Application Gateway設定
・バックエンドにBlobの静的サイト設定
・フロントエンドは固定IP設定
・PFXファイルアップロード
では、またの機会に

コメント