工具科普系列(2) — GCP Cloud Run 建置 Azure DevOps CI/CD Pipelines agents 實例(一)

陳彥榮
MODA IT
Published in
9 min readNov 17, 2023
圖片來源:https://blog.google/products/google-cloud/what-was-new-google-cloud-november-2020/

Cloud Run 是 Google Cloud Platform(GCP)提供的全託管 container 部署服務,結合 container 部署的優勢,以及 serverless 架構的彈性和便利性,能讓開發人員將應用程式快速以 container 部署和執行,而無需管理基礎架構或伺服器,使得開發和部署彈性且高度靈活。

Cloud Run 提供自動擴展功能,可根據應用程式的需求動態調整資源,從而節省成本並確保高效率。此外,Cloud Run 也與 Google Cloud 的其他服務整合良好,例如 Cloud Build、Cloud Monitoring 和 Cloud Logging,這些功能可提供更完整的開發、監控和管理解決方案,有助於開發者建立可靠且高效的應用程式。

原先我們在 Azure DevOps CI/CD pipelines 使用 Microsoft-hosted agents 為代理程式時,僅需指定 OS image(選項參照下圖),每次執行時即可有全新的執行環境,並由微軟負責建置和維護代理程式等工作項目。如此便捷的服務,卻出現一個問題:Microsoft-hosted agents 的 IP 位址來源廣泛(參考資料),難以設立 IP 位址白名單。

Microsoft-hosted agents 目前提供的 OS image

有鑑於此,我們研究在 GCP Cloud Run services 以 container 自建 Azure Pipelines Self-hosted Linux agent,搭配使用 Cloud NAT 的網路位址轉譯功能,以固定 agent 對外連線之 IP 位址,並於每次工作執行後即重建一個新的 agent,除能提供全新的執行環境,也能確保資料安全性。

微軟在官網有提供 Self-hosted Linux agent 的 Dockerfile,我們先選擇 Ubuntu 22.04 的範本:

FROM ubuntu:22.04

RUN apt update
RUN apt upgrade -y
RUN apt install -y curl git jq libicu70

# Also can be "linux-arm", "linux-arm64".
ENV TARGETARCH="linux-x64"

WORKDIR /azp/

COPY ./start.sh ./
RUN chmod +x ./start.sh

RUN useradd agent
RUN chown agent ./
USER agent
# Another option is to run the agent as root.
# ENV AGENT_ALLOW_RUNASROOT="true"

ENTRYPOINT ./start.sh

由於我們的 CI/CD 工作流程會使用 gcloud CLI、kubectl 和 envsubst 等 Linux 指令,所以我們在 container 中安裝相關套件,讓 agent 能執行相關指令:

FROM ubuntu:22.04

ENV AGENT_ALLOW_RUNASROOT="true"
ENV TARGETARCH="linux-x64"
ENV CLOUDSDK_CORE_DISABLE_PROMPTS="1"

RUN apt-get update && apt-get install -y curl git jq libicu70 sudo gnupg gettext-base

# install kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
chmod +x kubectl && \
mv kubectl /usr/local/bin/

# Install gcloud
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | \
tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && \
apt-get update && \
apt-get install -y google-cloud-cli && \
apt-get install -y google-cloud-sdk-gke-gcloud-auth-plugin

RUN apt-get upgrade -y

COPY ./start.sh /
WORKDIR /azp/

ENTRYPOINT /start.sh

之後我們在 GCP 自建 Artifact Registry 以提供 container images 存儲,並在 Cloud Shell 使用 Cloud Build 指令建置 image,於 Cloud Run services 建置 agent 進行測試,我們發現了兩個需要克服的問題:

  1. Cloud Run services 強制對 tcp port(預設為 8080)進行啟動健康檢查,但 agent 是 pull based mechanism,未有接收流量之需求。我們的解決方案是在 container 安裝網路工具套件 netcat,並在 start.sh 寫入 netcat 指令$ nc -lnp 8080以監聽 tcp port 8080。
  2. 由於我們希望每次工作執行後即重建一個新的 agent,須在 container 執行時加入--once參數,確保工作執行後 container 會自動移除,再利用 Cloud Run services 最低服務數量之設定,確保 container 會被重啟。但原先微軟官方提供的 entrypoint 格式,會導致參數無法被執行,所以我們根據下圖由 Docker 官方提供的資料,更改 entrypoint 格式。
資料來源:https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact

最後修改完成的 Dockerfile 如下:

FROM ubuntu:22.04

ENV AGENT_ALLOW_RUNASROOT="true"
ENV TARGETARCH="linux-x64"
ENV CLOUDSDK_CORE_DISABLE_PROMPTS="1"

RUN apt-get update && apt-get install -y curl git jq libicu70 sudo gnupg gettext-base netcat

RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
chmod +x kubectl && \
mv kubectl /usr/local/bin/

RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | \
tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && \
apt-get update && \
apt-get install -y google-cloud-cli && \
apt-get install -y google-cloud-sdk-gke-gcloud-auth-plugin

RUN apt-get upgrade -y

COPY ./start.sh /
WORKDIR /azp/

ENTRYPOINT ["/start.sh"]
CMD ["--once"]

建置 image 後,我們只須在 Cloud Run 執行前配置 Azure DevOps Server 相關環境變數,即可在 Cloud Run 執行後註冊與運行 Self-hosted Linux agents。

由於 Cloud Run 是全託管服務,預設不提供使用者以指令操作 container,導致我們在 image 建置過程中難以 debug,因此我們使用 ttyd 套件建置網頁終端機,讓我們能使用瀏覽器頁面直接對 container 下指令,以便測試。

https://github.com/tsl0922/ttyd/releases

我們在 Github 下載 ttyd.86_64 套件後,於 Cloud Shell 新增 Dockerfile :

From ubuntu:22.04

COPY ./ttyd /usr/bin/ttyd
COPY ./start.sh /

ENTRYPOINT ["/start.sh"]

以及 start.sh:

#!/bin/bash

ttyd -W -p 8080 -u 0 bash

使用 Cloud Build 指令建置 image 後,我們即可在 Cloud Run 建置並使用網頁終端機:

點選網址即可啟動網頁終端機

--

--