update
This commit is contained in:
@@ -0,0 +1,155 @@
|
|||||||
|
name: 'Reusable Docker Image Build'
|
||||||
|
description: '通用的 Docker 镜像构建 / 验证 / 清理逻辑,用于在各仓库中复用'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
dockerfile:
|
||||||
|
description: 'Dockerfile 路径(相对于仓库根目录)'
|
||||||
|
required: true
|
||||||
|
context:
|
||||||
|
description: '构建上下文路径(相对于仓库根目录)'
|
||||||
|
required: false
|
||||||
|
default: '.'
|
||||||
|
image_name:
|
||||||
|
description: 'Docker 镜像名称(不含标签)'
|
||||||
|
required: true
|
||||||
|
image_tag:
|
||||||
|
description: 'Docker 镜像标签/版本'
|
||||||
|
required: true
|
||||||
|
enable_cache:
|
||||||
|
description: '是否启用 Docker 构建缓存'
|
||||||
|
required: false
|
||||||
|
default: 'true'
|
||||||
|
build_args:
|
||||||
|
description: 'Docker 构建参数(每行一个,格式: KEY=VALUE)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Cache Docker layers
|
||||||
|
if: ${{ inputs.enable_cache == 'true' }}
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ inputs.image_name }}-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-${{ inputs.image_name }}-
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
|
||||||
|
- name: Prepare build arguments
|
||||||
|
id: prepare
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 准备构建参数 ======"
|
||||||
|
|
||||||
|
DOCKERFILE="${{ inputs.dockerfile }}"
|
||||||
|
CONTEXT="${{ inputs.context }}"
|
||||||
|
IMAGE_NAME="${{ inputs.image_name }}"
|
||||||
|
IMAGE_TAG="${{ inputs.image_tag }}"
|
||||||
|
FULL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||||
|
|
||||||
|
echo "Dockerfile: $DOCKERFILE"
|
||||||
|
echo "Context: $CONTEXT"
|
||||||
|
echo "Image: $FULL_IMAGE"
|
||||||
|
|
||||||
|
# 验证 Dockerfile 是否存在
|
||||||
|
if [ ! -f "$DOCKERFILE" ]; then
|
||||||
|
echo "✗ Dockerfile 不存在: $DOCKERFILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 验证构建上下文目录是否存在
|
||||||
|
if [ ! -d "$CONTEXT" ]; then
|
||||||
|
echo "✗ 构建上下文目录不存在: $CONTEXT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ 构建参数验证通过"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 设置输出变量
|
||||||
|
echo "full_image=$FULL_IMAGE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# 处理构建参数
|
||||||
|
BUILD_ARGS=""
|
||||||
|
if [ -n "${{ inputs.build_args }}" ]; then
|
||||||
|
echo "====== 构建参数 ======"
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [ -n "$line" ]; then
|
||||||
|
echo " $line"
|
||||||
|
BUILD_ARGS="$BUILD_ARGS --build-arg $line"
|
||||||
|
fi
|
||||||
|
done <<< "${{ inputs.build_args }}"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "build_args=$BUILD_ARGS" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 开始构建 Docker 镜像 ======"
|
||||||
|
echo "构建时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
echo "分支: ${{ github.ref_name }}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "====== 构建配置 ======"
|
||||||
|
echo "镜像: ${{ steps.prepare.outputs.full_image }}"
|
||||||
|
echo "Dockerfile: ${{ inputs.dockerfile }}"
|
||||||
|
echo "Context: ${{ inputs.context }}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 构建命令
|
||||||
|
BUILD_CMD="docker build \
|
||||||
|
-t ${{ steps.prepare.outputs.full_image }} \
|
||||||
|
-f ${{ inputs.dockerfile }} \
|
||||||
|
${{ steps.prepare.outputs.build_args }} \
|
||||||
|
${{ inputs.context }}"
|
||||||
|
|
||||||
|
echo "执行命令:"
|
||||||
|
echo "$BUILD_CMD"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 执行构建
|
||||||
|
eval $BUILD_CMD
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "====== 镜像构建完成 ======"
|
||||||
|
|
||||||
|
- name: Verify image
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 验证构建的镜像 ======"
|
||||||
|
|
||||||
|
IMAGE="${{ steps.prepare.outputs.full_image }}"
|
||||||
|
|
||||||
|
if docker image inspect "${IMAGE}" >/dev/null 2>&1; then
|
||||||
|
SIZE=$(docker image inspect "${IMAGE}" --format='{{.Size}}' | awk '{printf "%.2f", $1/1024/1024}')
|
||||||
|
CREATED=$(docker image inspect "${IMAGE}" --format='{{.Created}}')
|
||||||
|
ID=$(docker image inspect "${IMAGE}" --format='{{.Id}}' | cut -d':' -f2 | cut -c1-12)
|
||||||
|
|
||||||
|
echo "✓ ${IMAGE}"
|
||||||
|
echo " 镜像 ID: ${ID}"
|
||||||
|
echo " 大小: ${SIZE} MB"
|
||||||
|
echo " 创建时间: ${CREATED}"
|
||||||
|
else
|
||||||
|
echo "✗ ${IMAGE} 验证失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ 镜像验证成功"
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 清理悬空镜像 ======"
|
||||||
|
docker image prune -f
|
||||||
|
echo "✓ 清理完成"
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
name: 'Reusable Docker Compose Deploy'
|
||||||
|
description: '通用的 Docker Compose 部署逻辑,用于在各仓库中复用'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
compose_file:
|
||||||
|
description: 'Docker Compose 文件路径(相对于仓库根目录)'
|
||||||
|
required: true
|
||||||
|
compose_dir:
|
||||||
|
description: 'Docker Compose 工作目录(相对于仓库根目录,默认使用 compose_file 所在目录)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
checkout_ref:
|
||||||
|
description: '要检出的分支或标签'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
enable_sparse_checkout:
|
||||||
|
description: '是否启用稀疏检出'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
sparse_checkout:
|
||||||
|
description: '稀疏检出路径列表(每行一个路径)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
startup_wait:
|
||||||
|
description: '服务启动后等待时间(秒)'
|
||||||
|
required: false
|
||||||
|
default: '0'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.checkout_ref || github.ref }}
|
||||||
|
sparse-checkout: ${{ inputs.enable_sparse_checkout == 'true' && inputs.sparse_checkout || '' }}
|
||||||
|
sparse-checkout-cone-mode: false
|
||||||
|
fetch-depth: ${{ inputs.enable_sparse_checkout == 'true' && 1 || 0 }}
|
||||||
|
|
||||||
|
- name: Prepare compose paths
|
||||||
|
id: prepare
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
COMPOSE_FILE="${{ inputs.compose_file }}"
|
||||||
|
COMPOSE_DIR_INPUT="${{ inputs.compose_dir }}"
|
||||||
|
|
||||||
|
if [ -z "$COMPOSE_DIR_INPUT" ]; then
|
||||||
|
DIR="$(dirname "$COMPOSE_FILE")"
|
||||||
|
if [ "$DIR" = "." ]; then
|
||||||
|
DIR="."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
DIR="$COMPOSE_DIR_INPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "compose_file=$COMPOSE_FILE" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "compose_dir=$DIR" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
echo "Compose file: $COMPOSE_FILE"
|
||||||
|
echo "Compose dir : $DIR"
|
||||||
|
|
||||||
|
- name: Stop old services
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 停止旧服务 ======"
|
||||||
|
|
||||||
|
cd "${{ steps.prepare.outputs.compose_dir }}"
|
||||||
|
|
||||||
|
# 停止并移除容器
|
||||||
|
docker compose -f "${{ steps.prepare.outputs.compose_file }}" down || true
|
||||||
|
|
||||||
|
echo "✓ 旧服务已停止"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
- name: Deploy services
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 部署服务 ======"
|
||||||
|
|
||||||
|
cd "${{ steps.prepare.outputs.compose_dir }}"
|
||||||
|
|
||||||
|
echo "启动服务..."
|
||||||
|
docker compose -f "${{ steps.prepare.outputs.compose_file }}" up -d
|
||||||
|
|
||||||
|
echo "✓ 服务已启动"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
- name: Wait for services
|
||||||
|
if: ${{ inputs.startup_wait != '0' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 等待服务初始化 ======"
|
||||||
|
echo "等待时间: ${{ inputs.startup_wait }} 秒"
|
||||||
|
sleep ${{ inputs.startup_wait }}
|
||||||
|
echo "✓ 等待完成"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
- name: Verify services
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "====== 验证服务状态 ======"
|
||||||
|
|
||||||
|
cd "${{ steps.prepare.outputs.compose_dir }}"
|
||||||
|
|
||||||
|
docker compose -f "${{ steps.prepare.outputs.compose_file }}" ps
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查是否有失败的服务
|
||||||
|
FAILED_SERVICES=$(docker compose -f "${{ steps.prepare.outputs.compose_file }}" ps --status exited --format json | jq -r '.Service' 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$FAILED_SERVICES" ]; then
|
||||||
|
echo "⚠ 以下服务启动失败:"
|
||||||
|
echo "$FAILED_SERVICES"
|
||||||
|
echo ""
|
||||||
|
echo "查看失败服务的日志:"
|
||||||
|
for service in $FAILED_SERVICES; do
|
||||||
|
echo ""
|
||||||
|
echo "=== $service 日志 ==="
|
||||||
|
docker compose -f "${{ steps.prepare.outputs.compose_file }}" logs --tail=50 "$service"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "✓ 所有服务运行正常"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user