# 🚀 使用 K3s、GitHub 和 ArgoCD 實現 GitOps 自動化部署 這份文件將引導你設置一個完整的 CI/CD 流程。當你推送程式碼到 GitHub 時,會自動觸發 GitHub Actions 來建置 Docker 映像檔、推送到 GitHub Container Registry (GHCR),並更新 Kubernetes (K3s) 的部署清單。最後,ArgoCD 會偵測到部署清單的變更,並自動將應用程式更新到你的 K3s 叢集中。 --- ## 步驟 1:📦 安裝 K3s K3s 是一個輕量級的 Kubernetes 發行版,非常適合在資源有限的環境中運行。 ```bash # 執行此命令來下載並安裝 K3s curl -sfL https://get.k3s.io | sh - # 為了讓 kubectl 可以存取 K3s 叢集,需要修改設定檔的權限 sudo chmod 644 /etc/rancher/k3s/k3s.yaml ``` > **說明:** > * `curl` 指令會從官方網站下載 K3s 的安裝腳本。 > * `sh -` 會直接執行該腳本來進行安裝。 > * `chmod 644` 讓非 root 用戶也能讀取 K3s 的 kubeconfig 檔案,這樣您才能使用 `kubectl` 指令與叢集互動。 --- ## 步驟 2:⛵️ 安裝 ArgoCD ArgoCD 是一個用於 Kubernetes 的宣告式 GitOps 持續交付工具。 ```bash # 首先,為 ArgoCD 建立一個專屬的命名空間 kubectl create namespace argocd # 接著,從 ArgoCD 的官方 GitHub 儲存庫應用其安裝清單 kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml ``` > **說明:** > * `kubectl create namespace argocd`:在您的 K3s 叢集中建立一個名為 `argocd` 的隔離區,所有 ArgoCD 相關的資源都將部署在這裡。 > * `kubectl apply -f ...`:這個指令會下載 ArgoCD 官方提供的 YAML 清單檔案,並根據該檔案在 `argocd` 命名空間中建立所有必要的資源,例如 Deployments、Services、CRDs 等。 --- ## 步驟 3:🐙 建立應用程式儲存庫 (python-app-repo) 這個私有儲存庫將存放您的應用程式原始碼和 GitHub Actions 工作流程。 1. 在 GitHub 上建立一個**私有 (Private)** 儲存庫,命名為 `python-app-repo`。 2. 在儲存庫中建立以下檔案: * **`app.py` (一個簡單的 Flask 應用)** ```python from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello from k3s, ArgoCD, and GHCR!' if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` * **`Dockerfile` (用於建置應用程式映像)** ```dockerfile FROM python:3.12-slim WORKDIR /app RUN pip install Flask COPY app.py . EXPOSE 5000 CMD ["python", "app.py"] ``` * **`.github/workflows/build-push-update.yml` (GitHub Actions 工作流程)** ```yaml name: Build, Push to GHCR, and Update Manifests on: push: branches: - main # 只在 main 分支 push 時觸發 jobs: build_and_update: runs-on: ubuntu-latest permissions: contents: read packages: write # 允許推送到 GHCR steps: - name: Checkout App Repo uses: actions/checkout@v3 - name: Log in to GHCR uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Get Image Tag id: meta run: echo "TAG=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT - name: Build and Push to GHCR uses: docker/build-push-action@v4 with: context: . push: true tags: ghcr.io/${{ github.repository_owner }}/python-app:${{ steps.meta.outputs.TAG }} - name: Checkout Manifests Repo uses: actions/checkout@v3 with: repository: <GITHUB_USERNAME>/k8s-manifests-repo # 替換成您的部署儲存庫 path: k8s-manifests-repo token: ${{ secrets.DEPLOY_PAT }} # 需要設定 PAT ref: main # 推送指定分支 - name: Update Deployment Image run: | OWNER_LC=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') sed -i "s|image: ghcr.io/${OWNER_LC}/python-app:.*|image: ghcr.io/${OWNER_LC}/python-app:${{ steps.meta.outputs.TAG }}|g" k8s-manifests-repo/deployment.yaml - name: Commit and Push Manifest Changes run: | cd k8s-manifests-repo git config --global user.name 'github-actions[bot]' git config --global user.email 'github-actions[bot]@users.noreply.github.com' git commit -am "Update image to ${{ steps.meta.outputs.TAG }}" || echo "No changes to commit" git push ``` 3. **設定 `DEPLOY_PAT` Secret** > 此工作流程需要一個 Personal Access Token (PAT) 才能推送到另一個儲存庫 (`k8s-manifests-repo`)。 * **產生 PAT**: 1. 前往 GitHub **Settings > Developer settings > Personal access tokens > Tokens (classic)**。 2. 點擊 **"Generate new token" (classic)**。 3. 最重要的:勾選 **`repo`** 權限。這將允許它存取並推送到您的所有儲存庫。 4. 產生 Token 並立即複製它 (離開頁面後將無法再次看到)。 * **在 `python-app-repo` 中儲存 Secret**: 1. 前往 `python-app-repo` 儲存庫。 2. 點擊 **Settings > Secrets and variables > Actions**。 3. 在 "Repository secrets" 區域,點擊 **"New repository secret"**。 4. **Name**: `DEPLOY_PAT` 5. **Value**: 貼上剛剛複製的 PAT (它看起來像 `ghp_...`)。 6. 點擊 **"Add secret"**。 --- ## 步驟 4:📝 建立部署清單儲存庫 (k8s-manifests-repo) 這個公開儲存庫將存放 Kubernetes 部署清單,ArgoCD 會監控此儲存庫的變更。 1. 在 GitHub 上建立一個**公開 (Public)** 儲存庫,命名為 `k8s-manifests-repo`。 2. 在儲存庫中建立以下 YAML 檔案: * **`namespace.yaml`** ```yaml apiVersion: v1 kind: Namespace metadata: name: python-app-ns ``` * **`deployment.yaml`** ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: python-app namespace: python-app-ns spec: replicas: 2 selector: matchLabels: app: python-app template: metadata: labels: app: python-app spec: containers: - name: web # 注意:請將 <GITHUB_USERNAME> 替換成 GitHub 用戶名 (全小寫) image: ghcr.io/<github_username>/python-app:initial-tag ports: - containerPort: 5000 imagePullSecrets: - name: ghcr-creds # 關鍵:k3s 需要這個 Secret 來拉取私有映像 ``` > **注意:** `image` 欄位中的 `initial-tag` 是一個佔位符,當 GitHub Actions 第一次成功運行後,它會被自動更新。 * **`service.yaml`** ```yaml apiVersion: v1 kind: Service metadata: name: python-app-svc namespace: python-app-ns spec: selector: app: python-app ports: - protocol: TCP port: 80 targetPort: 5000 type: NodePort ``` --- ## 步驟 5:🔑 建立用於拉取映像的 PAT K3s 需要一個 Token 才能從私有的 GitHub Container Registry (GHCR) 拉取 Docker 映像。 1. 前往 GitHub **Settings > Developer settings > Personal access tokens > Tokens (classic)**。 2. 點擊 **"Generate new token" (classic)**。 3. 勾選 **`read:packages`** 權限。 4. 點擊 **"Generate token"** 並複製它。 --- ## 步驟 6:🔒 在 K3s 中建立映像拉取 Secret 將上一步產生的 Token 提供給 K3s,讓它可以通過身份驗證。 在 Linux 主機上執行以下指令: ```bash kubectl create secret docker-registry ghcr-creds \ --namespace=python-app-ns \ --docker-server=ghcr.io \ --docker-username=<GITHUB_USERNAME> \ --docker-password=<步驟5產生的TOKEN> ``` > **說明:** > * `ghcr-creds`:這是 Secret 的名稱,必須與 `deployment.yaml` 中的 `imagePullSecrets` 名稱一致。 > * `--namespace=python-app-ns`:確保這個 Secret 建立在您的應用程式所在的命名空間中。 > * `--docker-username`:您的 GitHub 用戶名。 > * `--docker-password`:貼上您在步驟 5 中產生的 `read:packages` Token。 --- ## 步驟 7:🤖 建立 ArgoCD 應用程式 現在,我們需要告訴 ArgoCD 要監控哪個 Git 儲存庫以及要將它部署到哪裡。 1. 在 Linux 主機上,執行以下指令來建立 `argocd-app.yaml` 檔案。 > **注意:** 請記得將 **`<GITHUB_USERNAME>`** 替換成您自己的 GitHub 用戶名。 ```yaml # argocd-app.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: # 1. 應用程式的名稱 name: python-app # 2. ArgoCD Application CRD 必須建立在 ArgoCD 所在的命名空間 namespace: argocd spec: # 3. ArgoCD 專案,使用預設的 'default' 即可 project: default # 4. 來源 (Source) - 您的 Git 儲存庫 source: # 5. 替換成您的 "公開" k8s-manifests-repo URL repoURL: https://github.com/**`<GITHUB_USERNAME>`**/k8s-manifests-repo.git # 6. 要監控的 Git 分支 targetRevision: main # 7. YAML 檔案所在的儲存庫路徑 ( '.' 代表根目錄) path: . # 8. 目的地 (Destination) - 您的 k3s 叢集 destination: # 9. 'https://kubernetes.default.svc' 是 ArgoCD 內部的 API 伺服器地址 server: https://kubernetes.default.svc # 10. 您希望將應用程式部署到 k3s 上的哪個命名空間 # 這必須與 k8s-manifests-repo/deployment.yaml 中的 namespace 一致 namespace: python-app-ns # 11. 同步策略 (Sync Policy) syncPolicy: # 12. 啟用自動同步 automated: # (推薦) 當 Git 中的資源被刪除時,也自動從 k3s 中刪除 prune: true # (推薦) 自動修復叢集狀態與 Git 狀態的偏差 selfHeal: true # (可選) 確保 ArgoCD 在部署前建立 'python-app-ns' 命名空間 syncOptions: - CreateNamespace=true ``` --- ## 步驟 8:✅ 應用 ArgoCD 應用程式清單 執行此指令後,ArgoCD 將開始同步到 `k8s-manifests-repo` 儲存庫。 ```bash kubectl apply -f argocd-app.yaml ``` --- ## 步驟 9:🔍 驗證部署 現在,您可以檢查應用程式的狀態。 ```bash # 查看 Pod 的啟動狀態,確認它們是否為 "Running" kubectl get pods -n python-app-ns # 查看 Service 的 Port,找到 NodePort 對應的外部端口 # 例如:80:31234/TCP,其中 31234 就是外部端口 kubectl get service python-app-svc -n python-app-ns # 查看節點 (Node) 的外部 IP kubectl get nodes -o wide ``` > **如何存取應用程式?** > > 在瀏覽器中輸入 `http://<節點的外部IP>:<NodePort端口>` 即可看到 "Hello from k3s, ArgoCD, and GHCR!" 的訊息。