輕量級 CI/CD 實戰(四):本地開發釘釘告警 → 自動部署 Kafka 消費者容器

目標:在不破壞現有邏輯的前提下,新增「釘釘告警」功能,並通過 CI/CD 自動部署到阿里雲,替換正在運行的容器。
關鍵詞:Git Hooks、Docker、Kafka 消費者、釘釘機器人、自動化部署
適用場景:自建 CI/CD 流水線|日誌監控系統升級|Python 應用容器化
環境:CentOS 7 + Git bare repo + Docker 24.x + Python 3.9


目錄

  • 一、實驗目標
  • 二、當前環境回顧
  • 三、整體流程概覽
  • 四、本地開發準備
  • 4.1 修改消費者邏輯
  • 4.2 確保項目可容器化
  • 五、CI/CD 腳本改造
  • 5.1 更新 post-receive 鈎子
  • 5.2 敏感信息管理
  • 六、觸發自動部署
  • 七、部署結果驗證
  • 7.1 查看部署日誌
  • 7.2 檢查容器狀態
  • 7.3 驗證釘釘告警
  • 八、常見問題排查
  • 九、總結


一、實驗目標

本次實驗旨在實現以下目標:

  1. 在本地開發機修改 Kafka 消費者代碼,新增釘釘告警功能
  2. 將消費者應用容器化打包,確保可獨立運行;
  3. 利用已有的 Git Hooks CI/CD 流程,實現 git push 後自動部署到阿里雲服務器;
  4. 自動替換正在運行的 log-consumer 容器,無需手動干預;
  5. 驗證新容器能正常消費 Kafka 消息並觸發釘釘告警。

整個過程完全複用你此前搭建的輕量級 CI/CD 架構,不引入任何外部平台。



二、當前環境回顧

根據你在阿里雲服務器的實際配置,當前環境如下:

  • 裸倉庫路徑/var/repo/log-consumer.git
  • 工作目錄/opt/log_consumer
  • 正在運行的容器:名為 log-consumer 的 Docker 容器(通過 docker run 啓動)
  • 本地開發路徑/log_consumer/project/consumer.py
  • CI/CD 觸發方式git push origin main → 觸發 post-receive 鈎子

此前的 post-receive 腳本使用 systemctl restart consumer,但該服務已棄用,當前容器由手動 docker run 啓動。



三、整體流程概覽

本次升級後的 CI/CD 流程如下:

  1. 開發者在本地修改 consumer.py,加入釘釘告警邏輯;
  2. 提交併推送代碼:git push origin main
  3. 阿里雲服務器的 /var/repo/log-consumer.git 接收推送;
  4. post-receive 鈎子自動執行:
  • 檢出最新代碼到 /opt/log_consumer
  • 構建新的 Docker 鏡像
  • 停止並刪除舊的 log-consumer 容器
  • 啓動新的容器(注入釘釘 token 等環境變量)
  1. 新容器立即生效,具備釘釘告警能力。

整個過程全自動,開發者只需關注業務代碼



四、本地開發準備

4.1 修改消費者邏輯

在本地 /log_consumer/project/consumer.py 中,我們需要新增一個異步發送釘釘消息的函數,並在異常檢測邏輯處調用它。

核心要求:

  • 使用 threading.Thread 異步發送,避免阻塞 Kafka 消費主循環;
  • 從環境變量讀取 DINGTALK_TOKEN,不硬編碼;
  • 增加重試和超時保護,防止網絡問題拖慢程序。

需修改的代碼部分:

  • 功能:異步發送文本消息到釘釘機器人
  • 依賴:
    os.getenv(“DINGTALK_TOKEN”):從環境變量獲取 Token
    requests:發送 HTTP 請求
    threading:實現異步非阻塞

通過異步方式調用釘釘機器人 API,避免了因網絡延遲導致消費者卡頓,保證了日誌處理的實時性與穩定性。

注意:需確保 DINGTALK_TOKEN 已正確注入容器環境變量

def send_dingtalk_async(msg):
    """異步發送釘釘告警(從環境變量 DINGTALK_TOKEN 讀取)"""
    token = os.getenv("DINGTALK_TOKEN")
    if not token:
        print("[WARN] DINGTALK_TOKEN 未設置,跳過釘釘告警")
        return

    def send():
        try:
            webhook = f"https://oapi.dingtalk.com/robot/send?access_token={token}"
            payload = {
                "msgtype": "text",
                "text": {
                    "content": msg.strip()
                },
                "at": {
                    "isAtAll": False
                }
            }
            resp = requests.post(webhook, json=payload, timeout=5)
            if resp.status_code == 200 and resp.json().get("errcode") == 0:
                print("[DINGTALK] 告警發送成功")
            else:
                print(f"[DINGTALK] 發送失敗: {resp.text}")
        except Exception as e:
            print(f"[DINGTALK] 異常: {e}")

    thread = threading.Thread(target=send)
    thread.daemon = True
    thread.start()

4.2 確保項目可容器化

項目根目錄必須包含以下文件:

  • Dockerfile:定義鏡像構建步驟
  • requirements.txt:聲明 Python 依賴(需包含 requests

若尚未創建,請在本地 /log_consumer/project/ 下添加這兩個文件。

分佈式消息系統之Kafka_#ci/cd



五、CI/CD 腳本改造


5.1 更新 post-receive 鈎子

編輯服務器上的鈎子腳本:

/var/repo/log-consumer.git/hooks/post-receive

將其內容替換為支持 Docker 容器自動更新的版本。關鍵步驟包括:

  • git checkout 到 /opt/log_consumer
  • docker build 構建帶時間戳的新鏡像
  • docker stop && docker rm 停止舊容器
  • docker run 啓動新容器,並通過 -e 注入環境變量

注意:不再調用 systemctl,完全由 Docker 管理進程生命週期。

#!/bin/bash
set -e

DEPLOY_PATH="/opt/log_consumer"
IMAGE_NAME="log-consumer-app"
CONTAINER_NAME="log-consumer"

# 1. 拉取最新代碼
GIT_WORK_TREE="$DEPLOY_PATH" git --git-dir=/var/repo/log-consumer.git checkout -f

# 2. 進入項目目錄構建鏡像
cd "$DEPLOY_PATH"
docker build -t "$IMAGE_NAME:latest" .

# 3. 停止並刪除舊容器
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true

# 4. 啓動新容器(使用 host 網絡,直接訪問宿主機的 Kafka)
docker run -d \
  --name "$CONTAINER_NAME" \
  --net host \
  --restart unless-stopped \
  -e DINGTALK_TOKEN="$(cat /opt/secrets/dingtalk.token)" \
  "$IMAGE_NAME:latest"

echo "$(date '+%Y-%m-%d %H:%M:%S'): ✅ Dockerized deploy completed (host network)" >> /var/log/log-consumer-deploy.log


5.2 敏感信息管理

釘釘機器人的 access_token 屬於敏感信息,不可寫入代碼或 Git 倉庫

我們將其存放在服務器安全目錄:

/opt/secrets/dingtalk.token

權限設置為 600,僅 root 或 git 用户可讀。

分佈式消息系統之Kafka_#釘釘_02

在 docker run 命令中通過 $(cat /opt/secrets/dingtalk.token) 動態注入。



六、觸發自動部署

在本地完成代碼修改和文件準備後,執行標準 Git 操作:

cd /log_consumer/project/
git add .
git commit -m "feat: add dingtalk alert"
git push origin main

推送完成後,無需登錄服務器,CI/CD 流程將自動完成部署。



七、部署結果驗證


7.1 查看部署日誌

部署過程會被記錄到:

/var/log/log-consumer-deploy.log

成功時應包含類似日誌:

2025-11-24 21:45:12: ✅ Deployed and restarted Docker container

分佈式消息系統之Kafka_#docker_03


7.2 檢查容器狀態

執行以下命令確認新容器已運行:

docker ps --filter "name=log-consumer" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"

應看到 log-consumer 容器狀態為 Up,且鏡像標籤為時間戳。

7.3 驗證釘釘告警

模擬一條異常日誌(如構造非法 IP 訪問),觀察是否收到釘釘消息。

分佈式消息系統之Kafka_#docker_04

若未收到,請檢查:

  • 容器內是否設置了 DINGTALK_TOKEN
  • 釘釘機器人是否開啓“加簽”或 IP 白名單
  • 服務器能否訪問外網(curl https://oapi.dingtalk.com)


八、常見問題排查

  • 問題1:docker build 失敗

→ 檢查 Dockerfile 和 requirements.txt 是否已推送到服務器(查看 /opt/log_consumer/)

  • 問題2:容器啓動後立即退出

→ 執行 docker logs log-consumer 查看 Python 異常

  • 問題3:釘釘收不到消息

→ 在容器內執行 print(os.getenv(“DINGTALK_TOKEN”)) 確認環境變量注入成功

  • 問題4:post-receive 無反應

→ 檢查腳本是否有執行權限:chmod +x post-receive



九、總結

本次實驗成功將釘釘告警功能集成到 Kafka 消費者中,並通過純 Git Hooks + Docker 實現全自動部署。關鍵成果包括:

  • 本地開發與服務器部署完全解耦
  • 容器自動更新,無需手動停啓
  • 敏感信息安全隔離
  • 延續了“輕量、透明、自主”的 CI/CD 哲學