Build and smoke-test AutoLibrary as a container
Build and test website container / build (push) Successful in 11m33s
Build and test website container / build (push) Successful in 11m33s
This commit is contained in:
1 parent
e7bd715243
commit
9065a0d3cf
9 files changed
+219
-9
No files matched your search
@@ -0,0 +1,18 @@
|
||||
**
|
||||
!go.mod
|
||||
!go.sum
|
||||
!webserver.go
|
||||
!backend/
|
||||
!backend/**
|
||||
!cli/
|
||||
!cli/**
|
||||
!config/
|
||||
!config/**
|
||||
!frontend/
|
||||
!frontend/**
|
||||
!utils/
|
||||
!utils/**
|
||||
backend/data/
|
||||
frontend/node_modules/
|
||||
frontend/dist/
|
||||
frontend/.env*
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Build and test website container
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, container-ci]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: linux-amd64-docker-small
|
||||
timeout-minutes: 35
|
||||
container:
|
||||
image: docker:29.1.3-cli
|
||||
steps:
|
||||
- name: Install checkout tools
|
||||
shell: sh
|
||||
run: apk add --no-cache bash git
|
||||
|
||||
- name: Check out the pushed commit
|
||||
uses: builtin:checkout
|
||||
with:
|
||||
ref: ${{ gitea.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and test the image
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker info --format '{{range .SecurityOptions}}{{println .}}{{end}}' | grep -Fx 'name=rootless'
|
||||
image="autolibrary-web:${RELEASE_SHA}"
|
||||
trap 'docker image rm "$image" >/dev/null || true' EXIT
|
||||
docker build -t "$image" .
|
||||
bash deploy/smoke-container.sh "$image"
|
||||
@@ -1,12 +1,11 @@
|
||||
name: Deploy AutoLibrary Website
|
||||
name: Deploy native AutoLibrary service
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: linux-amd64-docker-small
|
||||
runs-on: autolibrary-native-deploy
|
||||
steps:
|
||||
- name: Check out the pushed commit
|
||||
uses: https://github.com/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
FROM node:24.22.2-bookworm-slim AS frontend-build
|
||||
WORKDIR /src/frontend
|
||||
COPY frontend/package.json frontend/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY frontend/ ./
|
||||
RUN npm run build
|
||||
|
||||
FROM golang:1.26.1-bookworm AS backend-build
|
||||
WORKDIR /src
|
||||
ENV CGO_ENABLED=1
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY webserver.go ./
|
||||
COPY backend/ ./backend/
|
||||
COPY cli/ ./cli/
|
||||
COPY config/ ./config/
|
||||
COPY frontend/frontend.go ./frontend/frontend.go
|
||||
COPY frontend/handlers/ ./frontend/handlers/
|
||||
COPY utils/ ./utils/
|
||||
RUN go test -p 1 -trimpath ./... && go build -p 1 -trimpath -o /out/webserver .
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl tzdata \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
COPY --from=backend-build /out/webserver ./webserver
|
||||
COPY --from=frontend-build /src/frontend/dist ./frontend/dist
|
||||
COPY backend/templates/ ./backend/templates/
|
||||
RUN install -d -o 10001 -g 10001 /app/backend/data /app/logs
|
||||
ENV AUTOLIBRARY_HTTP_PORT=3000
|
||||
USER 10001:10001
|
||||
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD curl -fsS --noproxy '*' --max-time 2 -o /dev/null "http://127.0.0.1:${AUTOLIBRARY_HTTP_PORT}/" \
|
||||
&& curl -fsS --noproxy '*' --max-time 2 -o /dev/null "http://127.0.0.1:${AUTOLIBRARY_HTTP_PORT}/api/health"
|
||||
ENTRYPOINT ["/app/webserver"]
|
||||
CMD ["start", "--config", "/app/config.json"]
|
||||
@@ -88,7 +88,7 @@ go build -o webserver .
|
||||
|
||||
## 发布与维护
|
||||
|
||||
网站源码推送到 Gitea 的 `main` 后,由生产 Runner 构建、部署并检查服务。首次接入见 [Gitea 自动部署](docs/gitea-deployment.md)。
|
||||
网站源码推送到 Gitea 的 `main` 后,由专用 Runner 构建并验证网站镜像。镜像运行、数据挂载和切换步骤见 [容器部署说明](docs/container-deployment.md)。使用原生 systemd 发布时,见 [Gitea 原生部署](docs/gitea-deployment.md)。
|
||||
|
||||
完整部署、备份和回滚步骤见 [Ubuntu 部署说明](docs/migration-to-ubuntu.md)。配置和运行时数据与前端构建分开保存;本地现有数据库、主题文件和 Casdoor 配置不需要重建。
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
services:
|
||||
website:
|
||||
image: ${AUTOLIBRARY_IMAGE:?Set AUTOLIBRARY_IMAGE}
|
||||
user: "${AUTOLIBRARY_UID:-10001}:${AUTOLIBRARY_GID:-10001}"
|
||||
network_mode: host
|
||||
environment:
|
||||
AUTOLIBRARY_HTTP_PORT: "${AUTOLIBRARY_HTTP_PORT:-3003}"
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 20s
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:mode=1777
|
||||
cap_drop:
|
||||
- ALL
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${AUTOLIBRARY_CONFIG:?Set AUTOLIBRARY_CONFIG}
|
||||
target: /app/config.json
|
||||
read_only: true
|
||||
bind:
|
||||
create_host_path: false
|
||||
- type: bind
|
||||
source: ${AUTOLIBRARY_DATA_DIR:?Set AUTOLIBRARY_DATA_DIR}
|
||||
target: /app/backend/data
|
||||
bind:
|
||||
create_host_path: false
|
||||
- type: bind
|
||||
source: ${AUTOLIBRARY_LOG_DIR:?Set AUTOLIBRARY_LOG_DIR}
|
||||
target: /app/logs
|
||||
bind:
|
||||
create_host_path: false
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
image=${1:?Usage: bash deploy/smoke-container.sh IMAGE}
|
||||
container=
|
||||
fixture=
|
||||
cleanup() {
|
||||
local status=$?
|
||||
if [[ -n $container ]]; then
|
||||
if ((status != 0)); then
|
||||
docker logs "$container" >&2 || true
|
||||
fi
|
||||
docker rm -f "$container" >/dev/null || true
|
||||
fi
|
||||
if [[ -n $fixture ]]; then
|
||||
docker volume rm "$fixture" >/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fixture=$(docker volume create)
|
||||
docker run --rm -i --network none --user 0:0 --cap-drop ALL \
|
||||
--mount "type=volume,source=$fixture,target=/fixture" \
|
||||
--entrypoint /bin/sh "$image" \
|
||||
-c 'umask 022; cat > /fixture/config.json' < config.example.json
|
||||
container=$(docker create --network none --read-only --cap-drop ALL \
|
||||
--security-opt no-new-privileges \
|
||||
--mount "type=volume,source=$fixture,target=/fixture,readonly" \
|
||||
--tmpfs /app/backend/data:uid=10001,gid=10001,mode=0700 \
|
||||
--tmpfs /app/logs:uid=10001,gid=10001,mode=0700 \
|
||||
--tmpfs /tmp:mode=1777 "$image" start --config /fixture/config.json)
|
||||
docker start "$container" >/dev/null
|
||||
|
||||
for ((attempt = 0; attempt < 30; attempt++)); do
|
||||
if [[ $(docker inspect -f '{{.State.Health.Status}}' "$container") == healthy ]]; then
|
||||
for path in /marketplace /assets/favicon.svg /api/download/latest; do
|
||||
docker exec "$container" curl -fsS --noproxy '*' --max-time 3 -o /dev/null \
|
||||
"http://127.0.0.1:3000$path"
|
||||
done
|
||||
docker stop --time 20 "$container" >/dev/null
|
||||
[[ $(docker inspect -f '{{.State.ExitCode}}' "$container") == 0 ]]
|
||||
echo 'Image passed frontend, SQLite API, and graceful shutdown checks.'
|
||||
exit 0
|
||||
fi
|
||||
if [[ $(docker inspect -f '{{.State.Running}}' "$container") != true ]]; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo 'Container did not become healthy.' >&2
|
||||
exit 1
|
||||
@@ -0,0 +1,36 @@
|
||||
# 网站容器
|
||||
|
||||
镜像在独立构建阶段编译 Vue 和启用 CGO 的 Go 程序。最终镜像运行单个 `webserver` 进程,同时提供静态资源和 API。容器配置、SQLite、上传文件和日志由部署机挂载。
|
||||
|
||||
## 构建和验证
|
||||
|
||||
需要 Linux Docker Engine 和 Buildx。在源码根目录运行:
|
||||
|
||||
```sh
|
||||
docker build -t autolibrary-web:local .
|
||||
bash deploy/smoke-container.sh autolibrary-web:local
|
||||
```
|
||||
|
||||
冒烟测试使用临时配置和空数据库,在无外部网络的容器里验证首页、后端健康检查、深层路由、静态资源、SQLite API 和 SIGTERM 退出。
|
||||
|
||||
Gitea Actions 在 `main` 和 `container-ci` 推送时执行同一套镜像构建和冒烟测试。专用 Runner `hk-vps-runner-02` 使用 `linux-amd64-docker-small` 标签,作业在 Docker CLI 容器中运行。给构建作业提供专用 rootless Docker daemon,工作流会检查 daemon 的 rootless 标志。镜像仓库推送和生产切换需要单独接入。
|
||||
|
||||
## 使用现网配置
|
||||
|
||||
生产机运行 Compose v2。复制 `/home/autolibrary/config.json` 到独立文件,将 `frontend.static.path` 设置为 `./frontend/dist`。数据库路径使用 `./backend/data/` 下的现有相对路径。保留前端端口 `3003`、后端端口 `8080` 和 Casdoor 地址 `http://127.0.0.1:8000`。Compose 使用 Linux 宿主机网络,让 Nginx 和 Casdoor 继续通过原有地址连接。
|
||||
|
||||
从部署机设置以下环境变量。镜像可以用提交 SHA 标签或不可变的镜像摘要引用:
|
||||
|
||||
```dotenv
|
||||
AUTOLIBRARY_IMAGE=autolibrary-web:<提交SHA>
|
||||
AUTOLIBRARY_CONFIG=/绝对路径/网站容器配置.json
|
||||
AUTOLIBRARY_DATA_DIR=/home/autolibrary/backend/data
|
||||
AUTOLIBRARY_LOG_DIR=/home/autolibrary/logs
|
||||
AUTOLIBRARY_UID=996
|
||||
AUTOLIBRARY_GID=987
|
||||
AUTOLIBRARY_HTTP_PORT=3003
|
||||
```
|
||||
|
||||
配置文件对容器运行身份可读,数据目录及日志目录可写。Compose 会检查挂载源是否存在。
|
||||
|
||||
正式切换前,先用独立端口和数据库副本验证容器,并备份数据库和上传文件。切换时停止占用相同端口的 `autolibrary-webserver.service`,运行 `docker compose up -d --wait`,然后验证 Nginx 入口、登录及上传。若首次切换失败,停止网站容器,再启动原网站服务。后续发布可将 `AUTOLIBRARY_IMAGE` 指回上一个镜像,再运行 `docker compose up -d --wait`。程序回退继续使用同一份持久数据。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 通过 Gitea Actions 部署官网
|
||||
# 通过 Gitea Actions 部署原生网站服务
|
||||
|
||||
推送到网站仓库的 `main` 后,Gitea 把任务交给 Ubuntu 部署机上的专用 Runner。Runner 检出该次提交,使用锁文件安装前端依赖,执行前端构建、`go test ./...` 和启用 CGO 的 Go 编译。每次发布生成独立目录,原子切换 `current`,重启 systemd 服务并检查首页和 `/api/health`。检查失败时自动切回上一发布,并将本次任务标记为失败。
|
||||
本页用于手动触发原生网站发布。推送触发的镜像构建见 [容器部署说明](container-deployment.md)。在 Gitea Actions 手动运行 `Deploy native AutoLibrary service` 时,任务由具备 `autolibrary-native-deploy` 标签的宿主机 Runner 接收。每次发布生成独立目录,原子切换 `current`,重启 systemd 服务并检查首页和 `/api/health`。检查失败时自动切回上一发布,并将本次任务标记为失败。
|
||||
|
||||
## 1. 准备 Ubuntu 部署机
|
||||
|
||||
@@ -52,7 +52,7 @@ autolibrary-deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart autolibrary-w
|
||||
sudo -u autolibrary-deploy -H sh -c 'cd "$HOME" && gitea-runner register'
|
||||
```
|
||||
|
||||
输入实例地址和仓库级令牌,名称填写 `hk-vps-runner-02`,标签只填写 `linux-amd64-docker-small:host`。冒号前是工作流使用的调度标签,`:host` 使发布脚本能操作宿主机上的网站服务。以同一账号和工作目录运行 `gitea-runner daemon`。可用下面的 systemd unit 持久运行,将 `ExecStart` 与 `PATH` 调整到实际安装位置。
|
||||
输入实例地址和仓库级令牌,使用独立的原生发布 Runner 名称,标签只填写 `autolibrary-native-deploy:host`。以同一账号和工作目录运行 `gitea-runner daemon`。可用下面的 systemd unit 持久运行,将 `ExecStart` 与 `PATH` 调整到实际安装位置。
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
@@ -84,7 +84,7 @@ git remote add origin <Gitea 网站源码仓库的克隆地址>
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
在 Gitea 的 Actions 页确认部署任务完成。之后日常发布只需推送 `main`。发布脚本在切换前读取远端 `main`,已过时的任务会跳过部署。生产密钥、数据库、上传目录和 Casdoor 实例数据由部署机保存。
|
||||
在 Gitea 的 Actions 页手动运行 `Deploy native AutoLibrary service`,选择 `main`,然后确认部署任务完成。发布脚本在切换前读取远端 `main`,已过时的任务会跳过部署。生产密钥、数据库、上传目录和 Casdoor 实例数据由部署机保存。
|
||||
|
||||
## 排查和回滚
|
||||
|
||||
|
||||
Reference in new issue
Block a user