分類: 維運日誌

《AI 整理版|AWS 全球大當機完整解密:DynamoDB DNS 競態引爆連鎖故障、官方根因與賠償機制全解析》

《AI 整理版|AWS 全球大當機完整解密:DynamoDB DNS 競態引爆連鎖故障、官方根因與賠償機制全解析》

以下整理上週(以台北時間,落在 2025/10/20–10/21)AWS 全球性大規模事件的官方根因、時序、影響範圍、後續改進與賠償機制。所有敘述均以 AWS 官方文件為主,並輔以權威媒體技術脈絡補充。你要決策、要追 SLA、要做事後改善,照這份做。


結論

  • 根因(Root Cause):DynamoDB 於 us-east-1自動化 DNS 管理系統存在潛在競態條件(race condition),導致將 regional endpoint(dynamodb.us-east-1.amazonaws.com) 的 DNS 記錄誤更新為空集合,且自動修復失效,需人工介入修正;接著 EC2DropletWorkflow Manager(DWFM) 與網路狀態傳播 backlog 引發新開機/網路配置的連鎖復原延遲NLB 健康檢查在網路狀態未完全傳播時誤判,觸發 AZ failover 造成連線錯誤攀升。
  • 範圍:起於 DynamoDB,但波及 EC2 / Lambda / EKS / ECS / Fargate / NLB / Connect / Redshift 等多項服務於 us-east-1;全球大量第三方服務連鎖受影響。
  • 官方時序(PDT→台北時間):事件自 10/19 23:48 PDT(10/20 14:48 TST) 起,分三波衝擊,AWS 宣告 10/20 15:01 PDT(10/21 06:01 TST) 全部服務恢復正常。詳細見下方時序表。
  • 後續改進:全面停用 DynamoDB DNS Planner/Enactor 自動化並修補競態、對 NLB 加上容量移除速度控制(velocity control)EC2 增加 DWFM 復原大規模測試與以佇列深度為基準的節流機制。
  • 賠償(SLA Service Credit):依各服務 SLA 申請服務抵用金(Service Credit)非自動發放,需在事件後第二個帳單週期結束前透過 Support Case 以「SLA Credit Request」提出。範例如 DynamoDB SLAEC2/Compute SLA 與各服務的 Credit Request 條款。

一、Root Cause(技術根因拆解)

  1. DynamoDB:DNS 管理競態 → 空白 DNS 記錄 → 端點無法解析
  • 內部 DNS Planner 產生計畫、DNS Enactor 多 AZ 冪等套用至 Route 53。因一個 Enactor 長時間重試延遲,另一個較新的計畫先套用且觸發舊計畫清理;延遲的 Enactor 之後把舊計畫套回 regional endpoint,而清理程序又把該舊計畫刪掉,導致所有 IP 記錄被移除且狀態不一致,自動修復停滯,需人工介入。
  1. EC2:DWFM / Network Manager 復原連鎖
  • 事件期間 DWFM 與 droplets 的 lease 檢查依賴 DynamoDB,先被拖垮;DynamoDB 復原後 lease 大量重建、工作佇列壅塞,DWFM 進入壅塞崩潰(congestive collapse),需節流+選擇性重啟才能清併列。接著 Network Manager 處理積壓的網路狀態傳播,造成新起機器可開但無法立即通網
  1. NLB:健康檢查與 DNS AZ failover 的交互放大
  • 健康檢查在網路狀態尚未完整傳播時誤判,導致節點被移出/又加回,放大負載與錯誤;AWS 一度停用自動健康檢查 failover 以回復容量。

上述技術解釋以 AWS Post-Event Summary(PES) 為準;外電報導(Guardian/Reuters/Wired 等)與第三方監測(ThousandEyes)之描述與 AWS 官方內容一致或相符。


二、官方時序(轉換為台北時間,UTC+8;括號內為 PDT)

來源:AWS About Amazon 官方更新與 PES。

  • 10/20 14:48(10/19 23:48 PDT):DynamoDB regional endpoint DNS 異常開始,API 錯誤上升(第一波)。
  • 10/20 17:25–17:40(10/20 02:25–02:40 PDT):AWS 修復 DNS 記錄;隨各地 DNS 快取過期,DynamoDB 恢復。
  • 10/20 20:30–10/21 05:09(10/20 05:30–14:09 PDT):NLB 健康檢查誤判引發連線錯誤;09:36 PDT 停用自動 failover、14:09 PDT 恢復。
  • 10/20 20:01–10/21 04:50(10/20 05:01–13:50 PDT):EC2 新開機與 API 逐步恢復,DWFM/Network Manager 清 backlog。13:50 PDT(10/21 04:50 TST) EC2 全恢復。
  • 10/21 06:01(10/20 15:01 PDT):AWS 對外宣告所有服務恢復正常。

期間 IAM Console、Support Console、Redshift、Lambda、ECS/EKS/Fargate、Connect 皆有不同時段/型態的 API 錯誤與延遲,詳見 PES 細節分段。


三、影響與證據

  • 多服務於 us-east-1 大範圍受影響,含 EC2/Lambda/EKS/ECS/Fargate/NLB/Connect/Redshift/IAM Console/Support 等;第三方大規模中斷(通訊、金流、遊戲、媒體等)。
  • AWS Health Dashboard / About Amazon:官方對外狀態與統一時序;PES:完整技術剖析。
  • 外部監測與媒體旁證(ThousandEyes / Wired / Guardian / Reuters):記錄全球影響與技術脈絡。

四、AWS 後續改進(官方承諾)

  • DynamoDB:全球停用 DNS Planner/Enactor 自動化,修補競態並加防護,再評估重啟。
  • NLB:加入 velocity control,限制單一負載平衡器在 AZ failover 時可移除的容量,以避免抽走過量健康容量。
  • EC2:新增 DWFM 大規模復原測試套件節流機制改為以佇列深度為準,高負載時自保服務穩定。
  • 跨服務:檢討跨服務復原路徑以縮短下次 TTR。

五、賠償與申請實務(SLA Service Credits)

要點:不是自動賠付;你要主動提。標準流程如下(各服務 SLA 條款相近):

  1. 確認受影響服務與區域(例如:DynamoDB、EC2,區域 us-east-1),計算該月度可用性是否落入 SLA 賠付檔次。
  2. 提出申請:在 事件後第二個帳單週期結束前,到 AWS Support Center 建立 Support Case,主旨含 “SLA Credit Request”,附上受影響期間、資源、帳單證明與監測證據。
  3. 抵用金形式Service Credit 會抵扣未來帳單(部份服務載明可視情況退刷同月信用卡),非現金退款

參考:DynamoDB SLAEC2/Compute SLACredit Request 條款(多服務條款結構相似)。


六、你現在該做的(行動清單|魔鬼教練版)

  1. SLA 索償
    • 彙整你在 10/20 14:48–10/21 06:01(TST) 的錯誤率、失敗交易、不可用時段;逐一比對 DynamoDB / EC2 / 其他受影響服務 的月可用性與 SLA 門檻,本週內送出 Support Case
  2. 架構補強(依官方改進方向對齊與超前部署)
    • DNS 依賴降風險:對控制平面依賴(e.g., 資料表/隊列/金鑰管理)建立跨區域 endpoint fallback更短 TTL / 獨立解析策略。
    • 啟動分區容錯:關鍵業務至少雙區域(active/active),避免 us-east-1 單點;Global Tables 與讀寫路由切換演練常態化。
    • NLB 容量與健康檢查:避免健康檢查信號耦合於延遲網路傳播;對AZ failover 做壓力測與節流曲線
    • EC2 啟動路徑:將冷啟容器/VM 的依賴降至最少;必要時改用可在異區預熱的機制、或以 Lambda/ECS/Fargate 輔助短期擴容。
    • 運維演練:把這次時序寫進故障劇本(runbook),每月演練一次:DNS 端點解析失效 → 控制面不可達 → 容量節流 → 逐步恢復 的全鏈路演習。
    • 外部技術脈絡可佐證你的設計說帖(ThousandEyes / Wired / Guardian)。

七、權威來源(官方文件|可供稽核附檔)

  • AWS Post-Event Summary(PES)Summary of the Amazon DynamoDB Service Disruption in the Northern Virginia (US-EAST-1) Region根因、時序、影響、後續改進的權威版)。
  • About Amazon 官方公告(同日更新)Update – AWS services operating normally整體時序對外版,含 PES 連結)。
  • AWS Health Dashboard(事件歷史):可回溯各服務的官方時間線與公告。
  • SLA 與賠償條款
    • DynamoDB SLA(可用性門檻與信用額度計算)。
    • Amazon Compute/EC2 SLA(Region/Instance 級別承諾與 Credit)。
    • Credit Request 規範(提出申請期限與格式要求)。
    • 其他服務(如 S3、Connect)之 SLA 條款與 Credit 機制可類推查核。
  • 外部權威脈絡(非官方,作為影響面旁證):ThousandEyes、Wired、Guardian、Reuters。

.net core 應用程式 在AppService進行dotnet dump

.net core 應用程式 在AppService進行dotnet dump

當應用程式有High Memory 或是High Cpu的現象時,若希望對應用程式進行Runtime的分析,以前在IIS上常常進行的是在工作管理員對w3wp進行傾印,移到雲端又是Container形式後,跟以往 在windows的經驗不大一樣,不得其門而入,以下記錄一下作法

在Container For AppService的環境下要能進行Dump,會有以下 步驟

Container安裝dotnet-dump 的tool

# 前略...
# Open port 2222 for SSH access
EXPOSE 80 2222

# dotnet
RUN apk add icu-libs tzdata
RUN apk --update add libgdiplus ttf-dejavu
RUN apk add --no-cache bash curl icu-libs libc6-compat \
    && curl -sSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
    && bash /tmp/dotnet-install.sh --channel 8.0 --install-dir /usr/share/dotnet 

# 安裝 dotnet-dump
RUN /usr/share/dotnet/dotnet tool install -g dotnet-dump \
    && ln -s /root/.dotnet/tools/dotnet-dump /usr/bin/dotnet-dump \
    && dotnet --info

# 後略...

確認Docker Build成功

通常你的webapp有多個 instance,請先設定環境變數增加以下 設定為true

WEBSITES_ENABLE_APP_SERVICE_STORAGE

這個設定是讓 多個instance的/home目錄共用,後續可以透過kudu的newui進行FileManager下載Dump檔案

透過進階工具連到開發工具(不是上面的SSH,這個外層的SSH應該主要是連到Container Host的主機,要連到指定的Instance的話,可以進到Kudu去指定Instance)

接著ssh連進去 確認Container內dotnet-dump版本

/home/LogFiles# dotnet-dump --version
9.0.553101+5b61d34de04d6100e6003415f7d7e9c4b971afd4

確認指定ok後,查詢process id

ps aux | grep dotnet
16 root 5h23 dotnet /app/example.dll
10891 root 0:00 grep dotnet

進行dump collect,注意,此步驟在linux container進行時,並不會中斷process或重啟(這跟我們之前w3wp.exe的經驗不太一樣,不過或許還是會間接造成伺服器比較忙錄,所以可以離峰進行)

dotnet-dump collect  -p [process-id]  --type Full  --diag

Writing full to /home/LogFiles/core_20250211_010126
Complete

成功後

透過kudu 的FileManager就可以找到檔案 進行下載分析~~

Reference :

https://techcommunity.microsoft.com/blog/appsonazureblog/how-to-collect-net-core-dump-on-linux-web-app/2260713

Server Set Cookie Cross Domain的雷

Server Set Cookie Cross Domain的雷

繼API的CORS的問題後

現在又遇到了一個set cookie的問題,下面的測試順序是反過來的,最早是遇到無法設定到Browser/Application的Cookie,後來發現可以設定的方式後,改實驗多種Domain的組合…

首先本機測試Host先改成模擬前後端分離站台的部署模式

      response.cookies.set('refreshToken', refreshToken, {
        path: '/',
        maxAge: 60 * 60 * 24 * 7,
      });

      response.cookies.set('domainTokenByMiddleWare', refreshToken, {
        path: '/',
        domain: '.azure-paul.com',
        maxAge: 60 * 60 * 24 * 7,
        secure: true,
      });

set-cookie成功!

接著改換 azure-paul.net

      response.cookies.set('refreshToken', refreshToken, {
        path: '/',
        domain: '.azure-paul.net',   
        maxAge: 60 * 60 * 24 * 7,
      });

      response.cookies.set('domainTokenByMiddleWare', refreshToken, {
        path: '/',
        domain: '.azure-paul.net',
        maxAge: 60 * 60 * 24 * 7,
        secure: true,
      });

一樣可以

透過 client端直接呼叫api server response的set-cookie也work

最後我改成這個domain

     response.cookies.set('refreshToken', refreshToken, {
        path: '/',
        domain: '.azurewebsites.net',   
        maxAge: 60 * 60 * 24 * 7,
      });

      response.cookies.set('domainTokenByMiddleWare', refreshToken, {
        path: '/',
        domain: '.azurewebsites.net',
        maxAge: 60 * 60 * 24 * 7,
        secure: true,
      });

結果無情的被拒絕set-cookie

真的沒有寫進去…驚嘆號上的hint是寫著..”current host url invalid”

這樣看來跟.net or .com沒有關係 ,倒是跟azurewebsites.net的domain被列入了卡控 名單有關係

似乎..這跟我”一開始”在/etc/hosts改成dev.azure.com 一樣,會直接被chrome卡掉

繞了一大圈後…

小結論如下
CORS跟Cookie ,若以不同domain要做到CrossDomain的存取,必須繞路避開大網站的domain
(如上azure-paul.com, azure-paul.net passed)

或是直接以NGINX Proxy建成xxxx.yyyy.com + xxxx.yyyy.com/backend,直接就可以不用遇到這種雷…

若有其他發現或知道真相的人歡迎一起分享指教~~

自行備註:

針對azurewebsites.net的set sub-domain的問題其實有人分享過 ,只是一開始哪會找這個方向XD

https://learn.microsoft.com/en-us/answers/questions/360645/cannot-set-a-subdomain-friendly-cookie

竟然是真的跟這邊的名單有關?(半信半疑)

https://publicsuffix.org/list/public_suffix_list.dat

此文的解法 真的也是綁到名單之外的Domain

透過Azure DataStudio / SSMS查詢效能不佳的SQL語法

透過Azure DataStudio / SSMS查詢效能不佳的SQL語法

這兩天遇到一個情境,一個早上突然所有的請求都卡住,平均回應 時間都要1~2分鐘。當下一時間沒啥方向,往登入那邊查,結果找錯了方向,會這樣想純粹是因為認為那個是一條測試的必經之路。而我們還在開發的資料庫中,最多也才幾百筆,最大 也不到一萬筆,為什麼會突然 這麼慢呢?

後來請 DBA看了一下後,馬上就找到問題了,大至記錄如下:

情境:
假如現在有兩張表
分別為
表 1 Master(Id)
表 2 Detail(Id, MasterId)

當時Master表大概有9xx筆,而Detail表有7千筆左右

select * from Master m
left join Detail d on m.Id = d.MasterId
where m.xxxxxx = xxxxxx

結果這樣不得了,一查發現大概執行個5、6百次 ,總執行時間就超過4小時以上了..
一般來說,PrimaryKey需設是Unique+Index(Cluster)因此只以Id作搜尋條件,效能不會差
但此時,Foreign Key若子表的Column沒有建Index,則對搜尋效能仍無影響,FK只作為 限制功能

補充以上觀點後

再補上SqlServer這次如何查找有問題的效能語法的方法(我是Mac,突然很羨慕ssms完整版功能)
不過我也立馬補上Azure Data Studio的方法,不無小補 一下。

1.Azure Portal對有問題的database進行 “查詢效能深入解析” (Azure Portal上的DB查詢權限要開放)

ex: 透過下列清單,可以查詢到Top5慢的查詢,透過查詢ID,可以再往 展開

註 : 這個畫面出不來的話代表 Azure Portal上對DB的權限不夠,不過至少可以對到查詢 ID,再請DBA或用 SSMS/Azure Data Studio去細追

2.透過SSMS,需要DBA針對db user進行開放

Query Store(查詢存放區)
-> Top Resource Consuming
-> Tracked Queries
-> QueryId

SSMS功能就是強大 ,可以針對 時間/CPU/IO統計

對於我們的查詢 ,在一個時間區間內,Where 條件不一樣 ,可能就QueryId就會不同(Plan Id就會不一樣)
-> ViewQueryTest查詢其問題語法分析 執行計劃

透過 查詢計劃可以看到發生了兩次Scan

3.透過Azure Data Studio,加入dashboard圖表

最後一種,若你是用Mac的環境(M1 Core),沒有辦法安裝SSMS這套工具的話

教學:https://learn.microsoft.com/en-us/azure-data-studio/tutorial-qds-sql-server

設定完重啟,在Database-> Manage就可以看到以下的圖表,也可以對齊上述方法的查詢Id

能看到非常 明顯 的峰點,那就還算是好的情境~(特別是還在 測試區)

針對該圖表 可以往下 看Insight的清單,可以對到1525就是問題查詢的所在

從query_sql_text就可以拿到問題語法,一樣貼到Azure Data Studio的Query窗

就可以Estimated Plan來顯示查詢計劃囉

[資訊安全] 在Mac上用GPG套件將檔案加密(231108 更新)

[資訊安全] 在Mac上用GPG套件將檔案加密(231108 更新)

Gpg是一個數位簽章的檔案加密套件

其原理可以從他的祖先PGP去略知一二

利用了RSA的演算法與各種雜湊演算法對檔案進行處理,但若直接 使用RSA演算法無法對檔案大小的長度(我的照片6xx kb)內容加密,所以RSA主要是用在對檔案進行對稱加密的金鑰進行保護加密。
其原理可以再自行看一下相關連結。

下載 GPG套件

https://sourceforge.net/projects/gpgosx/

https://formulae.brew.sh/formula/gnupg

基本上,若是採用這個協定進行加密,應該會提供pgp檔案,pgp通常為對方可公開的公鑰檔案。匯入我們這端的系統後,就可以讓我們以gpg指定對方公鑰作為收件者進行檔案加密。照上圖,檔案加密的RandomKey就是由對方的公鑰做加密,以確保只有對方解的開。


然而對方應該不會提供自己的私鑰,通常是會用於加簽(後面指令中的參數為–sign),若你用自己的私鑰加簽,就要提供自己的公鑰,對方才能做驗簽,可以透過gpg –list-secret-key檢查自己的系統是否有私鑰,若沒有的話,可以上網申請一組。

ex:透過RSA對私鑰進行簡易密語設定,格式也可以指定,匯入時gpg套件都會幫你封裝好這些細節

這邊我們在mac上實際 用 gpg一樣可以匯入pgp的檔案,所以基本上應該是有向下支援了。

gpg import xxxx.asc或skr (注意,是兩個減號) => 此為私鑰檔案,通常只有一份要管理/備份好,若都沒有的話,可以透過指令/金鑰工具產生。

gpg import yyyy.pgp (注意,是兩個減號) => 此為公鑰檔案,每個訊息交換端都可以散佈公鑰檔提供對方做加密傳給自己,而只有自己的私鑰可以解開。

匯入yyyy.gpg的時候會需要輸入password

匯入後,使用以下指令就可以進行檔案加密

gpg –output “/Users/paul_huang/Desktop/{加密後的檔案}.encrypted” -u “paul(Test)” –pinentry-mode loopback –always-trust -r “收檔案者(收件者)的公鑰ID” –s2k-digest-algo “SHA1” –sign –passphrase “加簽章時使用的私鑰密語” –encrypt “/Users/paul_huang/Desktop/{欲加密的檔案}.xml”

成功加密的話,就會有以下的檔案產生  因為涉及加簽,加簽關係到驗簽,證明發送端是我進行的,因此還需要我的公鑰進行驗簽。

註:  

-u, –local-user 使用者-ID,拿指定使用者 ID 來簽署或解密 , 這一步置關重要,要帶入這個參數,對方 才知道你是用 這個人的私key加簽,對方在驗簽的時候,需要你的公鑰進行驗證簽章 ,代表保證檔案的合法性

-r 可以多組 ,代表這個加密檔案,有在收件者當中的人都可以用他的私鑰解密 

可以透過以下指令進行匯出提供接收端做驗簽

gpg –armor –export {公鑰ID} > PublicKey.pgp ( -a, –armor  會以建立以 ASCII 封裝過的輸出)

公鑰ID可以用gpg –list-keys查詢一下私鑰對應的公鑰是哪個  (因為是公鑰,所以不怕公開)

公私鑰使用上的原理如下

加密者,以RamdonKey進行對稱式加密檔案,接著以 解密端(收件者)的 “公鑰” 將Random Key進行檔案加密,對方可以用自己的私鑰解密randomkey,進行檔案解密。其中加密者會在加密後,再用私鑰進行一次簽章,此簽章只能用加密者的公鑰進行驗簽,此驗證就是確保,是加密 者進行上述加密行為,無其他人篡改過。

Reference

https://blog.miniasp.com/post/2022/05/11/gnupg

https://xeodou.me/how-pgp-works/

[動手做]安裝 GUI Dockers管理器 – Portainer

[動手做]安裝 GUI Dockers管理器 – Portainer

既上一篇

租了3台機器,但是各自沒有使用Docker,接下來會逐漸的將所有核心都開始Docker化

Docker雖然方便,但是經過了不同機器的隔離,要去操作,仍需要ssh的話,也很麻煩

因為GUI Portainer的工具的出現,徹底的簡化了這一層

在此記錄一下相關的配置操作

首先Docker Portainer的安裝 我們安裝在Jenkins的主機上

Jenkins其實本身也可以用Docker安裝,暫時先不討論

Jenkins這台VM我們裝上去Docker

Docker CE的指令就看官網的就好了
https://docs.docker.com/engine/install/ubuntu/

接著建立Portainer的相關容器(只要幾個指令也太無腦了)

docker volume create portainer_data
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

接著是被管理的Docker VM上可以設定Docker Api

sudo nano /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H=tcp://0.0.0.0:4243

systemctl daemon-reload 
sudo service docker restart
注意,重新啟動docker後,有可能會造成container不見,這邊可以再去用 jenkins重建服務

接著要去portainer設定相關環境了,portainer在初次 連結的時候可能會需要你重啟container(註)
設定了超過12碼的帳密後,就可以登入了。

接著我們將 要被遙控的docker server,透過 gui加入環境中(如下面擷圖)

重新看,可以從portainer看到

Reference

https://ithelp.ithome.com.tw/articles/10265048

https://docs.portainer.io/start/install-ce/server/docker/linux

https://docs.portainer.io/start/install-ce/server/docker/linux

https://hackmd.io/@JYU/B1w9NDGnD

[動手做] 將C# Api佈署上 AWS+Github+Jenkins + Docker 的CICD實踐-Jenkins篇

[動手做] 將C# Api佈署上 AWS+Github+Jenkins + Docker 的CICD實踐-Jenkins篇

寫了微軟程式這麼久,雖然都是寫功能比較多,對於DevOps界久聞Jenkins大名,但從未真的使用過Jenkins做過一段完整的CICD流程。出於好奇心,找了一部網路影片,結合C# dotnet core的主題,希望實際 手把手try出如何在aws上做完一個low level的佈署過程 。總不好說自己會用 Azure Pipelin就是有做過 CICD ,終究Azure Pipeline也封裝 簡化了很多東西,做起來已經相對簡單一點了,不過缺點也是彈性不夠大加上指令或任務也不夠透明化。這一版本sonarQube先ignore(主要是 做的時候發現無法啟動,待之後再來補強這段)

這一次的專案範例如下 ,不接 db不接 外部服務,純程式的模擬

github url: https://github.com/pin0513/CICDExample

Program.cs的內容是一個模擬未來五天的天氣預測的Api

using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.FeatureManagement;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddFeatureManagement();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
“Freezing”, “Bracing”, “Chilly”, “Cool”, “Mild”, “Warm”, “Balmy”, “Hot”, “Sweltering”
};

app.MapGet(“/weatherforecast”, () =>
{
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast()
{
DateTime = DateOnly.FromDateTime((DateTime.Now).AddDays(index)),
Temperature = Random.Shared.Next(-20, 55),
Status = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
return forecast;
}).WithName(“GetWetherForecast”)
.WithOpenApi();
app.Run();

public class WeatherForecast
{
public DateOnly DateTime { get; set; }
public int Temperature { get; set; }
public string Status { get; set; }
}

實際跑起來如下 :

接著我們把他Commit與Push到Github

AWS端,我們先創建EC2的VM作為 Jenkins Server

選擇免費方案就好了XD

分別建立3個Instance後如下

我們透過 SSH連線過去,會先發現

paul@IpdeMacBook-Pro aws-cert % ssh -i SSH-KEY-Jenkins.pem ubuntu@18.206.225.245 

Permissions 0644 for 'SSH-KEY-Jenkins.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "SSH-KEY-Jenkins.pem": bad permissions
[email protected]: Permission denied (publickey).

爆了以上的錯誤,代表你的權限開太大了,執行前必須先將你的金鑰改成無法公開檢視

重新輸入paul@IpdeMacBook-Pro aws-cert % sudo chmod 440 SSH-KEY-Jenkins.pem 以後,就可以ssh過去了

在Jenkins的Vm上依序執行以下指令

sudo apt update
sudo apt install openjdk-11-jre

https://www.jenkins.io/doc/book/installing/linux/

curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee \
  /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins

安裝後,接著到EC2端設定 安全性

接著啟動jenkinks

systemctl status jenkins

跑起來後,會如下圖,會有token到時拿來登入用的,此擷圖不是我的主機,僅示意,安全性至上!

新的作業 -> enter automated-pipeline-aws

接著到Github專案去設定 Webhook

http://18.206.225.245:8080/github-webhook/ (這邊注意要加/)

接著到jenkins測試一下,點擊馬上建置

看一下工作目錄,就有包含最早我們commit的方案資訊

接著到github測試一下webhook

Reference: https://www.youtube.com/watch?v=361bfIvXMBI

建置觸發成功!實際看jenkins的工作目錄也有新的檔案了!

SonarQube Vm透過SSH一樣 的方式登入後,去SonarQube官網下載Community版本

ubuntu@ip-172-31-89-20:~$ wget ttps://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-10.1.0.73491.zip

sudo apt install unzip
unzip sonarqube-10.1.0.73491.zip
/home/ubuntu/sonarqube-10.1.0.73491/bin/linux-x86-64
ubuntu@ip-172-31-89-20:~/sonarqube-10.1.0.73491/bin/linux-x86-64$ ./sonar.sh console

上面指令跑不成功可能是java環境沒裝,所以抄上面jenkins的安裝java指令執行一次

實測Java要裝到18版

sudo apt install openjdk-19-jdk-headless

實際跑起來目前

2023.08.06 05:12:07 INFO  app[][o.s.a.SchedulerImpl] Waiting for Elasticsearch to be up and running的問題 (會暫時卡住)

我們先跳過去做佈署到Docker-Server

paul@IpdeMacBook-Pro aws-cert % ssh -i SSH-KEY-Jenkins.pem [email protected]

ubuntu@ip-172-31-82-131:~$ sudo hostnamectl set-hostname docker
ubuntu@ip-172-31-82-131:~$ /bin/bash
ubuntu@docker:~$ sudo apt update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /etc/apt/keyrings/docker.gpg $ sudo chmod a+r /etc/apt/keyrings/docker.gpg

執行
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

回到jenkins切換 hostname

sudo hostnamectl set-hostname jenkins

ubuntu@jenkins:~$ sudo su jenkins
ubuntu@jenkins:~$ ssh [email protected] (連到Docker Server)

此時會出現
[email protected]: Permission denied (publickey).

這時先回到docker的那台 vm,用 sudo su進去root

再編輯nano /etc/ssh/sshd_config 檔案 (注意: 是sshd_config)

把以下幾個設定啟用 ,反註解後存檔

PubkeyAuthentication yes
PasswordAuthentication yes 

重啟sshd : systemctl restart sshd (要在root權限下: sudo su)

同時在 root 權限下 passwd ubuntu這個帳號設定密碼

測試jenkins可否連到docker~

ssh [email protected]

若可以連線並驗證密碼通過就會像上圖

回到jenkins的vm透過sudo su jenkins切到jenkins的user透過ssh-keygen產生一個key

接著ssh-copy-id [email protected]

經過了上述的行為,我們透過了jenkins這個user去生成了一個ssh的key加到了docker的server

也就是我可以直接在jenkin vm這台透過 jenkins這個user執行ssh不用密碼就可以跟docker互動

接著我們試著透過 jenkins的管理去設定佈署的docker server

管理 Jenkins => 安裝 ssh2easy的plugin(因為影片中用的就是這個)

設定ServerGroupsCenter

組態中我們可以先試著用 remote shell做一個指令看看

馬上儲存來建置看看,實測如下,有確實執行指令

實際上也有帶上來!!

jenkins建置 C#的準備

sudo apt-get install -y dotnet-sdk-7.0
sudo apt-get install -y aspnetcore-runtime-7.0
sudo apt install nuget
sudo apt install zip

我們預計從Jenkins發佈程式後,上傳 zip到docker-server去處理
建立Build Steps

執行 Shell
dotnet publish ${WORKSPACE}\\WeatherWebApplication\\WeatherWebApplication.sln -c Release -o out -r linux-x64 --self-contained

執行 Shell

cd out && zip -qr output.zip .

Remote Shell
touch ${WORKSPACE}\\WeatherWebApplication\\out\\output.zip

最後我們設定一個
建置後動作 Delete workspace when build is done(這個是一個plugin)

上面的建置過程中我曾經發現他會一直出現以下錯誤 
error NETSDK1005: Assets file '/var/lib/jenkins/workspace/automated-pipeline-aws/WeatherWebApplication/WeatherWebApplication/obj/project.assets.json' doesn't have a target for 'net7.0'

後來發現,我雖然裝的是net7的SDK,但是在obj的project.assets.json中有綁到target: net8.0的配置,而且 obj目錄不小心commit了,所以我後續使用上面的delete workspace when is failure做清除後
再重新建置一次,這時改成is Success再清就好了,因為若是失敗的話,就還可以檢查問題
所以jenkins在工作目錄的操作預設是只會做覆蓋。所以錯誤的配置調整後,可能還是會錯誤這點在釐清問題的時候還是要看一下。

####################################
execute command exit status -->0
##########################################################################
[automated-pipeline-aws] $ /bin/sh -xe /tmp/jenkins16435309995668868877.sh
+ cd out
+ date +%F
+ mv output.zip output-2023-08-08.zip
+ date +%F
+ scp /var/lib/jenkins/workspace/automated-pipeline-aws/out/output-2023-08-08.zip [email protected]:~/upload
[WS-CLEANUP] Deleting project workspace...
[WS-CLEANUP] Deferred wipeout is used...
[WS-CLEANUP] done
Finished: SUCCESS

終於建置到移轉到docker-server,也看到docker-vm上有我們scp過去的檔案

接著我們嘗試加入一個Remote Shell

這一段主要是希望透過編碼可以做到整理Deploy上去的zip檔案。未來可以做版本備份的概念,但其實期望應該是可以做到日期流水編,這邊先簡單用日期做

在Docker-Server端為了設定權限,加上以下的script

ubuntu@docker:~/upload/app$ sudo usermod -aG docker ubuntu
ubuntu@docker:~/upload/app$ newgrp docker

做到不用sudo 可以執行docker

因為.net core在Docker的相容性已經有目共睹了,所以這邊索性調整Sample Project給的DockerFile

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM base AS final
WORKDIR /app
COPY *.* .
ENTRYPOINT ["dotnet", "WeatherWebApplication.dll"]

註: 測試Jenkins時,建議都先 在linux主機上驗證,通常 可以跑的指令 在jenkins上不太會出錯。

透過Remote Shell定義Docker Command

經過幾次調整後,終於可以運作了

因為是綁8085 port,所以docker server的安全性設定要開放8085 port

大功告成

我們試試看改程式後,整個運作起來看看正不正常

Enumerable 從1-5筆改成1-10筆

Push後,一路觸發了

哈!馬上建置失敗

因為Docker 的name已經重疊了,無法建立,為了簡單驗證,所以調整一下docker run 的shell,先 停止再 重新run,設定如下(–rm實測無法動態移除存在的container,所以我先改成stop再 rm):

cd ~/upload/app
docker build -t docker-app-image .
docker stop weather-app
docker rm weather-app
docker run -d -p 8085:80 --name=weather-app --rm docker-app-image

最後成功了!!

改成50筆也不是問題

讚啦…

首次手把手建立C# .net core程式透過jenkins模擬 CICD的流程 ,雖然還沒自動呼叫單元測試,但也算是解決了自已長久以來好奇的部分細節。

不過實務上每個細節都還有很多改進空間(廢話),例如cd的部分不太可能像我這邊用 stop的方式 中斷 服務,應該是能透過 Docker Swarm或是K8加入node的方式,也要更提早考慮封裝image的問題。以確保不是在prod環境才進行封裝,而是在stage封裝 後在 其他環境pull下來的image已經是穩定的。

這次的案例雖簡化許多,不過能打通一解我心中長久之謎,在很多細節真的是需要一一擊破,僅作為筆記 記錄此行~~

.Net 8的計量新框架 (Metrics)

.Net 8的計量新框架 (Metrics)

想當年,要做到.Net的監控機制,就是要做到這麼多的事情

可能包含要自己設計Log,考慮如何非同步寫入分庫DB,或是另外獨立呼叫外部服務(ex.Sentry)。

當然外部服務是肯定方便又快速的整合方式,但是就是貴森森,而且還有服務綁架問題(就是用一用 ,你就很難轉移到其他平台上)

曾幾何時,我們以前的公司也有架構team,專門搞了一個整合Grafana, Kibana, ElasticSearch的底層平台過。當然當初要架這些東西還沒容器化前,相信也是有相當的維運成本(現在也是有啦)

不過自從容器化後,這些事情都變的好像更容易指令化,就可以打包好一個獨立的自有服務。

當然 今天看到這篇.Net 8支援 Metrics的功能後,其實真的簡化了很多以往要自已造輪子的工。

有興趣可以看 .Net網紅的Demo

而官方文件也給出了手把手的教學!!

https://learn.microsoft.com/zh-tw/dotnet/core/diagnostics/metrics-collection

GCP平台 VM STARTUP SCRIPT 進行UFW DISABLE 記錄

GCP平台 VM STARTUP SCRIPT 進行UFW DISABLE 記錄

這陣子老婆想要寫網誌 (親子遊日後的心血來潮)

無奈各大平台包含xuite,以前的無名收的收,國外的新平台,又覺得好像不熟悉所以腦筋動到自架平台 ,剛好我有這個wordpress養在那邊

不過,因為想說要有一些公開內容,所以還是專業一點弄一下ssl

SSL申請事小,結果我在try ssh跟firewall簡稱(FW)的時候,為了檢查vm是否有fw

所以apt安裝了ufw,殊不知是惡夢的開始

先前因為常常用 ssh連線,不過這次我索性使用了gcp web SSH連過去,想說,應該是滿無腦的

也確實方便,webssh還整合了上傳下載功能,所以我可以很方便的上傳我將要用的SSL證書跟private key

(但上傳下載也其實就是ssh的指令啦)

結果我一開始裝完ufw後 ,一開始也好好的,繼續去檢查gcloud(不是vm哦)虛擬網路的防火牆

後來一重開VM後,就突然 webssh不進去了…,因為同時在調整gcp ssl的防火牆設定,所以我”以為”

我動了什麼設定造成了這個結果(盲點)

註:這段真的超笨的,一直鑽牛角尖在 外層的fw上,還加了全通的rule也不行..

後來我才知道 ,就是vm我因為裝了ufw,所以自己也有一層防火牆被打開了,所以外殼的就無法進入這個vm

這就有點像在vm中移除了網路界面卡,無法再透過網路的方式連進去了,以往有主機,還可以實體操作

之所以把gcp的設定問題排除主要也是我重新生成了一個新的vm,其實舊的image我也生成過,但生成後,重新掛”新”的獨立網路 還是連不進去,所以我用新的VM加新的網路後,用 我認知的外層 fw設定下,嗯可以,ssh的進去

所以我覺得應該還是在vm自已本身身上,猜想到我曾安裝ufw這一點後,我就試著設定ufw disable的語法到VM的開機指令去…想說碰碰運氣

在 VM的執行個體 編輯視窗..可以找到以下欄位

重啟動vm後 ,果然連進去了..恩 …自己搞自己..結案

註∶其實為了fw去安裝 ufw造成這個風波,在cloud的環境中,若能確認是內網的話(不對外),其實可以依賴google cloud的網路跟防火牆的設定就好(有界面萬歲),vm就分工上可以單純一點處理自己該做的事~就好

從Linux主機 使用SCP +SSH Copy檔案的相關指令

從Linux主機 使用SCP +SSH Copy檔案的相關指令

1.先將產生一個本地的ssh publickey/privatekey

#產生SSH key
ssh-keygen
#類型可以輸入rsa, 稍後就會產生id_rsa
cat id_rsa.pub
#印出id_rsa.pub內容
#複製到文字檔,再上傳到對方主機

#遠端到對方主機
#將公key append到ssh允許清單
cat id_rsa.pub >> .ssh/authorized_keys

2.本地檔案複製到對方主機

#遠端到對方主機

SCP -i ~/.ssh/id_rsa /本地檔案 username@hostname:/遠端檔案

#要注意-i指定的檔案id_rsa是私key,不是id_rsa.pub公key

就可以通了!