iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
DevOps

AWS ECS + Gitlab + Laravel + Terraform 從入門到摔坑系列 第 11

Day 11 配合 ALB 的 ECS Service

  • 分享至 

  • xImage
  •  

綜合前兩天的基本 ECS service 跟 load balancing,我們要來幫 ECS service 加上 load balancing 了!(本日程式碼

調整 Task Definition 的 container port mapping

第一件要做的事情是調整 task definition 的 container port mapping。前面有說到 task definition 不能修改、只能建立新版本,所以我們從右上角 create new revision:

https://ithelp.ithome.com.tw/upload/images/20230921/201606711at7g0bu21.png

記得前面 Day 8 我們建立 task definition 的時候是讓 container 的 port 80 對應到 host 的 port 80 嗎?(不記得的話回去翻一下)

這樣的 mapping 表示一台 host(即 container instance)上只能開一個 container,因為 host 的 port 80 被佔走啦~第二台 container 要再做 port mapping 的時候就會失敗,也就開不起來。欸不是,一個 container instance 只能開一個 container 是在搞笑嗎?這樣即使用大台機器也沒用啊~也不需要 container 了吧…… (開始思考人生意義)

ECS 當然沒那麼難用,除了原本的 static port mapping 外,它還有另一種 port mapping 稱為 dynamic port mapping。我們現在就是要調整 task definition 裡的 container port mapping,從 static port mapping 改成 dynamic port mapping。

static port mapping 就是原本直接指定 host 的某個 port,讓 container port 對應到那個 host port。dynamic port mapping 則是不指定 host port(或者給 0),container 會自動得到一個 ephemeral port 範圍 內的 host port 來做 mapping。

https://ithelp.ithome.com.tw/upload/images/20230921/20160671QIrUTGtFpq.png

其他設定不變,Create revision。

建立使用 ALB 的 ECS service

要使用 ALB 得重新建立一個 ECS service,無法沿用前面的 service(筆者原本以為可以…QQ)。先前建立的 service 可以到 CloudFormation 將對應的 stack 砍掉就能刪除了。

小提示:如果想避免建立 ECS service 因為 deploy 失敗而整個 rollback 或 deploy 到天荒地老 cloudformation stack 一直卡在 creating 都不知道是怎樣,可以先把 desired tasks 設成 0 讓 service 順利建立,之後再改 desired task 來進行 deployment。最常遇到的狀況是我們 mysql server 開在另一台 EC2 instance 上,為了省錢(O)會把它關掉,重新打開後 public IP address 改變,這時候需要修改 Laravel env 的設定並且再 deploy 一次 docker image。

建立 ECS service 的設定大部分跟前面一樣,差別在 Load balancing 這塊,只要選擇昨天建立的 ALB、target group 跟要做 load balancing 的 container 即可~

https://ithelp.ithome.com.tw/upload/images/20230921/20160671JZ8HrMM5g3.png

如果 create ECS service 把 desired task count 設成 0,可以從右上角 update service 進去將 desired task count 調成 1。

接著到 Deployments tab 觀察 deploy 的狀況:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671BhIqo63VHq.png

task 啟動後,ecs service 會向 ALB 的 target group 註冊一個 target,可以點進 target group 看看它各方面的狀態。現在就能看到底下 Registered target 有東西了,可以看到 instance 的 port 是 32781、不是 port 80:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671sw97TCiTIr.png

各位可以試試重新 deploy 一次,看看 target 的 port 有什麼改變(它應該要是另一個亂數 port number)。要重新 deploy 可以從 ECS service 的 update service 裡勾選 Force new deployment 後 update 來 trigger:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671Kf1Yp0uA5g.png

https://ithelp.ithome.com.tw/upload/images/20230921/20160671Usue0z3mJ4.png

ECS service 的 deployment 只要出現 reached steady state 就表示穩定了。先檢查一個 task 的狀況下,application 是否有正常執行。進到剛建立的 ALB:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671w9r7dcY55l.png

複製它的 DNS name,貼到瀏覽器上看看:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671FqkCr9pfff.png

太好了又是這個熟悉的畫面!

多跑個 task 吧~

再來我們要讓 ECS service 可以跑多個 task,這很簡單,只要更新 service 的 desired tasks 數量即可,我們更新到… 3 好了。

https://ithelp.ithome.com.tw/upload/images/20230921/201606719vaiaFNhXW.png

deploy 中…

https://ithelp.ithome.com.tw/upload/images/20230921/20160671v997KWI7ny.png

欸?怎麼停了?原來是 container instance 的 resource 不夠,那…回到 2 好了,先確認多個 task 的時候能夠正常運作。

https://ithelp.ithome.com.tw/upload/images/20230921/20160671famB3c4qP6.png

OK 正常!一樣用瀏覽器打開 ALB DNS name 來驗證~

網頁應該要能正常開啟~(一模一樣就不貼圖了…)

真的有 load balancing 嗎?

既然有兩個 container,當然要確認一下 request 是不是真的會給不同的 container 處理再回傳給 client,我們利用 ECS container metadata file 內的資訊確認!

依照 文件 說明,要打開 ECS container metadata file 功能,要設定 ECS_ENABLE_CONTAINER_METADATA container agent variable 為 true ,我們可以把 container instance 的 launch template 的 user data 改成如下:

#!/bin/bash
cat <<'EOF' >> /etc/ecs/ecs.config
ECS_CLUSTER=my-app
ECS_ENABLE_CONTAINER_METADATA=true
EOF

這個 script 跑完就是在 container instance 的 /etc/ecs/ecs.config 多加一行 ECS_ENABLE_CONTAINER_METADATA=true

跟 task definition 一樣,修改 launch template 是要建立新版本、不能直接更新原有的 template:

https://ithelp.ithome.com.tw/upload/images/20230921/2016067125Sdip7t1f.png

到最底下 Advanced details 的 user data 把新的 script 貼上去後按右邊的 Create template version。

筆者通常習慣把最新的 launch template version 設成 default,並且讓 auto scaling group 使用 default version 的 launch template。或者直接讓 auto scaling group 使用最新(latest)版本的 launch template。

https://ithelp.ithome.com.tw/upload/images/20230921/20160671Cgwl0nC0QW.png

https://ithelp.ithome.com.tw/upload/images/20230921/20160671ykLHNJUjzM.png

auto scaling group 設定以 default version 的 launch template 啟動 EC2 instance:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671iSrwy2Q6VH.png

https://ithelp.ithome.com.tw/upload/images/20230921/20160671ZnKia7wm4t.png

設定完會看到 auto scaling group 的 launch template version 長這樣:

https://ithelp.ithome.com.tw/upload/images/20230921/201606710z9SMEGlku.png

container 內的 metadata file 位置在 /opt/ecs/metadata/random_ID/ecs-container-metadata.json ,其中 random_ID 是個亂數,為了方便使用,metadata file 的位置會記錄在環境變數 ECS_CONTAINER_METADATA_FILE 。所以我們在 Laravel 加個 HelloController ,它會讀取環境變數 ECS_CONTAINER_METADATA_FILE 所指的檔案,parse 其中的 josn 後回傳 container id。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\File;

class HelloController extends Controller
{
    public function showContainer()
    {
        $content = json_decode(File::get($_ENV['ECS_CONTAINER_METADATA_FILE']), true);
        return $content['ContainerID'];
    }
}

這是個簡單的 API controller,我們到 routes/api.php 加入它的 route:

Route::get('/container', [HelloController::class, 'showContainer']);

最後用 ALB DNS name 連到 /api/container ,重新載入頁面幾次應該可以看到兩個 container id 輪番出現:

https://ithelp.ithome.com.tw/upload/images/20230921/201606714QME8mLkGK.png

https://ithelp.ithome.com.tw/upload/images/20230921/201606719U3L5bICVe.png

container id 就是 docker 的 container id,從 ECS task 的詳細頁面也可以看到:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671Hz4tb1XzCK.png

架構圖

現在的架構長這樣:

https://ithelp.ithome.com.tw/upload/images/20230921/20160671cguVCVFxrg.png

ALB 可以把流量導到兩個 public subnet,在 ap-northeast-1a 的 subnet 裡有一台 container instance,它身上分別用不同 port 跑著兩個 container。request 從 internet 進到 ALB,經過 Listener 的判斷後導向 target group,target group 會再將 request 丟給 EC2 instance 的某個 port(也就是 container)來處理。


上一篇
Day 10 Load Balancing
下一篇
Day 12 連接世界的橋樑:CodePipeline
系列文
AWS ECS + Gitlab + Laravel + Terraform 從入門到摔坑30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言