iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0

今天的主題是幫我們的 Laravel web service 加上 CDN(Content Delivery Network 或 Content Distribution Network),讓使用者可以更快取得取得服務。AWS 的 CDN 服務是 Cloudfront,是個 global 層級的服務。

之前用 ALB DNS name 連 Laravel 的時候是用 HTTP 連線,但在這時代沒有 HTTPS 大概是很難過下去(?)的,我們要在 ALB 前面加上 CDN,並且由 CDN 提供 HTTPS 的存取。這麼做可以讓從 CDN 往 cloud 內部的 network traffic 都不需要再做加解密的動作,因為已經在 cloud 內部是可以不用在傳輸時加密,稍微可以提昇 performance。

使用 Cloudfront 會需要一個 domain name,我們會以 Route 53 管理的 domain name 來實作。那~就開始吧~(本日程式碼

新增 certificate

要有 HTTPS 要有個有效的 certificate,可以到 AWS Certificate Manager(ACM)產生,給 Cloudfront 用的 certificate 必須建立在 us-east-1 region。

點右上角 request 按鈕:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671Vxj7xk2Fhp.png

進到 request certificate 頁面,直接 Next:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671HYJSELngqT.png

接著輸入準備要給 Laravel web application 使用的 domain name,並且用 DNS validation:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671QSgqvtW4jk.png

request 後會在 list 看到 pending 的 certificate:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671kGM5CS6NpH.png

我們使用 DNS 驗證,它利用在 DNS 加上指定的 record name 跟 value 來確認 domain 確實是申請人所有。如果是用 Route 53,可以直接進到 certificate 的頁面,在 Domains 點 Create records in Route 53:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671ZmcNDAoi3X.png

https://ithelp.ithome.com.tw/upload/images/20231007/20160671U5q9MtkL9E.png

Route 53 的 record:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671tcjVJEoimf.png

一旦驗證機制查到確實有相符的 DNS record,就能確定這個 domain 確實是申請人擁有。等個幾分鐘應該會 issue 完成:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671T8FShUduCB.png

如果不是用 Route 53,就要依據 certificate 中 Domains 的資訊到 DNS 設定 record 完成驗證。

建立 Cloudfront Distribution

要用 cloudfront 來 distribute 我們的資料時,就是要建立一個 distribution,它會設定資料來源(origin)、安全性(使用 https)、cache 等等。

首先開個存 cdn log 用的 s3 bucket:

resource "aws_s3_bucket" "cf_log" {
    bucket = "my-app-cdn-log"
}

resource "aws_s3_bucket_ownership_controls" "cf_log" {
  bucket = aws_s3_bucket.cf_log.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

接著加入 cloudfront distribution 的 resource:

resource "aws_cloudfront_distribution" "cdn" {
  enabled         = true
  comment         = "Laravel"
  is_ipv6_enabled = true
  aliases         = [var.domain]

  viewer_certificate {
    acm_certificate_arn            = var.domain_cert_arn
    cloudfront_default_certificate = false
    minimum_protocol_version       = "TLSv1.2_2021"
    ssl_support_method             = "sni-only"
  }

  origin {
    origin_id   = aws_lb.alb.dns_name
    domain_name = aws_lb.alb.dns_name
    connection_attempts = 3
    connection_timeout  = 10
    custom_origin_config {
      http_port                = 80
      https_port               = 443
      origin_keepalive_timeout = 5
      origin_protocol_policy   = "http-only"
      origin_read_timeout      = 60
      origin_ssl_protocols     = [
        "TLSv1",
        "TLSv1.1",
        "TLSv1.2"
      ]
    }
  }

  default_cache_behavior {
    allowed_methods          = ["GET", "HEAD", "DELETE", "POST", "PUT", "PATCH", "OPTIONS"]
    cached_methods           = ["GET", "HEAD"]
    target_origin_id         = aws_lb.alb.dns_name
    viewer_protocol_policy   = "redirect-to-https"
    compress                 = true
    cache_policy_id          = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled
    origin_request_policy_id = "216adef6-5c7f-47e4-b989-5492eafa07d3" # AllViewer
  }

  # 不做限制
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  logging_config {
    bucket          = aws_s3_bucket.cf_log.bucket_domain_name
    include_cookies = false
    prefix          = "cdn"
  }
}

其中變數 domain 是要給這個 distribution 用的 domain name,也就是剛剛 certificate 的 domain。distribution 會有個自己的 domain name,但長得很亂碼(下面會看到),應該是沒人記得起來,所以通常會用個好記的 domain 指過去。

變數 domain_cert_arn 則是剛剛產生的 certificate 的 ARN,viewer_certificate 內指定一些跟安全性有關的設定,細節可以參考 文件

origin block 是設定要透過 cdn distribute 的資料來源(content origin),我們的資料來源是 ALB,所以在 domain_name 指定 ALB 的 domain。並且設定是以 HTTP 取得 origin 的內容,因為我們的 ALB 是開啟 HTTP,不是用 HTTPS~

接下來設定 behavior——連到 distribution 的某個 path 時要給什麼資料。一定要設定一個 default behavior,也就是這邊的 default_cache_behavior block。behavior 會看 request 的 path,看符合哪個 behavior 的 path pattern,就把 request 送向 behavior 指定的 origin,並且依據 cache、viewer protocol 等 policy 將 response 回給 client。如果 request 的 path 不符合所有 pattern,就會用 default behavior。

上面 distribution 的 default behavior 會長這樣:

https://ithelp.ithome.com.tw/upload/images/20231007/201606717LdfPJNnG1.png

我們允許所有 HTTP method 並且對 GET 跟 HEAD 做 cache,這個 behavior 的 origin 是 ALB,client 如果用 HTTP 連線會被轉去 HTTPS。

default_cache_behavior 的設定可以看到有兩個寫死的 policy id,它們是 AWS 管理的 policy,但寫死 id 不好、沒有註解就看不懂是什麼,我們把它改成比較好的寫法:用 data source 取得 AWS 管理的 policy。

data "aws_cloudfront_cache_policy" "caching_disabled" {
  name = "Managed-CachingDisabled"
}

data "aws_cloudfront_origin_request_policy" "all_viewer" {
    name = "Managed-AllViewer"
}

resource "aws_cloudfront_distribution" "cdn" {
  default_cache_behavior {
    ...(ignored)
    cache_policy_id          = data.aws_cloudfront_cache_policy.caching_disabled.id
    origin_request_policy_id = data.aws_cloudfront_origin_request_policy.all_viewer.id
  }
}

Day 20 我們有用過 data source 處理 task definition 的版本問題,現在則是用來取得 AWS 管理的 cloudfront 相關 policy 的 resource,避免使用看起來像 magic number 的 hard code id。

logging_config 設定前面的 s3 bucket 作為存 log 的地方,prefix 是 log 所在的 folder,像這邊寫 cdn 就表示 log 檔案們會存在 bucket 的 cdn/ 底下。

確認 CDN 運作

設定好 cloudfront distribution,可以用 distribution domain name 連到 Laravel:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671rX2BwHo4cr.png

最後到 Route 53 新增 record 把 domain 指到 distribution domain name:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671Iy1hY5AdDX.png

在 Route 53 裡可以直接用 A record 的 alias 指到 distribution:

https://ithelp.ithome.com.tw/upload/images/20231007/20160671yZXImXoYMa.png

如果是用其他服務管理 DNS,就要加上 CNAME record。

最後確認 domain 可以連上、而且是 https:

https://ithelp.ithome.com.tw/upload/images/20231007/201606717Fcr0sq0NG.png


上一篇
Day 26 邁向 High Availability
下一篇
Day 28 CDN cache 與 CodePipeline 清 cache
系列文
AWS ECS + Gitlab + Laravel + Terraform 從入門到摔坑30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言