IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series: Lập trình Raspberry Pi – Bài 22: OTA “nhẹ” cho Raspberry Pi app — Git pull + version + rollback nhanh (production-friendly)

Series: Lập trình Raspberry Pi & Ứng dụng thực tế Phần 3 — Python “build app thật” Bài 22: OTA “nhẹ” cho Raspberry Pi app — Git pull + version + rollback nhanh (production-friendly)


1) Mục tiêu bài học

Sau bài này bạn sẽ:

  • Deploy cập nhật app trên Pi theo kiểu OTA nhẹ (không cần container).
  • Cập nhật bằng git pull + restart service.
  • Có endpoint /version để kiểm tra version đang chạy.
  • Có cơ chế rollback nhanh nếu update lỗi.
  • An toàn hơn: chỉ cho phép update từ LAN + có token.

Đây là kiểu OTA rất hợp cho “Pi gateway/app” khi bạn vận hành vài chục/ vài trăm Pi.

2) Quy ước version

Trong .env (hoặc systemd EnvironmentFile) thêm:

APP_VERSION=1.0.0
APP_GIT_SHA=dev

Bạn sẽ update APP_GIT_SHA tự động sau mỗi deploy.

3) Thêm endpoint /version (FastAPI)

Mở src/api.py, thêm:

import os
from fastapi import Header, HTTPException

Thêm endpoint:

@app.get("/version")
def version():
    return {
        "app": os.getenv("APP_NAME", "iotlabs-py-agent"),
        "version": os.getenv("APP_VERSION", "unknown"),
        "git_sha": os.getenv("APP_GIT_SHA", "unknown"),
    }

Test:

curl -s http://127.0.0.1:8000/version

4) Tạo script deploy (OTA nhẹ)

Tạo file scripts/deploy.sh:

cd ~/apps/iotlabs-py-agent
nano scripts/deploy.sh

Dán:

#!/usr/bin/env bash
set -euo pipefail

APP_DIR="/home/developer/apps/iotlabs-py-agent"
SERVICE_NAME="iotlabs-api"

cd "$APP_DIR"

echo "[1/6] Backup current revision"
TS="$(date +%Y%m%d-%H%M%S)"
mkdir -p backups
git rev-parse HEAD > "backups/rev_$TS.txt"

echo "[2/6] Fetch & reset to origin/main"
git fetch --all
git reset --hard origin/main

echo "[3/6] Update venv deps (if requirements changed)"
# Nếu bạn dùng requirements.txt:
if [ -f requirements.txt ]; then
  "$APP_DIR/.venv/bin/pip" install -r requirements.txt
fi

echo "[4/6] Write git sha to .env (APP_GIT_SHA)"
SHA="$(git rev-parse --short HEAD)"
if grep -q "^APP_GIT_SHA=" .env; then
  sed -i "s/^APP_GIT_SHA=.*/APP_GIT_SHA=$SHA/" .env
else
  echo "APP_GIT_SHA=$SHA" >> .env
fi

echo "[5/6] Restart service"
sudo systemctl restart "$SERVICE_NAME"

echo "[6/6] Health check"
sleep 1
curl -fsS "http://127.0.0.1:8000/health" >/dev/null
echo "OK deployed sha=$SHA"

Cho phép chạy:

chmod +x scripts/deploy.sh

Chạy thử:

./scripts/deploy.sh

5) Rollback nhanh (khi update lỗi)

Tạo scripts/rollback.sh:

nano scripts/rollback.sh

Dán:

#!/usr/bin/env bash
set -euo pipefail

APP_DIR="/home/developer/apps/iotlabs-py-agent"
SERVICE_NAME="iotlabs-api"

cd "$APP_DIR"

echo "Available backups:"
ls -1 backups | tail -n 10

echo -n "Enter backup file name (e.g., rev_20260218-210001.txt): "
read -r f

REV="$(cat "backups/$f")"
echo "Rollback to $REV"

git reset --hard "$REV"

SHA="$(git rev-parse --short HEAD)"
if grep -q "^APP_GIT_SHA=" .env; then
  sed -i "s/^APP_GIT_SHA=.*/APP_GIT_SHA=$SHA/" .env
else
  echo "APP_GIT_SHA=$SHA" >> .env
fi

sudo systemctl restart "$SERVICE_NAME"
sleep 1
curl -fsS "http://127.0.0.1:8000/health" >/dev/null
echo "OK rollback sha=$SHA"

Cho phép chạy:

chmod +x scripts/rollback.sh

6) Tạo “OTA API” (tuỳ chọn) — gọi update từ xa

Bạn có thể tạo endpoint /admin/deploy để trigger script deploy.sh.

⚠️ Lưu ý an toàn:

  • Chỉ mở trong LAN
  • Bắt buộc token
  • Chạy dưới quyền hạn chế (không khuyến khích chạy sudo trực tiếp từ API)

Cách an toàn hơn (khuyến nghị)

  • Không gọi deploy từ API
  • Thay vào đó: deploy bằng SSH hoặc CI runner nội bộ.

Nếu vẫn muốn endpoint, bạn có thể làm “request → ghi flag file → scheduler job chạy deploy” (tránh chạy lệnh nguy hiểm trong HTTP handler). Bài sau mình sẽ làm kiểu đó.

7) Gợi ý: systemd EnvironmentFile

Trong /etc/systemd/system/iotlabs-api.service thêm:

EnvironmentFile=/home/developer/apps/iotlabs-py-agent/.env

Sau khi sửa:

sudo systemctl daemon-reload
sudo systemctl restart iotlabs-api

8) Checklist vận hành OTA

  • /version trả đúng sha ✅
  • Deploy xong chạy health check ✅
  • Có backup revision để rollback ✅
  • Update dependency có kiểm soát (requirements.txt) ✅
  • Chỉ deploy từ người/CI tin cậy ✅