使用Gitlab CI + S3 + Cloudfront佈署靜態網站

2024/10/17

AWS前置設定

 

建立IAM User

這個IAM User之後要提供給Gitlab CI使用

讓Gitlab CI可以自動將web上傳至s3

並且清除Cloudfront cache

 

以下為參考permission json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "cloudfront:GetInvalidation",
                "cloudfront:CreateInvalidation"
            ],
            "Resource": "*"
        }
    ]
}

 

{
	"Version": "2012-10-17",
	"Statement": [
			{
					"Sid": "VisualEditor0",
					"Effect": "Allow",
					"Action": [
							"s3:DeleteObject",
							"s3:PutObject",
							"s3:ListBucket",
							"s3:GetObjectAcl",
							"s3:PutBucketAcl",
							"s3:GetObject",
							"s3:PutObjectAcl",
							"s3:GetBucketAcl",
							"s3:GetBucketLocation"
					],
					"Resource": [
							"arn:aws:s3:::web-bucket",
							"arn:aws:s3:::web-bucket/*"
					]
			},
			{
				"Sid": "VisualEditor1",
				"Effect": "Allow",
				"Action": [
					"s3:ListAllMyBuckets"
				],
				"Resource": "*"
			}
			
	]
}

 

設定S3 bucket

建立一個bucket

將「封鎖所有公開存取權」功能「關閉」

物件擁有權設定為「物件寫入器」

image.png

 

並啟用靜態網站託管

image.png

 

Gitlab CI設定

 

設定CI/CD Variable

  • Key: AWS_SHARED_CREDENTIALS_FILE
  • Type: File
  • Value: 設定前面的IAM key, 用來讓Gitlab CI可以更新S3及設定CloudFront, 格式如下
[default]
aws_access_key_id = aws_access_key_id
aws_secret_access_key = aws_secret_access_key

 

設定.gitlab-ci.yml

variables:
  WEB_DOMAIN: example.com

stages:
  - test
  - build
  - deploy

# build nuxt並存至gitlab artifact
build:
  stage: build
  image: node:20
  cache:
    paths:
      - frontend/node_modules
  only:
    variables:
      - $CI_COMMIT_TAG =~ /build/
  script:
    - cd $CI_PROJECT_DIR/frontend
    - yarn
    - yarn generate
    - cp -r $CI_PROJECT_DIR/frontend/.output/public $CI_PROJECT_DIR/web-artifact
  artifacts:
    name: $CI_COMMIT_SHORT_SHA
    expire_in: 1 hour
    paths:
      - $CI_PROJECT_DIR/web-artifact

# 將前面build好的nuxt site上傳至指定s3 bucket中
deploy:
  stage: deploy
  image:
    name: amazon/aws-cli
    entrypoint: [ "" ]
  variables:
    BUCKET_NAME: my-web-bucket
  only:
    variables:
      - $CI_COMMIT_TAG =~ /deploy/
  dependencies:
    - build
  script:
    - aws s3 rm s3://$BUCKET_NAME/ --recursive
    - |
      aws s3 sync ./web-artifact s3://$BUCKET_NAME/ \
      --acl public-read \
      --cache-control "max-age=31536000"

 

測試

透過git tag的方式觸發build/deploy job

並確認網站是否能夠正確上傳至s3

image.png

 

完成後

可以先上s3 bucket確認是否有檔案

並且到s3的靜態網站託管設定中取得網站endpoint

直接在瀏覽器存取看看

基本上有看到網站正常呈現就代表成功

 

透過Cloudfront對網站進行cache

 

先建立自訂的s3-website policy

image.png

Headers設定

  • Origin
  • x-method-override
  • Referer
  • x-http-method
  • x-http-method

並啟用br/gzip壓縮

因為後續每次更新網站都會自動使用cloudfront invalidation

因此TTL可以直接設定成一年(31536000秒)

 

建立distribution

image.png

origin domain選擇其面建立的web s3 bucket

 

cache的部份

image.png

建立完成之後要等它佈署一下

佈署完成後

直接用瀏覽器存取cloudfront的endpoint

確認有看到網站就代表成功

如果要確認是否有cache成功

可以開啟chrome developer tool查看network

資源請求如果response header有X-Cache: Hit from cloudfront就代表cache成功

 

Gitlab CI調整在更新後執行CloudFront invalidation

因為cloud front本身會進行cache

如果再佈署網站沒有清除cache的話會吃到舊的資源

因此需要再調整.gitlab-ci.yml的deploy job

在網站更新至s3後清除cache

aws cloudfront create-invalidation \
        --distribution-id $CLOUDFRONT_DISTRIBUTION_ID \
        --paths "/*"

若要額外自訂invalidation規則

可參考此文件

 

 

使用自訂domain

通常我們不會直接使用cloudfront的預設domain

因為他是無意義的名稱

因此我們需要設定自訂網域

 

AWS Certificate Manger設定

前往AWS Certificate Manger設定頁面

region選擇us-east-1(virginia)

因為cloudfront自訂網域只接受us-east-1的的憑證

 

接著請求一個公有憑證

驗證方式依照需求

這邊使用DNS驗證

image.png

 

DNS設定

憑證建立完成之後

會產生一個驗證個CNAME規則

至設定DNS好規則後即可

另外也需要使用CNAME規則將自己的網域指向cloudfront的原始網域

需要等待一下讓Certificate Manger驗證

等驗證成功後

即可進行下一步至Cloudfront設定

image.png

 

Cloudfront設定調整

前往cloudfront設定備用網域

image.png

 

Done!

接著等待cloudfront更新完成即可