GCPの静的サイトホスティングをCloudDeploymentManagerで構築してみる
前回はAWSでしたが、今回はGCPにチャレンジしてみました。CloudDeploymentManagerでLBを使った静的サイトホスティングの構成を構築できるようにしてみようというやつです。
日本語で同じようなことやってるサイトがあまりなく、英語サイトからの丸パクリです。ツヨツヨな人でないとGoogleはハードルが高いです。公式ドキュメント読んでもさっぱりだし、自分のダメさ加減を痛感します。
相変わらずへっぽこですが、何かの時に使うかもしれないので備忘録でメモとしておいておこうかと思い公開した次第です。ご指摘とかアドバイスあれば頂戴できると幸いです。2021年2月20日時点の情報です。
・環境
Google Cloud SDK 327.0.0 alpha 2021.02.05 app-engine-python 1.9.91 beta 2021.02.05 bq 2.0.64 cloud-datastore-emulator 2.1.0 core 2021.02.05 gsutil 4.58 Linux/5.4.0-65-generic Python 3.7.7
◆作成したもの
1.ディレクトリ構造
|-- create_stack.sh |-- delete_stack.sh `-- yaml |-- backendbuckets-template.jinja |-- dns-template.jinja |-- httpproxies-template.jinja |-- ipaddress-template.jinja |-- loadbalancer-template.jinja |-- ssl-template.jinja |-- static-site-create.yaml `-- storage-template.jinja
2.シェルスクリプト群
スタック構築のテンプレートを呼び出すShellスクリプト
・create_stack.sh
#!/bin/bash cd `dirname $0` SLEEP_TIME=30 HTTP_STATUS_CODE=200 if [ $# != 1 ]; then echo "Empty Domain! Please [./create_stacks.sh example.com]" exit 1 fi domain=$1 sitename=${domain/./-} cp yaml/static-site-create.yaml yaml/${sitename}-static-site-create.yaml sed -i -e "s/SITENAME/${sitename}/g" -e "s/DOMAIN/${domain}/g" yaml/${sitename}-static-site-create.yaml echo "*** Deploymentmanager Run ***" gcloud deployment-manager deployments create ${sitename}-static-site-deployment --config yaml/${sitename}-static-site-create.yaml echo "*** dnssec on ***" gcloud dns managed-zones update ${sitename}-dnszone --dnssec-state on echo "*** Web Sit Setting ***" gsutil rsync -R ~/html/dist/ gs://site-${sitename} gsutil iam ch allUsers:objectViewer gs://site-${sitename} gsutil web set -m index.html -e 404.html gs://site-${sitename} echo "*** Please Setting Your Domain Nameserver ***" ns_records=$(gcloud dns record-sets list \ --zone="${sitename}-dnszone" \ --name="${domain}" \ --type="NS" \ | grep -oP "ns-cloud-[0-9a-zA-Z?=#+_&:/.%]+") array=(${ns_records//$'\n'/ }) for i in ${array[@]} do echo ${i} done echo "*** http statuscode check ***" while true do echo "Check now please wait・・・" sleep ${SLEEP_TIME} naked_code=$(echo $(curl -s https://${domain} -o /dev/null -w "%{http_code}\n")) www_code=$(echo $(curl -s https://www.${domain} -o /dev/null -w "%{http_code}\n")) if [ "$naked_code" -eq "$HTTP_STATUS_CODE" ] && [ "$www_code" -eq "$HTTP_STATUS_CODE" ]; then break fi done echo "*** Setting Complete ***"
スタックを削除するShellスクリプト
・delete_stack.sh
#!/bin/bash cd `dirname $0` if [ $# != 1 ]; then echo 'Empty Domain! Please [./deletestack.sh example.com]' exit 1 fi domain=$1 sitename=${domain/./-} gsutil rm gs://site-${sitename}/** echo '*** Delete Stack ***' gcloud deployment-manager deployments delete ${sitename}-static-site-deployment rm yaml/${sitename}-static-site-create.yaml
3.DeploymentManagerテンプレート
全体のテンプレートをまとめて実行するテンプレートです
・static-site-create.yaml
imports: - path: ipaddress-template.jinja - path: dns-template.jinja - path: ssl-template.jinja - path: storage-template.jinja - path: backendbuckets-template.jinja - path: loadbalancer-template.jinja - path: httpproxies-template.jinja resources: - name: ipaddress type: ipaddress-template.jinja properties: site-name: SITENAME - name: dnsrecords type: dns-template.jinja properties: site-name: SITENAME site-domain: DOMAIN static-ip-v4-addr: $(ref.ipaddress.ipv4) static-ip-v6-addr: $(ref.ipaddress.ipv6) - name: sslcertificates type: ssl-template.jinja properties: site-name: SITENAME site-domain: DOMAIN - name: storagebucket type: storage-template.jinja properties: site-name: SITENAME - name: backendbuckets type: backendbuckets-template.jinja properties: site-name: SITENAME - name: loadbalancer type: loadbalancer-template.jinja properties: backend-buckets: $(ref.backendbuckets.backend) site-name: SITENAME - name: httpproxies type: httpproxies-template.jinja properties: site-name: SITENAME ssl-certificate: $(ref.sslcertificates.cert) http-urlmap: $(ref.loadbalancer.http) https-urlmap: $(ref.loadbalancer.https) ipv4: $(ref.ipaddress.ipv4) ipv6: $(ref.ipaddress.ipv6)
固定IP取得用テンプレートです(IP-V4,V6両方を取得)
・ipaddress-template.jinja
resources: - name: {{ properties["site-name"] }}-ipv4 type: compute.v1.globalAddress properties: ipVersion: IPV4 - name: {{ properties["site-name"] }}-ipv6 type: compute.v1.globalAddress properties: ipVersion: IPV6 outputs: - name: ipv4 value: $(ref.{{ properties["site-name"] }}-ipv4.address) - name: ipv6 value: $(ref.{{ properties["site-name"] }}-ipv6.address)
DNSゾーンを作成しAとAAAAレコードを登録するテンプレート
・dns-template.jinja
resources: - name: {{ properties["site-name"] }}-dnszone type: gcp-types/dns-v1:managedZones properties: description: StaticSiteSample dnsName: {{ properties["site-domain"] }}. dnssecConfig.state: on - name: {{ properties["site-name"] }}-naked-a-record type: gcp-types/dns-v1:resourceRecordSets properties: name: tohonokai.cf. managedZone: $(ref.{{ properties["site-name"] }}-dnszone.name) records: - name: {{ properties["site-domain"] }}. type: A ttl: 300 rrdatas: - {{ properties["static-ip-v4-addr"] }} - name: {{ properties["site-name"] }}-www-a-record type: gcp-types/dns-v1:resourceRecordSets properties: name: www.{{ properties["site-domain"] }}. managedZone: $(ref.{{ properties["site-name"] }}-dnszone.name) records: - type: A ttl: 300 rrdatas: - {{ properties["static-ip-v4-addr"] }} - name: {{ properties["site-name"] }}-naked-aaaa-record type: gcp-types/dns-v1:resourceRecordSets properties: name: tohonokai.cf. managedZone: $(ref.{{ properties["site-name"] }}-dnszone.name) records: - name: {{ properties["site-domain"] }}. type: AAAA ttl: 300 rrdatas: - {{ properties["static-ip-v6-addr"] }} - name: {{ properties["site-name"] }}-www-aaaa-record type: gcp-types/dns-v1:resourceRecordSets properties: name: www.{{ properties["site-domain"] }}. managedZone: $(ref.{{ properties["site-name"] }}-dnszone.name) records: - type: AAAA ttl: 300 rrdatas: - {{ properties["static-ip-v6-addr"] }}
GoogleマネージドSSL発行用のテンプレート
・ssl-template.jinja
resources: - name: {{ properties["site-name"] }}-ssl type: compute.v1.sslCertificate properties: type: MANAGED managed: domains: - {{ properties["site-domain"] }} - www.{{ properties["site-domain"] }} outputs: - name: cert value: $(ref.{{ properties["site-name"] }}-ssl.selfLink)
静的ホスティング用とログ用のストレージ作成用テンプレート
・storage-template.jinja
resources: - name: log-{{ properties["site-name"] }} type: gcp-types/storage-v1:buckets properties: predefinedAcl: projectPrivate projection: full location: asia-east2 storageClass: REGIONAL - name: site-{{ properties["site-name"] }} type: gcp-types/storage-v1:buckets properties: location: asia locationType: multi-region defaultObjectAcl: - bucket: {{ properties["site-name"] }} entity: allUsers role: READER website: mainPageSuffix: index.html notFoundPage : 404.html logging: logBucket: $(ref.log-{{ properties["site-name"] }}.name) logObjectPrefix: {{ properties["site-name"] }} outputs: - name: sitebucket value: $(ref.site-{{ properties["site-name"] }}.name) - name: logbucket value: $(ref.log-{{ properties["site-name"] }}.name)
・backendbuckets-template.jinja
resources: - name: {{ properties["site-name"] }}-backend type: compute.beta.backendBucket properties: bucketName: $(ref.site-{{ properties["site-name"] }}.name) outputs: - name: backend value: $(ref.{{ properties["site-name"] }}-backend.selfLink)
URLマップ作成用テンプレート
・loadbalancer-template.jinja
resources: - name: {{ properties["site-name"] }}-http-urlmap type: compute.v1.urlMap properties: defaultUrlRedirect: httpsRedirect: true redirectResponseCode: MOVED_PERMANENTLY_DEFAULT - name: {{ properties["site-name"] }}-https-urlmap type: compute.v1.urlMap properties: defaultService: {{ properties["backend-buckets"] }} hostRules: - hosts: ["*"] pathMatcher: "allpaths" pathMatchers: - name: "allpaths" defaultService: {{ properties["backend-buckets"] }} pathRules: - service: {{ properties["backend-buckets"] }} paths: ["/*"] outputs: - name: http value: $(ref.{{ properties["site-name"] }}-http-urlmap.selfLink) - name: https value: $(ref.{{ properties["site-name"] }}-https-urlmap.selfLink)
httpプロキシ作成用テンプレート
・httpproxies-template.jinja
resources: - name: {{ properties["site-name"] }}-http-proxy type: compute.v1.targetHttpProxy properties: urlMap: {{ properties["http-urlmap"] }} - name: {{ properties["site-name"] }}-https-proxy type: compute.v1.targetHttpsProxy properties: urlMap: {{ properties["https-urlmap"] }} sslCertificates: - {{ properties["ssl-certificate"] }} - name: lb-{{ properties["site-name"] }}-http-v4-forwardingrule type: compute.v1.globalForwardingRule properties: target: $(ref.{{ properties["site-name"] }}-http-proxy.selfLink) IPAddress: {{ properties["ipv4"] }} IPProtocol: TCP portRange: 80-80 - name: lb-{{ properties["site-name"] }}-http-v6-forwardingrule type: compute.v1.globalForwardingRule properties: target: $(ref.{{ properties["site-name"] }}-http-proxy.selfLink) IPAddress: {{ properties["ipv6"] }} IPProtocol: TCP portRange: 80-80 - name: lb-{{ properties["site-name"] }}-https-v4-forwardingrule type: compute.v1.globalForwardingRule properties: target: $(ref.{{ properties["site-name"] }}-https-proxy.selfLink) IPAddress: {{ properties["ipv4"] }} IPProtocol: TCP portRange: 443-443 - name: lb-{{ properties["site-name"] }}-https-v6-forwardingrule type: compute.v1.globalForwardingRule properties: target: $(ref.{{ properties["site-name"] }}-https-proxy.selfLink) IPAddress: {{ properties["ipv6"] }} IPProtocol: TCP portRange: 443-443
DNSの伝播がとんでもなく遅いのであまり意味ないかもしれないけどCloudDNSのSOAレコードとNSレコードのTTLを300秒程度に手動で変更してたりしています。まぁ意味ないんでしょうけど・・・
そしてDNSとかSSLが絡むと自動化の難易度が一気に上がって辛くなります。いよいよ本丸のTerraformかな・・・。
◆参考サイト
・コピペ元(w
・CloudDeploymentManager
https://cloud.google.com/deployment-manager/docs/quickstart?hl=ja
https://qiita.com/shotaTsuge/items/bb995f4e2f3f6ae9d12d
https://future-architect.github.io/articles/20200219/
https://cloud.google.com/deployment-manager/docs
https://github.com/GoogleCloudPlatform/deploymentmanager-samples/tree/master/templates
https://qiita.com/shojimotio/items/f303007e9d9b900d5b52
https://dev.classmethod.jp/articles/gcp-cloud-deployment-manager-cloud-functions/
https://cloud.google.com/deployment-manager/docs/configuration/supported-resource-types?hl=ja
https://cloud.google.com/deployment-manager/docs/configuration/use-references?hl=ja
https://cloud.google.com/deployment-manager/docs/configuration/syntax-reference?hl=ja
https://cloud.google.com/deployment-manager/docs/configuration/expose-information-outputs?hl=ja
https://cloud.google.com/deployment-manager/docs/at-scale?hl=ja
https://pc.atsuhiro-me.net/entry/2021/01/04/200658
https://this.aereal.org/entry/2018/08/21/192317
・サンプルのテンプレート
https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/tree/master/dm/templates/gcs_bucket
・外部IPアドレス予約
https://cloud.google.com/sdk/gcloud/reference/compute/addresses/create
https://cloud.google.com/compute/docs/reference/rest/v1/addresses?hl=ja
https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address?hl=ja
・CloudDNS
https://yukidarake.hateblo.jp/entry/2016/04/26/203318
https://cloud.google.com/dns/docs/records?hl=ja#gcloud
https://plugaru.org/2018/08/21/managing-dns-zones-with-gcp-deployment-manager/
・ロードバランサー
https://cloud.google.com/load-balancing/docs/ipv6
https://codeblog.dotsandbrackets.com/external-load-balancer/
https://stackoverflow.com/questions/54959122/ssl-issues-with-jinja-https-load-balancer-google-cloud
https://stackoverflow.com/questions/58920827/gcp-cloud-deployment-load-balancer-backend-bucket
https://ja.ojit.com/so/google-cloud-platform/3835319
https://yamavlog.com/gcp-loadblancer-redirect-https/
・GCSの作成
https://cloud.google.com/storage/docs/json_api/v1/buckets?hl=ja
https://dev.classmethod.jp/articles/gs-deployment-manager-gcs-bigquery-create/
https://zenn.dev/nekoshita/articles/5730d79bc39a20
https://cloud.google.com/storage/docs/access-logs?hl=ja
・SSL証明書
https://stackoverflow.com/questions/55376106/use-cloud-deployment-manager-to-upload-ssl-certificates
https://cloud.google.com/compute/docs/reference/rest/v1/sslCertificates
https://cloud.google.com/load-balancing/docs/ssl-certificates/google-managed-certs?hl=ja#api
https://tutorialmore.com/questions-302176.htm
https://github.com/GoogleCloudPlatform/gke-managed-certs/issues/13
・その他
https://dominicusin.github.io/2019/07/25/gcloud-cheat-sheet.html
コメント