This commit is contained in:
2026-10-21 12:21:45 +08:00
commit ffc4152fe6
5 changed files with 288 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
# magic-docker
一个 action 搞定 Docker 镜像的构建与推送,支持:
- `context`:指定构建目录(前端/后端在子目录时用)
- `dockerfile`:指定 Dockerfile 的完整路径
- `preset`:内置方案,对应 action 根目录下的 `vue3.Dockerfile`、`vue3-hash.Dockerfile`、`dotnet.Dockerfile`
优先级:**`dockerfile` > `preset` > `context` 下的默认 `Dockerfile`**。
设置了 `dockerfile` 时完全忽略 `preset`;设置了 `preset` 时用对应的 Dockerfile 构建,构建完自动 push 到 registry。
## 内置 preset
| preset | 对应 Dockerfile | 说明 |
| --- | --- | --- |
| `vue3` | `vue3.Dockerfile` | Vue3 + history 路由,nginx 做 `try_files` 回退并带跨域头 |
| `vue3-hash` | `vue3-hash.Dockerfile` | Vue3 + hash 路由,nginx 默认配置 |
| `dotnet` | `dotnet.Dockerfile` | .NET self-contained 发布(linux-x64) |
- 编译全部写在 Dockerfile 里(多阶段构建),action 本身只负责传 `--build-arg VERSION=<tag>`:
- vue:`npm ci` → `npm run build-only`(没有该脚本时回退 `npm run build`)→ `npm pkg set version=<tag>`
- dotnet:`dotnet publish -r linux-x64 -c Release --self-contained -p:AssemblyName=App -p:Version=<tag>`
- `vue3` 的 nginx 配置也内联在 Dockerfile 里:`context` 下有 `nginx.conf` 就用项目的,否则用内置默认配置(history 回退 + 跨域头)。
## 参数
| 参数 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `registry` | 是 | `${{ vars.DOCKER_REGISTRY }}` | Docker registry 地址 |
| `user` | 是 | `${{ vars.DOCKER_USER }}` | registry 用户名 |
| `pass` | 是 | `${{ vars.DOCKER_PASS }}` | registry 密码 |
| `image` | 是 | `${{ github.repository }}` | 镜像名 |
| `tag` | 否 | `${{ github.ref_name }}` | 镜像 tag |
| `platform` | 否 | `linux/amd64` | 构建平台 |
| `context` | 否 | `.` | 构建目录,相对仓库根目录 |
| `dockerfile` | 否 | 空 | Dockerfile 完整路径(相对仓库根目录或绝对路径) |
| `preset` | 否 | 空 | 内置方案:`vue3` / `vue3-hash` / `dotnet` |
| `proxy` | 否 | 空 | 构建时使用的 HTTP(S) 代理 |
| `no_proxy` | 否 | 见 action.yml | 不使用代理的地址 |
## 示例
### 使用 preset
```yaml
- uses: actions/magic-docker@main
with:
context: vue
preset: vue3
```
```yaml
- uses: actions/magic-docker@main
with:
context: vue
preset: vue3-hash
```
```yaml
- uses: actions/magic-docker@main
with:
context: backend
preset: dotnet
```
### 使用自己的 Dockerfile
指定 `dockerfile` 后 `preset` 会被忽略:
```yaml
- uses: actions/magic-docker@main
with:
context: backend
dockerfile: backend/Dockerfile
platform: linux/arm64
```
### 只给 context(默认用 context/Dockerfile)
```yaml
- uses: actions/magic-docker@main
with:
context: .
```
### 指定镜像名与 tag
```yaml
- uses: actions/magic-docker@main
with:
context: vue
preset: vue3
image: simcu/web
tag: ${{ github.ref_name }}
```
+104
View File
@@ -0,0 +1,104 @@
# action.yml
name: "magic docker build and push"
description: "一键构建并推送 Docker 镜像:支持自定义 context / dockerfile,或使用内置 preset(vue3、vue3-hash、dotnet)"
inputs:
registry:
description: "Docker registry URL"
required: true
default: "${{ vars.DOCKER_REGISTRY }}"
user:
description: "Docker registry username"
required: true
default: "${{ vars.DOCKER_USER }}"
pass:
description: "Docker registry password"
required: true
default: "${{ vars.DOCKER_PASS }}"
image:
description: "Docker image name"
required: true
default: "${{ github.repository }}"
tag:
description: "Docker image tag (default: github.ref_name)"
required: false
default: "${{ github.ref_name }}"
platform:
description: "Build platform (default: linux/amd64)"
required: false
default: "linux/amd64"
context:
description: "构建目录,相对仓库根目录(默认 .)"
required: false
default: "."
dockerfile:
description: "Dockerfile 的完整路径,相对仓库根目录或绝对路径。设置后忽略 preset(默认留空)"
required: false
default: ""
preset:
description: "内置方案:vue3 / vue3-hash / dotnet。未设置 dockerfile 时生效(默认留空)"
required: false
default: ""
runs:
using: "composite"
steps:
# 编译、nginx 配置都在 preset 的 Dockerfile 里(多阶段构建)
# 优先级:dockerfile > preset > context 下的默认 Dockerfile
- name: build docker image and push
uses: docker://docker:git
env:
DOCKER_BUILDKIT: 1
REGISTRY: ${{ inputs.registry }}
REG_USER: ${{ inputs.user }}
REG_PASS: ${{ inputs.pass }}
IMAGE: ${{ inputs.image }}
TAG: ${{ inputs.tag }}
PLATFORM: ${{ inputs.platform }}
CONTEXT_DIR: ${{ inputs.context }}
DOCKERFILE: ${{ inputs.dockerfile }}
PRESET: ${{ inputs.preset }}
ACTION_PATH: ${{ github.action_path }}
with:
entrypoint: "/bin/sh"
args: |
-c '
set -e
image="$REGISTRY/$IMAGE:$TAG"
dockerfile_path="${DOCKERFILE:-}"
preset="${PRESET:-}"
build_args=""
if [ -n "$dockerfile_path" ]; then
if [ -n "$preset" ]; then
echo "已指定 dockerfile($dockerfile_path),忽略 preset($preset)"
fi
elif [ -n "$preset" ]; then
dockerfile_path="$ACTION_PATH/$preset.Dockerfile"
if [ ! -f "$dockerfile_path" ]; then
echo "未知 preset:$preset(可选:vue3 / vue3-hash / dotnet)"
exit 1
fi
# preset 的 Dockerfile 用 VERSION 覆盖 package.json 版本 / dotnet Version
build_args="VERSION=$TAG"
echo "使用 preset:$preset"
else
dockerfile_path="$CONTEXT_DIR/Dockerfile"
fi
echo "构建目录:$CONTEXT_DIR"
echo "Dockerfile:$dockerfile_path"
echo "镜像:$image"
set -- --platform "$PLATFORM" -t "$image" -f "$dockerfile_path"
if [ -n "$build_args" ]; then
set -- --build-arg "$build_args" "$@"
fi
docker ps && docker info && \
docker build "$@" "$CONTEXT_DIR" && \
echo "$image 已经构建完了" && \
docker login "$REGISTRY" -u "$REG_USER" -p "$REG_PASS" && \
docker push "$image" && \
echo "$image 推送成功"
'
+17
View File
@@ -0,0 +1,17 @@
# 多阶段构建:先在 SDK 里 self-contained 发布,最终镜像只保留 runtime + 发布产物
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
# 由 magic-docker 传入:--build-arg VERSION=<tag>
ARG VERSION=0.0.0
WORKDIR /src
# 构建上下文就是 context 目录
COPY . .
RUN dotnet publish -r linux-x64 -c Release --self-contained -o /out \
-p:AssemblyName=App -p:Version="$VERSION"
FROM mcr.microsoft.com/dotnet/runtime:10.0
ENV TZ Asia/Shanghai
COPY --from=build /out /home
WORKDIR /home
ENTRYPOINT ["./App"]
+21
View File
@@ -0,0 +1,21 @@
# 多阶段构建:hash 路由不需要 nginx 回退,最终镜像只保留 nginx + dist
FROM node:24 AS build
# 由 magic-docker 传入:--build-arg VERSION=<tag>
ARG VERSION=0.0.0
WORKDIR /app
# 构建上下文就是 context 目录
COPY . .
RUN npm ci
RUN npm pkg set version="$VERSION"
# 有 build-only 脚本就用它(兼容老项目),否则用 build
RUN if npm run 2>/dev/null | grep -q "build-only"; then \
npm run build-only; \
else \
npm run build; \
fi
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
+51
View File
@@ -0,0 +1,51 @@
# 多阶段构建:先在 node 里编译,最终镜像只保留 nginx + dist
FROM node:24 AS build
# 由 magic-docker 传入:--build-arg VERSION=<tag>
ARG VERSION=0.0.0
WORKDIR /app
# 构建上下文就是 context 目录
COPY . .
RUN npm ci
RUN npm pkg set version="$VERSION"
# 有 build-only 脚本就用它(兼容老项目),否则用 build
RUN if npm run 2>/dev/null | grep -q "build-only"; then \
npm run build-only; \
else \
npm run build; \
fi
# history 路由回退 + 跨域:context 里有 nginx.conf 就用项目的,否则用内置默认配置
RUN set -e; \
if [ -f nginx.conf ]; then \
cp nginx.conf /app/nginx.conf; \
echo "使用项目自带的 nginx.conf"; \
else \
printf '%s\n' \
'server {' \
' listen 80;' \
' root /usr/share/nginx/html;' \
' index index.html;' \
'' \
' add_header Access-Control-Allow-Origin * always;' \
' add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;' \
' add_header Access-Control-Allow-Headers "*, Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Token" always;' \
' add_header Access-Control-Allow-Credentials "true" always;' \
'' \
' if ($request_method = "OPTIONS") {' \
' return 204;' \
' }' \
'' \
' location / {' \
' try_files $uri $uri/ /index.html;' \
' }' \
'}' \
> /app/nginx.conf; \
echo "使用内置的 nginx.conf"; \
fi
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf