55屆全國技能競賽雲端運算 賽後隨筆 - Part 5

早安,這是「第 55 屆全國技能競賽英雄榜暨第3屆亞洲技能競賽及第 48 屆國際技能競賽國手選拔賽青年組雲端運算職類」系列文章的第五篇,這次來分享科目五的題目和解題過程。 轉眼間就寫到最後一篇了,等九月的二階國手選拔結束後再來繼續寫幾篇吧。

在雷門吃草莓可麗餅的カズサ

科目五: 一堆監控

這題都圍繞在 CloudWatch 的各項功能上,從 Metrics、Logs、Application Signals (APM) 到 Network Monitoring,可以說是把 CloudWatch 的功能都用上了。

題目提供了一個 CloudFront + S3 + API Gateway + Lambda 的架構,並要求使用者去監控這個架構的各項指標。

這題必須要先解第一大題才會開啟剩下的題目,因為整題都圍繞在 CloudWatch,且我沒有照順序做也沒做完,所以只列出大致的方向:

  • Lambda Code 改 metric unit
  • Metric filter 擷取特定 log 並轉換為 metric
  • Synthetics Canaries 監控 API 的可用性
  • 建立 Dashboard 來顯示各項指標
  • Metric anomaly detection 異常偵測
  • Internet monitors 監控各國連線狀態
  • RUM 監控實際使用者行為
  • 從 JSON 匯入 Dashboard
  • Dashboard 新增 RSS reader
  • WAF 封鎖 VPN 流量
  • 從 WAF logs 提取欄位
  • Logs Insights 查詢並產生指定報表

Lambda Code 改 metric unit

題目提到某 API 端點產生的 metrics unit 為 Percentage,需要將其改為 Count

到 CloudFront 可以得知 /api 的 origin 是 API Gateway,進入 API Gateway 後找到對應的 endpoint 即可找到目標 Lambda。 進入 Lambda 後可以很明顯地看到 unit 設為 Percentage,將其改為 Count 並 Deploy 即可。

python
def lambda_handler(event, context):
# ...
metric_data = {
'MetricName': 'APIRequests',
'Unit': 'Percentage', # 改為 Count
'Value': 1,
# ...
}
# ...

Metric filter 擷取特定 log 並轉換為 metric

題目要求將 /api/donate 的 payload 提取 amount 出來,並轉換為 metric。

透過剛剛的方式找到目標 Lambda,進入後可以看到程式碼內並沒有用到 metric,且我們也沒有修改程式碼的權限,但程式碼內有 logging 且內容為我們要的 amount。 因此我們可以透過 CloudWatch Logs 的 Metric filter 來擷取這些訊息。

python
def lambda_handler(event, context):
# ...
payload = event['body']
logger.info({
'event': 'donate',
'amount': payload['amount'],
})
# ...

在 CloudWatch Logs 找到對應的 Lambda log group,Actions -> Create metric filter,然後輸入以下 pattern:

json
{ $.event = "donate" && $.amount = * }

接著在下一步中設定 namespace 為題目指定的 UnicornFarm,metric name 為 Donations,metric value 為 $.amount,unit 為 Count 即可。

Synthetics Canaries 監控 API 的可用性

這題要透過 Synthetics Canaries 來監控 API 的可用性。功能跟 uptime robot 類似,就是定期發 request 去戳一下看正不正常。

這題因為題目講得不清不楚,我直接跑去設 UAM 想說怎麼沒得分,花了 20 分鐘把 CloudWatch 都摸過才知道原來是要用它…

在 CloudWatch Synthetics 中建立一個新的 Canary,Blueprints 選擇 API Canary,然後新增 HTTP request:

yaml
- Method: POST
- Application or endpoint URL: https://xxx.cloudfront.net/api/donate
- Headers:
- Content-Type: application/json
- Request data:
{ "amount": 0 }

需要留意題目提到的 API 為走 CloudFront 的,所以不能勾選 “I’m using an Amazon API Gateway API”。

接下來設定 Schedule 為每分鐘執行一次,然後 Deploy 即可。

賽後跟其他選手討論發現蠻多人設定完也沒有得分被卡著不能繼續,好像一定要用 API canary 的 blueprints 才會過。

建立 Dashboard 來顯示各項指標

題目要求建立一個 Dashboard 來顯示各項指標。

在 CloudWatch 中建立一個新的 Dashboard,然後把剛剛建立的 metric 和 canary 加入到 Dashboard 中即可。

Metric anomaly detection 異常偵測

題目要求對 Donations metric 建立異常偵測。當每分鐘的數值過小時發出 SNS 通知。

SNS 已經幫你建好了,只需要在 CloudWatch 中對 Donations metric 建立 alarm,threshold type 設為 Anomaly detection,然後選擇 Lower than the band,並設定 SNS topic 為題目提供的 UnicornFarmSNS 即可。

Internet monitors 監控各國連線狀態

題目要求建立 Internet monitors 來監控各國連線狀態。

在 CloudWatch 中建立一個新的 Internet monitor,在 Resources to monitor 中選擇自己的 CloudFront distribution 並建立即可。

RUM 監控實際使用者行為

題目要求使用 RUM 來監控實際使用者行為,功能與 Google Analytics、Cloudflare Web Analytics 類似。

在 CloudWatch 中建立一個新的 RUM app monitor,指定 Application domain list 為自己的 CloudFront domain,題目暗示到”所有需要使用到的驗證都已幫你設定好”,所以在 Authorization 需要選擇環境中唯一的 Identity Pool,其餘參數保持預設即可。

建立完成後會提供一段 JavaScript 程式碼,正常步驟應該自己更新 S3 上的 HTML,但只要提交建立的 RUM name 題目會自己幫你更新,真是貼心。

從 JSON 匯入 Dashboard

題目提供了一個 JSON 檔案,要求從中匯入 Dashboard。

需要留意的是 JSON 檔裡面有很多 [placeholder-your-xxx] 的部分,需要根據前幾題的設定來替換成自己的值,若直接上傳會跳第 n 個 widget 找不到資源的錯誤。 改好之後在 CloudWatch 中建立一個新的 Dashboard,然後選擇 Import dashboard,將 JSON 檔案上傳即可。

Dashboard 新增 RSS reader

題目要求在 Dashboard 中新增一個 RSS reader,顯示指定的 RSS feed。

在新增 widget 的 Other content types > Custom widget 中可以選擇內建的 RSS reader,會透過 CloudFormation 替你建立 Lambda。 但由於往年題目都要求不能使用 CloudFormation,雖然今年沒說(?而且昨天有用到 SAM 但我猶豫了,所以這題沒有做。 我相信應該是用這方法做沒錯?

WAF 封鎖 VPN 流量

題目要求透過 WAF 封鎖 VPN 流量。

在 WAF 中建立一個新的 Web ACL,然後新增一個規則,選擇 AWS Managed rule groups,其中有封鎖 VPN 的規則可以使用,勾選後套用到 CloudFront distribution 即可。

沒錢不敢在自已帳號開 WAF,有寫錯歡迎告知。

從 WAF logs 提取欄位

題目要求從 WAF logs 中提取每個請求的 host 與 uri,並另存為新的欄位。

在 Web ACL 內的 logging and metrics 中啟用 logging,將 log 儲存到指定的 log group。 然後到 Log Insights 中,選擇剛剛的 log group,使用以下查詢語句來提取欄位:

sql
fields @timestamp, @message
| parse @message ""host": "*"" as host_url
| parse @message ""uri": "*"" as host_uri

即可在結果中看到 host_urlhost_uri 兩個欄位,將 Query 儲存並提交即可。

Logs Insights 查詢並產生指定報表

題目要求使用 Logs Insights 查詢並產生各 API endpoint 的請求數量報表。

這步驟的前提是須要到 API Gateway 的 stage 中啟用 CloudWatch Logs,將請求日誌記錄到 CloudWatch Logs 中。

在 Log Insights 中選擇對應的 log group,使用以下查詢語句來統計各 endpoint 的請求數量:

sql
fields @timestamp, @message
| parse @message ""uri": "*"" as @path
| stats count() as @request_count by @path
| sort @request_count desc

這樣就可以得到各 API endpoint 的請求數量,一樣將 Query 儲存並提交即可。

科目心得

這次題目的難度沒記錯是從 300 ~ 400,看記分板發現有做到第二大題的人大概只有 5 位,可見大家都被 Canary 卡住。 我到最後還有約 10% 的題目沒做完,東西真的太多了,只有不到三小時一個人怎麼做的完啊。 但我又學到了很多東西,像是我更懂 metric 跟 Log Insights 語法了!

競賽結語

為期五天(扣掉開幕閉幕只有三天)的競賽,說長不長、說短不短,卻是一段充實無比的旅程。

兩年前我第一次參加技能競賽(53屆),當時的我接觸雲端還不到一年,雖然還是雲端小白但靠著多年來的實作經驗以及對資訊科技的熱愛,第一次參賽就拿到中區第四與全國第三,頒獎時自己也是嚇了一跳,雖然晉級二階國手選拔,但能力還是敵不過其他選手,與法國里昂的國際賽無緣。

兩年後,這次的我(55屆)在比完賽後才發現自己又變強了,總共五個科目都拿到第一,雖說大概有 70% 我沒接觸過的服務,但我還是靠著對資訊領域的知識來推測邏輯並快速釐清方向,也在幾個科目中拿到首殺(第一個得分,但不會因此加分)。

這次的競賽看到有些人在質疑我的成績,畢竟五個科目都第一難免會被針對。但我想說的是,雲端運算不單只是比誰會用雲端平台,而是比誰能在有限的時間內快速理解題目、找到符合真實世界的解決方案並實作出來。

雲端競賽考的是企業會遇到的真實問題,而不是課本上的標準答案。 在這科技日新月異、AI 技術週週更新的時代,只有不斷學習、快速適應新技術的人才能在競爭中存活,不被世界蛋雕

這一路走來常常都是自己一個人在學習與摸索(母胎單身😭)。高中暑假的某一天,突然腦袋撞到、異想天開地用手機學寫 Python 聊天機器人(對,就是這麼白癡),從此踏上了我不斷自學、撞牆、把牆撞破又遇到下一道牆的獨自升級之路。

感謝這幾天陪我討論跟吃晚餐的夥伴們,以及前幾個月一起參加訓練營的朋友們,讓我們一起加油,繼續在資訊科技的道路上前進。