在雲端原生時代,容器化應用程式已成為主流,如何有效地佈署和管理容器化應用程式是 DevOps 工程師的重要課題。本文將探討 Fargate、Knative、Jenkins 和 Spinnaker 等技術,並結合實務經驗,提供一套完整的容器化應用佈署。從基礎概念到進階技巧,涵蓋 CI/CD 流程、自動化佈署、秘密管理和容器安全等關鍵環節,協助開發團隊提升效率並確保應用程式安全。

雲端原生時代的 DevOps 最佳實務:Fargate 基礎概念與優勢

Fargate 基礎概念與優勢

Fargate是一種無伺服器(Serverless)計算引擎,可與Amazon ECS和EKS搭配使用,讓您無需管理伺服器即可執行容器。您只需指定所需的CPU和記憶體資源,Fargate便會自動組態底層基礎設施,並根據您的應用程式需求進行擴充套件。

相較於傳統的EC2佈署方式,Fargate的優勢在於:

  • 無需管理伺服器: 省去伺服器組態、修補和擴充套件的繁瑣工作。
  • 按需付費: 只需為實際使用的計算資源付費,降低成本。
  • 自動擴充套件: 根據應用程式負載自動調整資源,確保高用性和效能。
  • 簡化佈署: 簡化容器佈署流程,提高開發效率。

Fargate 實戰演練:佈署 Web 應用程式

以下將逐步示範如何使用Fargate佈署一個簡單的Web應用程式。

1. 定義任務與資源需求

首先,我們需要定義Fargate任務的引數,包括CPU和記憶體限制。以下ecs-params.yaml檔案定義了容器所需的資源:

version: 1
task_definition:
  services:
    web:
      cpu_shares: 256  # 256 millicores
      mem_limit: 512 # 512 MB

內容解密:

這個YAML檔案定義了Fargate任務的資源限制。cpu_shares指定CPU配額為256毫核心(millicores),mem_limit指定記憶體限制為512MB。這些設定確保容器在執行時擁有足夠的資源來執行應用程式。

2. 設定網路與安全群組

Fargate任務需要使用awsvpc網路模式,並指定子網路和安全群組。以下是一個ecs-params.yaml檔案的範例:

version: 1
task_definition:
  task_execution_role: ecsTaskExecutionRole
  ecs_network_mode: awsvpc
  task_size:
    mem_limit: 0.5GB
    cpu_limit: 256
  run_params:
    network_configuration:
      awsvpc_configuration:
        subnets:
          - "subnet-xxxxxxxxxxxxxxxxx"
          - "subnet-yyyyyyyyyyyyyyyyy"
        security_groups:
          - "sg-zzzzzzzzzzzzzzzzz"
        assign_public_ip: ENABLED

內容解密:

此設定檔定義了Fargate任務的網路組態。ecs_network_mode設定為awsvpc,表示使用AWS VPC網路模式。subnetssecurity_groups指定了任務所屬的子網路和安全群組。assign_public_ip設定為ENABLED,表示為任務分配公有IP地址,使其能夠從外部存取。

3. 佈署 Fargate 任務

使用以下指令佈署Fargate任務:

ecs-cli compose up --create-log-groups --cluster <cluster_name> --launch-type FARGATE

內容解密:

這個指令使用ecs-cli工具將任務佈署到指定的ECS叢集。--create-log-groups引數會自動建立CloudWatch Log Group,用於儲存容器日誌。--launch-type FARGATE指定使用Fargate啟動型別,表示任務將在Fargate上執行,而無需管理底層伺服器。

4. 擴充套件與監控

使用以下指令將任務數量擴充套件到2個:

ecs-cli compose scale 2 --cluster <cluster_name> --launch-type FARGATE

內容解密:

這個指令將Fargate任務的數量擴充套件到2,實作應用程式的橫向擴充套件,以應對更高的流量負載。這種自動擴充套件的能力是Fargate的一大優勢,能夠根據需求動態調整資源。

您可以使用CloudWatch監控Fargate任務的執行狀態和資源使用情況,並查詢容器日誌:

aws logs get-log-events --log-group-name /aws/webserver --log-stream-name <log_stream_name>

內容解密:

這個指令從CloudWatch擷取指定日誌串流的日誌事件。您可以透過aws logs describe-log-streams指令檢視可用的日誌串流,從而進一步分析和排查問題。

在 ECS 上排程服務

ECS服務類別似於Kubernetes的ReplicaSets,它們確保特定數量的任務在特定時間持續執行。我們可以使用ecs-cli指令來排程服務。

小技巧: 對於像Web伺服器這樣的守護程式,請務必使用服務。而對於批次作業,請使用任務,因為我們不希望作業結束後重新建立。

以下指令可以將NGINX Web伺服器作為服務執行:

ecs-cli compose service up --create-log-groups \
--cluster cluster-1 --launch-type FARGATE

從日誌中可以看出,服務會嘗試確保任務的desired count與running count相符。如果任務因為某些原因被刪除,ECS會用新的任務替換它。

使用 ECS CLI 瀏覽容器日誌

除了使用AWS CloudWatch,您還可以透過ECS CLI來瀏覽日誌,無論日誌儲存在哪裡。這有助於我們從單一視窗檢視所有資訊。

執行以下指令:

ecs-cli logs --task-id <任務ID> --cluster cluster-1

負載平衡 ECS 上執行的容器

負載平衡是多例項應用程式的重要功能,它允許我們透過單一入口點提供服務。AWS提供了兩種主要的負載平衡解決方案:使用網路負載平衡器(NLB)的第四層負載平衡和使用應用程式負載平衡器(ALB)的第七層負載平衡。

小技巧: 雖然兩種負載平衡器都有各自的應用場景,但對於根據HTTP的應用程式,使用第七層負載平衡器具有顯著優勢。它提供了進階流量管理功能,例如根據路徑和根據主機的路由。

我們可以使用以下指令建立一個應用程式負載平衡器:

aws elbv2 create-load-balancer --name ecs-alb \
--subnets <子網路1> <子網路2> \
--security-groups <安全群組ID> \
--region <區域>

接下來,我們需要建立目標群組並將其與負載平衡器關聯起來,然後更新服務以使用負載平衡器。這樣,我們就可以透過單一入口點存取我們的應用程式。

總而言之,AWS Fargate提供了一種簡化容器佈署和管理的方式,讓開發者能夠專注於應用程式開發,而無需擔心底層基礎設施的管理。結合ECS和負載平衡功能,可以實作高效、可靠的容器化應用佈署。

利用 Knative 開發 Python Flask 應用

在雲原生時代,快速佈署和彈性伸縮應用程式至關重要。Knative 作為一個根據 Kubernetes 的平台,簡化了無伺服器應用的佈署和管理,讓開發者能更專注於程式碼本身。本文將引導您使用 Knative 佈署一個簡單的 Python Flask 應用,並探討 Knative 的核心概念和優勢。

準備 Kubernetes 叢集

首先,您需要一個 Kubernetes 叢集。建議使用 Google Kubernetes Engine (GKE),它提供了高度穩健的叢集環境,與 Knative 的整合也非常順暢。如果您還沒有 GKE 帳號,可以利用 Google Cloud 提供的免費試用額度。

在 Google Cloud Console 中開啟 Cloud Shell CLI,執行以下指令來啟用 Kubernetes Engine API:

gcloud services enable container.googleapis.com

程式碼解析:

以上指令用於啟用 Google Kubernetes Engine API,是建立和管理 GKE 叢集的必要步驟。啟用後,您可以開始建立和管理叢集。

接著,建立一個單節點自動擴充套件的 GKE 叢集:

gcloud container clusters create cluster-1 \
--num-nodes 2 --enable-autoscaling \
--min-nodes 1 --max-nodes 5 --zone us-central1-a

程式碼解析:

此指令建立了一個名為 cluster-1 的 GKE 叢集,具有以下組態:

  • 初始節點數為 2
  • 啟用自動擴充套件功能
  • 節點數可在 1 至 5 之間自動調整
  • 叢集位於 us-central1-a 區域

自動擴充套件功能可根據工作負載需求動態調整節點數量,確保資源的有效利用。

安裝 Knative

在 GKE 叢集建立完成後,下一步是安裝 Knative。Knative 需要 Kubernetes 1.22 或更高版本,因此請確保您的叢集版本符合要求。

首先,安裝 Knative Serving 元件:

kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.8/serving-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.8/serving-core.yaml

程式碼解析:

以上指令安裝了 Knative Serving 的自定義資源定義(CRD)和核心元件。Knative Serving 負責管理無伺服器工作負載的生命週期,包括自動擴充套件和流量管理。

接著,安裝 Knative 網路層元件(例如 Kourier):

kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.8/kourier.yaml

並將 Kourier 設定為預設的網路層:

kubectl patch configmap/config-network \
--namespace knative-serving \
--type merge \
--patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'

程式碼解析:

Kourier 是 Knative 的一個網路層實作,提供流量路由和負載平衡功能。將其設定為預設網路層後,Knative 將使用 Kourier 來管理進入的工作負載流量。

建立 Python Flask 應用

接下來,建立一個簡單的 Python Flask 應用。建立一個名為 app.py 的檔案,並加入以下程式碼:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, Knative!'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

程式碼解析:

此 Python 程式碼建立了一個基本的 Flask 網頁伺服器,當存取根路徑 / 時,傳回 “Hello, Knative!” 字串。這是一個簡單的範例,用於展示如何將應用程式容器化並佈署到 Knative。

將應用容器化

建立 Dockerfile 以容器化您的 Flask 應用:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]

同時,建立 requirements.txt 檔案並新增以下內容:

flask

程式碼解析:

此 Dockerfile 使用官方 Python 3.9 映象作為基礎,將應用程式碼複製到容器中,並安裝所需的依賴項(Flask)。最後,它設定了容器的啟動命令以執行 Flask 應用。

建置並推播 Docker 映象

建置 Docker 映象並將其推播到容器註冊中心(例如 Google Artifact Registry 或 Docker Hub):

docker build -t gcr.io/[PROJECT-ID]/flask-knative-demo .
docker push gcr.io/[PROJECT-ID]/flask-knative-demo

請將 [PROJECT-ID] 替換為您的實際專案 ID。

程式碼解析:

此指令建置了一個名為 flask-knative-demo 的 Docker 映象,並將其推播到 Google Container Registry。請確保您已驗證 Docker 與您的容器註冊中心連線。

使用 Knative 佈署應用

建立一個 Knative Service 定義檔案 service.yaml,內容如下:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: flask-demo
spec:
  template:
    spec:
      containers:
      - image: gcr.io/[PROJECT-ID]/flask-knative-demo
        ports:
        - containerPort: 5000

[PROJECT-ID] 替換為您的專案 ID,然後執行以下指令以佈署服務:

kubectl apply -f service.yaml

程式碼解析:

此 YAML 組態定義了一個 Knative Service 物件,用於佈署 flask-knative-demo 映象。Knative 將自動建立一個可擴充套件的服務,並根據流量需求調整 Pod 數量。

驗證佈署結果

佈署完成後,您可以使用以下指令檢查服務狀態:

kubectl get ksvc flask-demo -o yaml

該指令將輸出服務的詳細組態,包括服務的 URL。存取該 URL 以驗證 Flask 應用是否正常執行。

結果解讀:

輸出結果包含服務的當前狀態、URL 和其他相關組態。透過存取提供的 URL,您可以確認 Flask 應用已成功佈署並可正常回應請求。

自動擴充套件測試

Knative 的一大優勢是其自動擴充套件功能。您可以使用以下指令產生一些流量,以測試自動擴充套件功能:

kubectl run --image=alpine --restart=Never --rm -it load-generator -- wget -q -O- http://flask-demo.default.127.0.0.1.sslip.io

執行期間,您可以觀察 Pod 的變化:

kubectl get pods -w

結果解讀:

此指令產生了一個臨時 Pod,向您的 Flask 服務傳送請求。同時,另一個終端視窗中的 kubectl get pods -w 命令將持續監控 Pod 狀態,您可以看到 Knative 自動擴充套件 Pod 以處理增加的流量。

清理資源

完成測試後,請記得清理資源,以避免不必要的費用。刪除 GKE 叢集:

gcloud container clusters delete cluster-1 --zone us-central1-a

程式碼解析:

此指令刪除之前建立的 GKE 叢集,釋放相關資源,避免持續產生費用。

使用 GitHub Actions 建立 CI 流程

持續整合(CI)在軟體開發生命週期(SDLC)中扮演著至關重要的角色。它可以及早發現程式碼問題,降低修復錯誤的成本,並提升軟體品質。本文將以一個 Python Flask 應用程式為例,示範如何使用 GitHub Actions 建立 CI 流程,自動執行建置和測試工作。

GitHub Actions 簡介

GitHub Actions 是一個根據 SaaS 的工具,與 GitHub 緊密整合。建立 GitHub 儲存函式庫後,即可立即使用此服務。對於 CI/CD 新手而言,GitHub Actions 是一個理想的入門工具。

#### 內容解密:

GitHub Actions 提供了一個強大的自動化平台,能夠簡化 CI/CD 流程。它與 GitHub 的整合使得建立和管理自動化工作流程變得更加容易,特別適合開發團隊快速迭代和交付高品質軟體。

建立 GitHub Actions 工作流程

要為 Python Flask 應用程式建立 CI 流程,首先需要在專案根目錄下建立 .github/workflows 目錄,並在其中建立一個 YAML 檔案來定義工作流程。例如,ci.yml

name: Python Flask CI

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.x'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install flake8 pytest
          pip install -r requirements.txt

      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

      - name: Test with pytest
        run: |
          pytest

#### 內容解密:

這個 YAML 檔案定義了一個名為 “Python Flask CI” 的工作流程,當 main 分支有程式碼推播時觸發。它包含了簽出程式碼、設定 Python 環境、安裝依賴項、使用 flake8 進行程式碼檢查以及使用 pytest 執行測試等步驟。這樣的工作流程確保了程式碼的品質和正確性。

自動化測試與建置

在上述工作流程中,我們使用了 pytest 來執行自動化測試。確保在 requirements.txt 中包含了所有必要的依賴項,包括 pytest

Flask==2.0.1
gunicorn==20.1.0
pytest==6.2.4

#### 內容解密:

透過在 requirements.txt 中指定依賴項版本,可以確保在不同環境中安裝相同的依賴項版本,從而提高應用程式的可重複性和可靠性。

#### 流程解密:

上圖展示了使用 GitHub Actions 的 CI 流程。當程式碼提交到 GitHub 時,GitHub Actions 自動觸發工作流程,執行自動化測試和建置,並回報結果。這樣的流程確保了程式碼變更能夠被及時驗證和回饋。

利用 GitHub Actions 建立 CI Pipeline 的實務技巧(續)

實作測試與建置

在 CI Pipeline 中,測試和建置是兩個關鍵步驟。測試能夠確保程式碼變更不會引入新的錯誤,而建置則負責將程式碼編譯或封裝成可執行的格式。以下是一個結合測試和建置的 Workflow 範例:

name: CI Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: 安裝依賴套件
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      - name: 執行測試
        run: |
          python -m unittest discover -s tests
      - name: 建置 Docker 映像檔
        run: docker build -t my-image .
      - name: 推播 Docker 映像檔
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
        run: |
          echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin
          docker push my-image

內容解密:

這個 Workflow 在 ubuntu-latest 環境中執行,包含以下步驟:

  1. 安裝依賴套件:升級 pip 並安裝 requirements.txt 中指定的依賴套件。
  2. 執行測試:使用 unittest 模組執行測試案例。
  3. 建置 Docker 映像檔:根據 Dockerfile 建置 Docker 映像檔。
  4. 推播 Docker 映像檔:登入 Docker Hub 並推播建置好的 Docker 映像檔。

Plantuml 圖表示範 CI Pipeline

以下 Plantuml 圖表展示了 CI Pipeline 的流程:

流程解密:

這張圖表描述了 CI Pipeline 的工作流程。當程式碼發生變更時,GitHub Actions 被觸發,依序執行以下步驟:

  1. Checkout 程式碼:從儲存函式庫中取出最新的程式碼。
  2. 安裝依賴套件:安裝專案所需的依賴套件。
  3. 執行測試:執行測試案例以驗證程式碼變更。
  4. 測試是否透過:檢查測試結果。如果測試透過,則繼續建置 Docker 映像檔;如果測試失敗,則傳送通知。
  5. 建置 Docker 映像檔:根據 Dockerfile 建置 Docker 映像檔。
  6. 推播 Docker 映像檔:將建置好的 Docker 映像檔推播到 Docker Hub。

實施 Kubernetes 的 CI/CD Pipeline

摘要

本文探討了在 Kubernetes 環境中建立高效 CI/CD pipeline 的技術細節,重點介紹了 GitHub Actions 和 Kaniko 的實務應用。透過詳細的技術分析和程式碼範例,展示瞭如何在 Kubernetes 叢集中實作自動化的建置、測試和佈署流程。

GitHub Actions 的 CI Pipeline 設定

要建立一個高效的 CI pipeline,首先需要在 GitHub 儲存函式庫中設定 GitHub Actions。以下是一個基本的 Workflow 設定範例:

name: CI Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

steps:
    - uses: actions/checkout@v3
    - name: Run Tests
      run: pytest
    - name: Build Docker Image
      if: success()
      run: docker build -t my-image .
    - name: Push Docker Image
      if: success()
      run: docker push my-image

內容解密:

這個 Workflow 在每次推播或提交 pull request 到 main 分支時觸發。它首先執行測試,只有在測試透過後才會建置 Docker 映像檔並將其推播到指定的容器註冊中心。

使用 Kaniko 建置容器映像檔

在 Kubernetes 環境中,Kaniko 提供了一個無需 Docker daemon 的容器映像檔建置方案,大大提高了安全性。以下是一個使用 Kaniko 的 Dockerfile 範例:

FROM gcr.io/kaniko-project/executor:v0.11.0 as kaniko
FROM jenkins/jnlp-slave
COPY --from=kaniko /kaniko /kaniko
WORKDIR /kaniko
USER root

內容解密:

這個 Dockerfile 使用多階段建置的方式,將 Kaniko 的執行檔整合到 Jenkins 的 JNLP slave 映像檔中,使得 Jenkins agent 能夠使用 Kaniko 建置容器映像檔。

在 Kubernetes 上佈署 Jenkins

要在 Kubernetes 上佈署 Jenkins,需要建立一系列的資源,包括 Deployment、Service 和 PersistentVolumeClaim。以下是一個 Jenkins Deployment 的 YAML 範例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      containers:
      - name: jenkins
        image: <您的 DockerHub 使用者名稱>/jenkins-master-kaniko
        ports:
        - containerPort: 8080
        - containerPort: 50000

內容解密:

這個 Deployment 使用自訂的 Jenkins master 映像檔,並暴露了 8080 和 50000 連線埠,分別用於 Web UI 和 JNLP 通訊。

CI/CD 流程示意圖

流程解密:

這個流程圖展示了從程式碼變更到佈署到 Kubernetes 的整個 CI/CD 流程。程式碼變更觸發 Workflow 後,首先執行測試。根據測試結果,決定是否建置映像檔並佈署到 Kubernetes,或通知開發者處理失敗的測試。

使用 Kaniko 在 Kubernetes 上建置可擴充套件的 Jenkins

在 Kubernetes 上執行 Jenkins 提供了高度的靈活性與可擴充套件性,結合 Kaniko 這樣的容器構建工具,更能簡化容器映象的構建流程。本文將探討如何在 Kubernetes 環境中佈署 Jenkins,並使用 Kaniko 構建 Docker 映象,同時分享我在實務操作中的一些心得與技巧。

執行第一個 Jenkins Job

在建立第一個 Jenkins Job 之前,需要先準備好程式碼儲存函式庫。以下步驟說明如何設定 GitHub 儲存函式庫並準備執行 Job:

  1. 複製範例程式碼到你的儲存函式庫:
cd ~/modern-devops/ch10
git clone [你的儲存函式庫網址]
cp -a flask-app/* [你的儲存函式庫名稱]
cp jenkins/jenkins-agent/build.sh [你的儲存函式庫名稱]

內容解密:

以上指令示範如何將範例程式碼複製到指定的 GitHub 儲存函式庫。首先,切換到目標目錄 ~/modern-devops/ch10,然後使用 git clone 下載儲存函式庫內容。接著,使用 cp 指令將 flask-app 目錄下的所有檔案複製到目標儲存函式庫,並將 build.sh 指令碼複製過去以供後續建置使用。

  1. 提交並推播你的修改到 GitHub。

完成後,就可以在 Jenkins 中建立 Job。步驟如下:

  1. 在 Jenkins 首頁,點選「新增作業」。
  2. 選擇「自由風格專案」,輸入 Job 名稱(建議與儲存函式庫名稱相同),然後點選「確定」。
  3. 在「原始碼管理」區塊,選擇「Git」,並填入你的 Git 儲存函式庫網址和分支名稱。參考下圖:

流程解密:

此 Plantuml 圖表說明瞭 Jenkins 如何與 Git 儲存函式庫互動。Jenkins 從指定的 Git 儲存函式庫擷取程式碼,並根據指定的分支名稱進行建置操作。

  1. 在「建置觸發程式」區塊,選擇「輪詢 SCM」,並設定輪詢時間。參考下圖:

流程解密:

此甘特圖顯示了 Jenkins 的輪詢設定。每隔一分鐘,Jenkins 就會檢查 Git 儲存函式庫是否有新的提交,以觸發建置流程。

  1. 在「建置」區塊,點選「新增建置步驟」,選擇「執行 shell」。在 shell 指令碼中,使用 build.sh 指令碼構建 Docker 映象,並根據你的需求修改引數。參考下圖:

流程解密:

此圖表說明瞭 Jenkins 建置流程中的 shell 指令碼執行步驟。透過執行 build.sh,Jenkins 建置 Docker 映象並進行相關操作。

  1. 點選「儲存」以完成 Job 設定。

現在可以執行這個 Job。你可以到 Job 設定頁面點選「立即建置」,或者推播修改到 GitHub 觸發建置。

使用觸發程式自動化建置

使用 post-commit webhook 是在程式碼修改後觸發 CI 建置的最佳方式。以下步驟說明如何在 Jenkins 和 GitHub 上設定 webhook:

  1. 在 Jenkins 的 Job 設定頁面,選擇「建置觸發程式」,勾選「GitHub hook trigger for GITScm polling」。
  2. 在 GitHub 儲存函式庫設定中,點選「Webhooks」,然後點選「Add webhook」。填入 Jenkins webhook URL,並選擇觸發事件。

使用 AWS Code Commit 和 Code Build 進行 CI

AWS Code Commit 和 Code Build 是 AWS 提供的 CI/CD 服務,可以簡化持續整合和持續交付流程。

建立 AWS Code Commit 儲存函式庫

使用以下指令建立名為 flask-app 的 AWS Code Commit 儲存函式庫:

aws codecommit create-repository --repository-name flask-app

內容解密:

此指令使用 AWS CLI 建立一個新的 CodeCommit 儲存函式庫,名稱為 flask-app。成功執行後,會傳回包含儲存函式庫詳細資訊的 JSON 回應,其中包括 cloneUrlHttpcloneUrlSsh,可用於複製儲存函式庫。

接下來,需要設定 Git 的認證資訊以連線到 CodeCommit:

git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true

內容解密:

以上組態設定了 Git 使用 AWS CodeCommit 認證助手來處理身分驗證請求,並啟用 HTTP 路徑支援,以確保正確存取 CodeCommit 儲存函式庫。

然後使用 HTTPS URL 複製儲存函式庫:

git clone https://git-codecommit.us-east-1.amazonaws.com/v1/repos/flask-app

建立 AWS Code Build Job

首先,需要建立一個 IAM 角色供 CodeBuild 使用:

aws iam create-role --role-name CodeBuildServiceRole --assume-role-policy-document file://create-role.json

內容解密:

此命令建立了一個名為 CodeBuildServiceRole 的 IAM 角色,並指定了信任策略檔案 create-role.json,定義了哪些服務可以擔任此角色。

接著,為角色新增必要的許可權策略:

aws iam put-role-policy --role-name CodeBuildServiceRole --policy-name CodeBuildServiceRolePolicy --policy-document file://put-role-policy.json

內容解密:

此命令為 CodeBuildServiceRole 增加了一個內嵌策略 CodeBuildServiceRolePolicy,該策略定義了 CodeBuild 可以執行的操作和存取的資源,從而使 CodeBuild 能夠與其他 AWS 服務互動。

總結來說,本文介紹瞭如何在 Kubernetes 上使用 Kaniko 建置可擴充套件的 Jenkins,並探討了使用 AWS CodeCommit 和 CodeBuild 的 CI/CD 組態細節。在下一篇文章中,我們將進一步探討 Spinnaker 的組態與應用,以實作更全面的持續交付和佈署自動化。

Spinnaker 技術深度解析與實務應用

Spinnaker 作為現代持續交付的核心工具,其技術架構和實務應用呈現出多項值得探討的特性。以下將從其架構設計、核心功能以及在實際環境中的佈署策略進行全面分析。

Spinnaker 的技術架構與核心優勢

Spinnaker 的技術架構設計使其能夠支援跨多雲環境的持續交付。該工具的核心優勢在於其強大的 Pipeline 管理能力,能夠無縫整合多種雲端服務和容器協調系統。透過支援 AWS EC2、EKS、Kubernetes、Google Cloud 等多種平台,Spinnaker 為企業提供了極高的靈活性和可擴充套件性。

在實際應用中,Spinnaker 的 Pipeline 功能涵蓋了從程式碼提交到生產環境佈署的完整流程。透過與 Git 事件、Jenkins、Docker 等工具的整合,Spinnaker 能夠實作自動化的構建、測試和佈署,大幅提升了軟體交付的效率和可靠性。

內容解密:

Spinnaker 的 Pipeline 組態包含多個階段,例如 Bake(構建映像檔)和 Deploy(佈署到 Kubernetes)。這些階段的設計確保了應用程式能夠以可預測和可重複的方式進行佈署。透過使用不可變映像檔,Spinnaker 減少了組態漂移的風險,提高了系統的穩定性。

Spinnaker 在複雜環境中的佈署策略

在複雜的企業環境中,Spinnaker 的佈署策略需要根據具體的業務需求進行調整。藍/綠佈署和金絲雀發布是兩種常見的佈署模式,分別適用於不同的場景。

藍/綠佈署:無縫切換的實務應用

藍/綠佈署策略透過平行執行兩個相同的生產環境(藍色和綠色),實作零停機時間的佈署。當新版本(綠色)準備就緒並透過測試後,流量將被切換到新環境,而舊版本(藍色)則保持備用狀態,以便在必要時進行快速回復。

流程解密:

此圖展示了藍/綠佈署的完整流程。首先,綠色版本與藍色版本平行佈署。接著,透過健全性檢查確認新版本的穩定性。如果測試透過,流量將被切換到綠色版本,並最終移除藍色版本。如果測試失敗,系統將自動回復到藍色版本,確保業務連續性。

金絲雀發布:精細控制的實務應用

金絲雀發布則是一種更為保守的佈署策略,透過將新版本佈署到一小部分使用者來進行驗證。這種方法允許團隊在正式全量發布前收集反饋並進行必要的調整,從而降低了大規模佈署帶來的風險。

流程解密:

金絲雀發布的核心在於對新版本的逐步驗證。首先,只有少數使用者會被導向新版本,透過監控這部分使用者的反饋來評估新版本的穩定性和效能。如果測試結果符合預期,則逐步增加新版本的流量比例,直至完全取代舊版本。

Spinnaker 的未來發展趨勢

隨著雲原生技術的不斷發展,Spinnaker 在未來將繼續扮演重要的角色。其對多雲環境的支援以及與各種 CI/CD 工具的整合,使其成為企業實作 DevOps 轉型的關鍵工具之一。

在未來的發展中,Spinnaker 有望進一步增強其自動化能力和智慧化水平,例如透過整合 AI/ML 技術來最佳化 Pipeline 的執行效率。同時,隨著更多企業採用混合雲和多雲策略,Spinnaker 的跨雲管理能力將變得更加重要。

總而言之,Spinnaker 以其強大的功能和靈活的架構,為現代軟體開發和維運團隊提供了高效、可靠的持續交付解決方案。透過深入理解其技術特性和實務應用,企業能夠更好地利用 Spinnaker 實作 DevOps 轉型,提升軟體交付的速度和品質。

Spinnaker 持續佈署實戰:開發自動化交付Pipeline(續)

完成範例應用程式佈署設定檔

在上一節中,我們開始建立 manifest.yaml 檔案,用於定義 Kubernetes 佈署所需的資源。以下是完整的設定檔內容:

apiVersion: v1
kind: Namespace
metadata:
  name: '${namespace}'

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-app
  namespace: '${namespace}'
spec:
  replicas: 3
  selector:
    matchLabels:
      app: flask-app
  template:
    metadata:
      labels:
        app: flask-app
    spec:
      containers:
      - name: flask-app
        image: '${docker_image}'
        ports:
        - containerPort: 5000

---
apiVersion: v1
kind: Service
metadata:
  name: flask-app
  namespace: '${namespace}'
spec:
  selector:
    app: flask-app
  ports:
  - name: http
    port: 80
    targetPort: 5000
  type: LoadBalancer

內容解密: 以上 YAML 設定檔定義了三個 Kubernetes 資源:

  1. Namespace:根據引數 ${namespace} 建立名稱空間。
  2. Deployment:建立名為 flask-app 的佈署,使用 ${docker_image} 指定的 Docker 映像檔,並設定副本數為 3。
  3. Service:建立名為 flask-app 的服務,將流量轉發到佈署中的容器,並透過 LoadBalancer 對外暴露服務。

在 Spinnaker 中建立Pipeline

  1. 登入 Spinnaker UI,點選 “Pipelines” > “Create Pipeline”。
  2. 輸入Pipeline名稱,例如 “Flask App Deployment”。
  3. 在 “Automated Triggers” 中,新增一個觸發器,選擇 “Docker Registry” 作為觸發型別,並設定監控的 Docker 映像檔倉函式庫。
  4. 新增一個 “Deploy (Manifest)” 階段,選擇剛才建立的 manifest.yaml 設定檔,並設定相關引數。

流程解密: 上圖展示了從程式碼變更到自動化佈署的流程。首先,開發人員提交程式碼變更,觸發 CI 流程。CI 流程完成後,將新版本的 Docker 映像檔推播到 Docker Hub。Spinnaker 監控到新的映像檔後,自動觸發Pipeline,將應用程式佈署到 Staging 環境。經過人工驗證後,如果透過,則自動將應用程式佈署到 Production 環境。

Pipeline設定詳解

在 Spinnaker 中,Pipeline是由多個階段組成的。每個階段可以是不同的操作,例如:

  • Deploy (Manifest):根據提供的 Kubernetes 清單檔案佈署應用程式。
  • Manual Judgment:需要人工干預的階段,用於審核或驗證。
  • Wait:等待一段時間,用於暫停 Pipeline 的執行。

以下是一個典型的 Pipeline 設定範例:

  1. 觸發器(Trigger):設定 Docker Registry 觸發器,當監控的映像檔有新版本時觸發 Pipeline。
  2. 佈署到 Staging:使用 “Deploy (Manifest)” 階段,將應用程式佈署到 Staging 環境。
  3. 人工驗證(Manual Judgment):新增一個 “Manual Judgment” 階段,需要人工確認是否繼續佈署到 Production 環境。
  4. 佈署到 Production:如果人工驗證透過,則使用另一個 “Deploy (Manifest)” 階段,將應用程式佈署到 Production 環境。

最佳實踐與注意事項

  1. 安全性:確保 Spinnaker 有適當的許可權存取 Kubernetes 叢集和 Docker Registry。
  2. 監控與日誌:設定適當的監控和日誌收集機制,以便及時發現和解決問題。
  3. 版本控制:將 Pipeline 設定和 Kubernetes 清單檔案納入版本控制系統,以便追蹤變更和管理不同版本。
  4. 測試與驗證:在 Pipeline 中加入適當的測試和驗證階段,確保應用程式的品質和穩定性。

透過遵循上述步驟和最佳實踐,您可以建立一個強大且自動化的持續佈署Pipeline,提高軟體交付的速度和品質。

在 Kubernetes 中保護 CI/CD Pipeline 的秘密管理

現代 DevOps 中的 CI/CD Pipeline 串聯所有流程並整合所有工具,以更快的速度交付更好的軟體。然而,如何確保這些 Pipeline 的安全至關重要。本文將探討如何在 Kubernetes 環境中安全地管理 CI/CD Pipeline 中的敏感資訊,並著重於使用 Google Cloud Key Management Service (Cloud KMS) 的最佳實踐。

秘密管理的重要性

應用程式碼通常需要存取敏感資訊,例如密碼、API 金鑰、SSH 金鑰和 TLS/SSL 私鑰等。這些資訊在 DevOps 中稱為「秘密」。妥善管理秘密對於防止未經授權的存取至關重要。

在 CI/CD Pipeline 中,由於所有構建都從原始碼開始,因此秘密管理變得更加重要。切勿將秘密硬編碼到 Pipeline 中,或將其儲存在程式碼儲存函式庫(如 Git)中。

容器化應用程式也需要特別注意秘密管理。避免將秘密嵌入容器映像中,因為這會造成嚴重的安全漏洞。

使用秘密管理解決方案

秘密管理解決方案或金鑰管理解決方案可協助儲存、管理和保護您的秘密,並在靜態和傳輸過程中進行加密。雲端供應商(例如 GCP 和 AWS)提供金鑰管理工具,或者您可以使用第三方工具(例如 HashiCorp Vault)。這些解決方案都提供 API 以在執行階段建立和查詢秘密,並透過 HTTPS 保護 API 以確保傳輸過程中的加密。

本文將使用 GCP 提供的 Cloud KMS 解決方案來儲存秘密,並在執行 CI/CD Pipeline 時存取它們。Cloud KMS 是 Google Cloud 的秘密管理系統,可協助您集中儲存和管理秘密。它非常安全,並使用硬體安全模組 (HSM) 來提供額外的秘密強化。

範例應用程式

我們將使用一個 Python Flask 應用程式作為範例。這是一個簡單的 API,它從名為 SECRET 的環境變數中取得秘密值,並傳回 “The secret is "。我們不會將秘密儲存在原始碼中,而是使用 Kubernetes 的 Secret 資源來管理它。

建立 Kubernetes Secret

首先,我們需要建立一個 Kubernetes Secret 資源來儲存我們的秘密。可以使用 kubectl 命令列工具來建立 Secret:

$ kubectl create secret generic my-secret --from-literal=SECRET=my_secret_value

在應用程式中使用 Secret

接下來,我們需要在應用程式中使用這個 Secret。可以在 Deployment 組態檔中參考這個 Secret,並將其作為環境變數注入到容器中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask-app
  template:
    metadata:
      labels:
        app: flask-app
    spec:
      containers:
      - name: flask-app
        image: <your-dockerhub-user>/flask-app:latest
        env:
        - name: SECRET
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: SECRET

使用 Cloud KMS 加密 Secret

為了進一步提高安全性,我們可以使用 Cloud KMS 來加密我們的 Secret。首先,需要建立一個 Cloud KMS 金鑰環和一個金鑰:

$ gcloud kms keyrings create my-keyring --location global
$ gcloud kms keys create my-key --location global --keyring my-keyring --purpose encryption

然後,可以使用這個金鑰來加密我們的 Secret:

$ echo -n my_secret_value | gcloud kms encrypt --location global --keyring my-keyring --key my-key --plaintext-file - --ciphertext-file - | base64

將加密後的 Secret 值儲存在 Kubernetes Secret 資源中,並在應用程式中使用它。

內容解密:

本文示範瞭如何在 Kubernetes 環境中使用 Cloud KMS 來安全地管理 CI/CD Pipeline 中的敏感資訊。首先,建立了一個 Kubernetes Secret 資源來儲存敏感資訊。然後,在應用程式中使用這個 Secret,將其作為環境變數注入到容器中。最後,使用 Cloud KMS 來加密 Secret,提高了安全性。

本範例示範瞭如何在現代 DevOps 中使用 Cloud KMS 和 Kubernetes 來保護 CI/CD Pipeline 的秘密管理。這種方法可以幫助您更好地保護您的應用程式和資料,提高整體的安全性。

關鍵內容審查與增強

根據提供的技術檔案內容,以下是對其結構、技術深度和本地化需求的專業審查與改進建議。

1. 內容結構最佳化

  • 改善小標題層次結構:目前的小標題層次不夠清晰,建議在每個主要章節前使用一級標題(#),並在子主題中使用二級標題(##)或更低層級的標題,以增強檔案的可讀性和導航性。
  • 統一程式碼範例的呈現方式:所有程式碼範例後應一致地使用「#### 內容解密:」部分進行詳細解釋,避免機械式說明,改用自然敘事方式闡述程式碼的功能與設計考量。

2. 提升技術深度與真實性

  • 強化現實世界應用案例:增加更多真實世界的應用場景和案例研究,以展示技術的實際應用和潛在挑戰,使內容更具說服力和實用價值。
  • 更新技術術語和工具版本:確保所使用的技術術語、工具和框架版本是最新的,並與台灣本地的技術社群保持一致,以提高內容的相關性和權威性。

3. 本地化需求強化

  • 使用繁體中文術語:確保所有技術術語和程式碼註解均使用台灣慣用的繁體中文,避免簡體中文或大陸術語,以符合本地化需求。
  • 符合台灣技術社群慣例:在語言表達和技術實踐上,應充分考慮台灣本地技術社群的習慣和偏好,例如程式碼命名慣例、註解風格等。

4. 圖表與視覺元素最佳化

  • Plantuml 圖表說明:對於所有 Plantuml 圖表,應提供清晰的「#### 流程解密」部分,詳細解釋圖表所展示的工作流程、架構或概念關係,避免對工具本身的參照。
  • 圖表本地化:確保所有視覺元素(如圖表、圖解)的文字說明和標註均使用繁體中文,並符合台灣本地的表達習慣。

5. 寫作風格與品質控制

  • 自然敘事風格:保持專業深度的同時,使用自然敘事風格撰寫內容,避免過度機械或程式化的表達方式。
  • 避免 AI 常見陷阱:嚴格避免 AI 生成內容常見的問題,如重複內容、元描述和對寫作過程的討論,確保內容的原創性和專業性。

6. 連續性與完整性要求

  • 文章完整性:確保每篇文章均能完整生成,不會在結論前意外終止。每篇文章都應包含實質性的結論,提供前瞻性思考和對實際影響的反思。
  • 結論品質:結論部分應提供有價值的見解,而非簡單的重複或突然結束。應根據主題深度,提供適當的前瞻性分析和實際應用建議。

透過上述改進措施,可以顯著提升技術檔案的品質、技術深度和本地化適應性,使其更符合專業讀者的需求和台灣本地技術社群的慣例。

容器安全強化:漏洞掃描與二進位授權的最佳實踐

在雲原生時代,容器安全已成為應用程式佈署的核心要素。本文將探討如何利用漏洞掃描工具 Grype 和二進位授權機制來強化容器佈署的安全性,並分享在實踐中的經驗和心得。

基礎映像選擇的最佳實踐

選擇合適的基礎映像是確保容器安全的第一步。建議優先使用 Alpine Linux 作為基礎映像,因為其體積小、安全性高。以一個根據 Flask 的應用程式為例,使用 Alpine Linux 作為基礎映像可以顯著減少映像大小。

$ docker images | grep flask-app-secret | grep alpine
flask-app-secret alpine 499786ff8b21 44 seconds ago 52.4MB

內容解密:

上述指令展示瞭如何檢查 Docker 映像的大小。使用 Alpine 版本的基礎映像可以將大小減少到 slim 版本的一半以下,從而降低攻擊面並提升佈署效率。

使用 Grype 進行漏洞掃描

Grype 是一款開源的漏洞掃描工具,可以快速識別容器映像中的已知漏洞。建議在 CI/CD 流程中整合 Grype,並設定嚴重性閾值以控制構建流程。

$ grype -f high flask-app-secret:slim
...
discovered vulnerabilities at or above the severity threshold

內容解密:

此指令設定了 high 嚴重性閾值,確保 Grype 在發現高或嚴重級別的漏洞時阻止構建。這種方式可以有效防止存在嚴重漏洞的映像被佈署到生產環境。

二進位授權:佈署階段的安全保障

二進位授權是一種佈署時的安全機制,確保只有受信任的映像被佈署到 Kubernetes 叢集中。該機制透過 Kubernetes 的准入控制器強制執行規則,只允許經過簽名的映像進行佈署。

使用 Google Cloud KMS 建立 PKI

在 Google Kubernetes Engine (GKE) 中,可以使用內建的二進位授權功能。以下是建立 PKI 的步驟:

  1. 設定環境變數:
$ PROJECT_ID=$(gcloud config list --format 'value(core.project)')
$ ATTESTOR_NAME=default-attestor
# ... 其他變數設定 ...
  1. 建立 Attestor Note 和 Attestor:
$ cat > /tmp/note_payload.json << EOM
{ ... }
EOM
$ curl -X POST ...
$ gcloud container binauthz attestors create ${ATTESTOR_NAME} ...
  1. 建立 Cloud KMS Keyring 和 Key,並將公鑰新增到 Attestor:
$ gcloud kms keyrings create ${KMS_KEYRING_NAME} ...
$ gcloud kms keys create ${KMS_KEY_NAME} ...
$ gcloud container binauthz attestors public-keys add ...

建立預設的二進位授權策略

建立一個預設策略,要求所有映像必須經過 Attestor 簽名才能佈署:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: REQUIRE_ATTESTATION
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  requireAttestationsBy:
  - projects/${PROJECT_ID}/attestors/${ATTESTOR_NAME}
name: projects/${PROJECT_ID}/policy

將策略匯入叢集:

$ gcloud container binauthz policy import /tmp/policy.yaml

驗證佈署安全性

嘗試佈署未經簽名的映像,驗證策略是否生效:

$ kubectl run flask-app-secret --image docker.io/<your_dockerhub_user>/flask-app-secret:1 --port 5000

佈署失敗後,需要對映像進行簽名後再次嘗試佈署。

容器安全流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Fargate Knative Jenkins Spinnaker 容器佈署安全

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

流程解密: 此圖表展示了從構建到佈署的完整流程,包括漏洞掃描和二進位授權兩個關鍵安全步驟,有效確保容器佈署的安全性。