Day 8 – 部署靜態網頁

前面說了這麼多的 API 部署,差不多也該來個網頁了,今天就來教大家如何部署一個靜態網頁吧!

https://ithelp.ithome.com.tw/upload/images/20200924/20117701Rqhfw3U79A.jpg

創建靜態網頁專案

創建專案

$ mkdir cdk-static-site && cd cdk-static-site
$ cdk init --language typescript

準備我們需要的 package

要創建一個靜態網頁我們需要幾個服務,我們先把它列出來

  • s3: 存放靜態網頁的地方
  • ACM: 網頁需要 HTTPS 憑證
  • CloudFront: 使用者開啟網頁第會先到 CDN 再讓 CDN 去 S3 取得靜態網頁檔 都想好了就先把我們需要的 package 裝起來吧!每次要裝的 npm package 其實都滿多的,這邊來教大家一個快速裝 npm package 的方法 我們因為的專案都是來自於 @aws-cdk 只有後面的專案名稱不一樣就可以用快速指令把它串接起來,如此就可以一行指令快速的把 package 裝起來了
$ npm install @aws-cdk/{aws-s3,aws-s3-deployment,aws-certificatemanager,aws-cloudfront}

準備 S3 Bucket

用過 S3 的朋友都知道如果要把東西放到 S3 要先創建 S3 Bucket,在這邊我以 "static.cdk.clarence.tw" 為 S3 Bucket 名稱同時也是網址名稱來創建 因為我們是要創建靜態網頁 Bucket 所以有幾個參數需要準備:

  • 必填欄位:
    • websiteIndexDocument: 網頁的起始檔案通常都是 index.html
    • publicReadAccess: 網頁要可以 public 存取,如果不行 public 就不用看網頁了對吧 XD
  • 選填欄位:
    • websiteErrorDocument: 網頁錯誤時預設檔案名稱
  • 開發欄位:
    • removalPolicy: 填入 cdk.RemovalPolicy.DESTROY 在我們執行 destory 的時候就會順便把它移除掉比較方便 debug,不建議放在正式專案大家要記得啊!
const siteDomain = "static.cdk.clarence.tw";

const siteBucket = new s3.Bucket(this, "SiteBucket", {
  bucketName: siteDomain,
  websiteIndexDocument: "index.html",
  websiteErrorDocument: "error.html",
  publicReadAccess: true,

  removalPolicy: cdk.RemovalPolicy.DESTROY,
});

建立 ACM

因為創建 CloudFront 需要放入 ACM 因此這邊有兩個選擇

  1. 使用 acm.Certificate 創建新的 ACM
  2. 使用 Certificate.fromCertificateArn 給予 ACM 的 arn 創建 ACM 物件

1. 使用 acm.Certificate

這邊要請大家注意因為 CloudFront 只可以使用 us-east-1 的 ACM 因此如果專案不是部署在 us-east-1 就只能使用方法二了

const cert = new acm.Certificate(this, "Certificate", {
  domainName: "static.cdk.clarence.tw",
  validation: acm.CertificateValidation.fromDns(),
});

2. 使用 Certificate.fromCertificateArn

const cert = acm.Certificate.fromCertificateArn(
  this,
  "Certificate",
  "arn:aws:acm:us-east-1:888888888888:certificate/9d2306e2-420d-48df-b934-1bd21bf1ce73"
);

創建 CloudFront 並且與 S3 串接

在這邊我們使用 CloudFrontWebDistribution 來部署我們的 CloudFront 首先要注意的是 viewerCertificate 因為我們這次的範例是要使用自己的網域所以才要填這個參數,如果未來是想要使用 CloudFront 網域可以不用填,這邊還要注意的是 aliases 它本身是一個 Array 因此可以填入多個的如果有多網域需求可以在這邊增加 接下來是 s3BucketSource 填入我們的 S3 Bucket 即可

const distribution = new cloudfront.CloudFrontWebDistribution(
  this,
  "Distribution",
  {
    viewerCertificate: cloudfront.ViewerCertificate.fromAcmCertificate(
      cert,
      {
        aliases: [siteDomain],
        securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1, // default
        sslMethod: cloudfront.SSLMethod.SNI, // default
      }
    ),
    originConfigs: [
      {
        s3OriginSource: {
          s3BucketSource: siteBucket,
        },
        behaviors: [{ isDefaultBehavior: true }],
      },
    ],
  }
);

上傳打包檔案到 S3 Bucket

不知道在前面的準備 package 步驟大家有沒有發現我偷渡了一個 package 這邊有一個很好用的 package aws-s3-deployment,使用此 package 只要在我們的專案旁邊建立一個資料夾把網頁放進去剩下的事情就交給 BucketDeployment 處理就好了,這邊範例我創建了一個叫做 website-dist 的資料夾來放 Demo 網頁

new s3deploy.BucketDeployment(this, "DeployWebsite", {
  sources: [s3deploy.Source.asset("./website-dist")],
  destinationBucket: siteBucket,
  distribution,
});

測試網頁

為了方便講解我這邊也提供一個範例網頁給大家測試一下

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>第 12 屆 iT 邦幫忙鐵人賽!</title>
  </head>
  <body>
    <p>用 CDK 定義 AWS 架構 AWS Lambda!</p>
  </body>
</html>

部署 CDK

第一次在 us-east-1 執行

建立 ACM 有提到 CloudFront 只能吃 us-east-1,所以特別為之前專案不是在 us-east-1 使用的朋友建立一個解說 第一次在 us-east-1 使用 CDK 的朋友需要先執行 cdk bootstrap 在這邊教大家如果只有此次專案想要執行在不同 region 可以使用 AWS_DEFAULT_REGION 這個專用的 env 來指定,後面再加上要執行的指令即可

$ AWS_DEFAULT_REGION=us-east-1 cdk bootstrap
$ AWS_DEFAULT_REGION=us-east-1 cdk deploy

如果出現

❌  CdkStaticSiteStack failed: Error: This stack uses assets, so the toolkit stack must be deployed to the environment (Run "cdk bootstrap aws://unknown-account/unknown-region")

就是因為還沒執行過 cdk bootstrap

之前專案都在 us-east-1 執行

直接執行

$ cdk deploy

看一下結果吧!

https://ithelp.ithome.com.tw/upload/images/20200922/20117701O79tNUhi5M.png

今日主題教大家如何部署靜態網頁希望有幫助到大家,其實在實作這個專案的時候踩了很多雷會在下一篇分享給大家,然後還會帶大家看看 ACM 實作的方法與目前 CDK 的一些限制,希望大家會喜歡 ~