Files
life-echo/.github/workflows/docker-build-deploy.yml
Workflow config file is invalid. Please check your config file: yaml: line 64: did not find expected key
iammm0 084075dcdb ci: 新增GitHub Actions CI/CD配置
- 新增.github/工作流配置
2026-01-26 11:54:20 +08:00

186 lines
6.4 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Docker Build and Deploy
on:
push:
branches:
- main
- master
- develop
paths:
- 'api/**'
- '.github/workflows/**'
workflow_dispatch: # 允许手动触发
env:
IMAGE_NAME: lifecho-api
REGISTRY: crpi-u2903xccyzd6nqnc.cn-shanghai.personal.cr.aliyuncs.com
REGISTRY_NAMESPACE: huaga
jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Alibaba Cloud Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.ALIYUN_CR_USERNAME }}
password: ${{ secrets.ALIYUN_CR_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./api
file: ./api/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy to Remote Server
runs-on: ubuntu-latest
needs: build-and-push
if: github.event_name != 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H -p ${{ secrets.SSH_PORT || 22 }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Determine image tag
id: image_tag
run: |
if [ "${{ github.ref_name }}" == "main" ] || [ "${{ github.ref_name }}" == "master" ]; then
echo "tag=latest" >> $GITHUB_OUTPUT
else
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi
- name: Deploy to remote server
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
IMAGE_TAG: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ steps.image_tag.outputs.tag }}
COMPOSE_FILE: docker-compose.yml
COMPOSE_DIR: ${{ secrets.DEPLOY_PATH || '/opt/life-echo' }}
REGISTRY: ${{ env.REGISTRY }}
ALIYUN_CR_USERNAME: ${{ secrets.ALIYUN_CR_USERNAME }}
ALIYUN_CR_PASSWORD: ${{ secrets.ALIYUN_CR_PASSWORD }}
run: |
echo "开始部署到远程服务器..."
echo "镜像标签: $IMAGE_TAG"
echo "部署目录: $COMPOSE_DIR/api"
# 登录到阿里云容器仓库
echo "$ALIYUN_CR_PASSWORD" | ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"docker login --username=$ALIYUN_CR_USERNAME --password-stdin $REGISTRY"
# 创建部署目录(如果不存在)
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"mkdir -p $COMPOSE_DIR/api"
# 复制 docker-compose.yml 到远程服务器
scp -P $SSH_PORT ./api/$COMPOSE_FILE $SSH_USER@$SSH_HOST:$COMPOSE_DIR/api/
# 在远程服务器上执行部署操作
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST bash -s << EOF
set -e
export COMPOSE_DIR="$COMPOSE_DIR"
export COMPOSE_FILE="$COMPOSE_FILE"
export IMAGE_TAG="$IMAGE_TAG"
cd \$COMPOSE_DIR/api
echo "拉取最新镜像: \$IMAGE_TAG"
docker pull "\$IMAGE_TAG" || true
echo "停止现有容器..."
docker-compose -f "\$COMPOSE_FILE" down || true
echo "更新 docker-compose.yml 中的镜像标签..."
# 使用 sed 更新镜像标签(简单可靠)
# 备份原文件
cp "\$COMPOSE_FILE" "\${COMPOSE_FILE}.bak"
# 更新所有包含 lifecho-api 或 life-echo-api 的 image 行
sed -i.tmp "s|image:.*lifecho-api.*|image: \$IMAGE_TAG|g" "\$COMPOSE_FILE"
sed -i.tmp "s|image:.*life-echo-api.*|image: \$IMAGE_TAG|g" "\$COMPOSE_FILE"
# 如果服务使用 build 而不是 image添加 image 行
# 在 api 服务中,如果只有 build 没有 image添加 image
if ! grep -q "image:" "\$COMPOSE_FILE" || grep -q "build:" "\$COMPOSE_FILE"; then
# 在 api 服务的 build 行后添加 image
sed -i.tmp '/^ api:/,/^ container_name:/ {
/build:/a\
image: '\$IMAGE_TAG'
}' "\$COMPOSE_FILE"
# 在 celery-worker 服务的 build 行后添加 image
sed -i.tmp '/^ celery-worker:/,/^ container_name:/ {
/build:/a\
image: '\$IMAGE_TAG'
}' "\$COMPOSE_FILE"
fi
echo "启动新容器..."
docker-compose -f "\$COMPOSE_FILE" pull || true
docker-compose -f "\$COMPOSE_FILE" up -d
echo "等待容器启动..."
sleep 10
echo "清理旧镜像..."
docker image prune -f || true
echo "部署完成!"
echo "检查容器状态..."
docker-compose -f "\$COMPOSE_FILE" ps
EOF
- name: Verify deployment
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
COMPOSE_DIR: ${{ secrets.DEPLOY_PATH || '/opt/life-echo' }}
run: |
echo "验证部署状态..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"cd $COMPOSE_DIR/api && docker-compose ps && docker-compose logs --tail=50 api"