1845 字
9 分鐘
實戰 GitOps:使用 k3s、ArgoCD 與 GitHub Actions 部署私有 Python 服務

實戰 GitOps:使用 k3s、ArgoCD 與 GitHub Actions 部署私有 Python 服務#

在現代化的 DevOps 流程中,GitOps 已經成為管理 Kubernetes 應用程式的標準方式。本文將帶領你從零開始,搭建一個輕量級的 Kubernetes (k3s) 叢集,安裝 ArgoCD,並實作一套完整的 CI/CD 流程,將一個「私有網路性質」的 Python 服務自動部署到叢集中。

🎯 目標架構#

我們的目標是建立以下流程:

  1. 開發 (Dev): 在本地編寫 Python 程式碼。
  2. 持續整合 (CI): 推送程式碼到 GitHub,觸發 GitHub Actions 進行 Docker Image 建置與推送。
  3. 版本更新: CI 流程自動修改 Git Repository 中的 Kubernetes Manifest,更新 Image Tag。
  4. 持續部署 (CD): ArgoCD 偵測到 Git 變更,自動將新版本同步到 k3s 叢集。
  5. 私有服務 (Private Service): 部署的 Python 服務僅在叢集內部可訪問,不對公網開放。
TIP

為什麼選擇 k3s? k3s 是由 Rancher 開發的輕量級 Kubernetes 發行版,二進制檔案不到 100MB,卻通過了 CNCF 認證。它非常適合開發環境、邊緣運算以及資源有限的伺服器。

🛠️ 環境準備#

在開始之前,你需要:

  • 一台 Linux 伺服器: 可以是雲端 VPS (如 AWS EC2, GCP, DigitalOcean) 或本地虛擬機。建議至少 2CPU, 4GB RAM。
  • GitHub 帳號: 用於存放程式碼與設定檔。
  • 基本知識: 對 Docker 與 Kubernetes 有基礎了解。

Step 1: 搭建 k3s 輕量級 Kubernetes 叢集#

1. 安裝 k3s#

在你的 Linux 伺服器上執行以下指令:

Terminal window
curl -sfL https://get.k3s.io | sh -

2. 驗證安裝#

安裝完成後,確認節點狀態:

Terminal window
sudo kubectl get nodes

如果看到狀態為 Ready,恭喜你,Kubernetes 叢集已經準備就緒!

3. 設定權限 (可選)#

為了方便操作,可以將 kubeconfig 複製到使用者目錄:

Terminal window
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

Step 2: 安裝與設定 ArgoCD#

ArgoCD 是專為 Kubernetes 設計的宣告式 GitOps 持續交付工具。

1. 建立 Namespace 並安裝#

Terminal window
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

2. 等待 Pod 啟動#

檢查 ArgoCD 的所有組件是否都已順利執行:

Terminal window
kubectl get pods -n argocd

3. 取得初始密碼#

ArgoCD 會自動產生一個初始的 admin 密碼:

Terminal window
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

4. 存取 UI#

由於我們是在伺服器上安裝,可以透過 Port Forwarding 將 UI 導出:

Terminal window
# 在伺服器上執行 (如果你是本機連線)
kubectl port-forward svc/argocd-server -n argocd 8080:443

現在你可以透過瀏覽器訪問 https://<伺服器IP>:8080,帳號為 admin,密碼為上一步取得的字串。

NOTE

遠端存取提示 若你在遠端伺服器操作且無法直接瀏覽 localhost,建議使用 SSH Tunnel: ssh -L 8080:localhost:8080 user@your-server-ip 然後在本地瀏覽器開啟 https://localhost:8080


Step 3: 準備 Python 服務 (Private Service)#

我們要建立一個簡單的 Python Web 服務,並將其設計為僅供內部存取

1. 專案結構#

在你的電腦上建立一個新資料夾,結構如下:

my-python-service/
├── app.py
├── requirements.txt
├── Dockerfile
└── k8s/
├── deployment.yaml
└── service.yaml

2. 應用程式程式碼 (app.py)#

使用 Flask 建立一個簡單的 API:

from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello():
version = os.environ.get('VERSION', 'v1')
return f"Hello from Private Python Service! Version: {version}\n"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

3. 依賴檔 (requirements.txt)#

flask

4. Dockerfile#

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]

5. Kubernetes Manifests (定義私有服務)#

這是關鍵部分。為了確保服務是私有的,我們將 Service Type 設為 ClusterIP (預設值)。

k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: python-private-service
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: python-private
template:
metadata:
labels:
app: python-private
spec:
containers:
- name: app
image: ghcr.io/<YOUR_GITHUB_USER>/python-private-service:latest
ports:
- containerPort: 5000
env:
- name: VERSION
value: "v1"
IMPORTANT

請務必將 <YOUR_GITHUB_USER> 替換為你的 GitHub 使用者名稱。同時,為了讓 ArgoCD 能夠管理版本,我們將在 CI 階段動態更新 image 的 tag。

k8s/service.yaml

apiVersion: v1
kind: Service
metadata:
name: python-private-service
namespace: default
spec:
selector:
app: python-private
ports:
- protocol: TCP
port: 80
targetPort: 5000
type: ClusterIP # 關鍵:ClusterIP 確保不對外公開 IP

Step 4: 處理私有 Registry 權限 (重要)#

如果你的 GitHub Repository 是私有的,或者你的 Container Registry (GHCR) 權限設為私有,Kubernetes 將無法直接拉取 Image。你需要建立一個 imagePullSecret

1. 產生 GitHub PAT#

前往 GitHub Settings > Developer settings > Personal access tokens 產生一個新的 Token (Classic),權限需包含 read:packages

2. 在 k3s 中建立 Secret#

在伺服器上執行:

Terminal window
kubectl create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=<YOUR_GITHUB_USER> \
--docker-password=<YOUR_PAT_TOKEN> \
--docker-email=<YOUR_EMAIL>

3. 修改 Deployment#

k8s/deployment.yaml 中加入 imagePullSecrets

spec:
imagePullSecrets:
- name: ghcr-secret
containers:
...
WARNING

常見錯誤 如果你看到 Pod 狀態為 ImagePullBackOffErrImagePull,通常就是忘記設定這個 Secret,或者是 Token 權限不足。


Step 5: 建立 GitOps 流程 (CI - GitHub Actions)#

我們需要設定 GitHub Actions 來自動建置 Docker Image,並將新的 Image Tag (SHA) 寫回 Git Repo,這樣 ArgoCD 才會知道有新版本。

1. 建立 Workflow 檔案#

在專案根目錄建立 .github/workflows/ci.yaml

name: CI/CD Pipeline
on:
push:
branches: [ "main" ]
paths-ignore:
- 'k8s/**' # 避免修改 k8s yaml 後再次觸發 CI 造成無限迴圈
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: write # 需要寫入權限來更新 manifest
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
- name: Update Kubernetes Manifest
run: |
# 設定 Git 使用者 (用於 commit)
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# 更新 deployment.yaml 中的 image tag
# 這裡使用 sed 來替換 image 欄位
sed -i "s|image: .*|image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}|g" k8s/deployment.yaml
# 提交變更
git add k8s/deployment.yaml
git commit -m "chore: update image tag to ${{ github.sha }}"
git push
CAUTION

權限設定 請確保你的 GitHub Repository 的 Settings > Actions > General > Workflow permissions 已設定為 Read and write permissions,否則 git push 會失敗。


Step 6: 設定 ArgoCD (CD)#

現在回到 ArgoCD UI 來設定自動部署。

1. 建立 Application#

在 ArgoCD 介面上點擊 New App

  • Application Name: python-private-service
  • Project: default
  • Sync Policy: Automatic (勾選 Prune Resources 與 Self Heal)

Source:

  • Repository URL: 輸入你的 GitHub Repo URL
  • Path: k8s

Destination:

  • Cluster URL: https://kubernetes.default.svc
  • Namespace: default

2. 觀察同步#

當你在本地修改程式碼並 push 到 GitHub 後:

  1. GitHub Actions 會自動打包新 Image。
  2. Actions 會修改 k8s/deployment.yaml 的 Image Tag。
  3. ArgoCD 偵測到 Git 變更,自動將新版本同步到 k3s 叢集。

Step 7: 驗證與測試#

因為這是私有服務,我們無法直接透過瀏覽器或 curl 從外部訪問它。我們必須進入叢集內部進行測試。

1. 啟動一個臨時 Pod 來測試#

Terminal window
kubectl run -it --rm debug-pod --image=curlimages/curl --restart=Never -- sh

2. 在叢集內部呼叫服務#

在臨時 Pod 的 Shell 中,嘗試連線到我們的服務:

Terminal window
# 格式為: http://<service-name>.<namespace>
curl http://python-private-service.default

如果看到以下回應,代表成功了!

Hello from Private Python Service! Version: v1

3. 確認外部無法存取#

你可以嘗試在伺服器外部或伺服器本身的 Shell 中執行 curl http://<Service-IP>,應該都是無法連線的。這證實了我們的服務成功隔離在私有網路中。


結語#

恭喜!你已經成功搭建了一套完整的 GitOps 流程。

  • k3s: 提供了輕量穩定的運行環境。
  • Private Service: 透過 ClusterIP 確保了服務的隔離性。
  • GitHub Actions: 自動化了建置與版本更新 (CI)。
  • ArgoCD: 確保了叢集狀態與 Git 保持一致 (CD)。
TIP

進階學習 在真實的生產環境中,你可能需要考慮使用 HelmKustomize 來管理更複雜的環境配置,或者使用 ArgoCD Image Updater 來處理自動更新,以進一步優化流程。

實戰 GitOps:使用 k3s、ArgoCD 與 GitHub Actions 部署私有 Python 服務
https://my-blog-fuwari.pages.dev/posts/gitops-k3s-argocd-python/
作者
Jakiro
發佈於
2025-11-30
許可協議
CC BY-NC-SA 4.0