diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml index ff51835..6e5611c 100644 --- a/.gitea/workflows/publish.yml +++ b/.gitea/workflows/publish.yml @@ -119,6 +119,7 @@ jobs: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 + pull: true push: true tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 44657b9..788fb9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,18 +10,15 @@ RUN npm --prefix web run build FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build ARG TARGETARCH WORKDIR /source +COPY global.json ./ COPY .env.example ./ COPY src/Jiaowu.Api/Jiaowu.Api.csproj ./src/Jiaowu.Api/ -RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \ - arch="${TARGETARCH/amd64/x64}" && \ - dotnet restore ./src/Jiaowu.Api/Jiaowu.Api.csproj --arch "$arch" +RUN dotnet restore ./src/Jiaowu.Api/Jiaowu.Api.csproj --arch "$TARGETARCH" COPY src/Jiaowu.Api/ ./src/Jiaowu.Api/ COPY --from=frontend /source/src/Jiaowu.Api/wwwroot/ ./src/Jiaowu.Api/wwwroot/ -RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \ - arch="${TARGETARCH/amd64/x64}" && \ - dotnet publish ./src/Jiaowu.Api/Jiaowu.Api.csproj \ +RUN dotnet publish ./src/Jiaowu.Api/Jiaowu.Api.csproj \ --configuration Release \ - --arch "$arch" \ + --arch "$TARGETARCH" \ --no-restore \ --no-self-contained \ --output /app/publish \ diff --git a/README.md b/README.md index 7a2a621..e115001 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,68 @@ Kubernetes 或密钥管理系统仍可覆盖文件中的值。 `chmod 600 .env`,Windows 应通过 ACL 只允许服务账号和管理员读取。连接串中的证书 路径必须是运行服务器上的实际路径。 +### Linux systemd 服务 + +仓库提供 [`deploy/systemd/jiaowu.service`](deploy/systemd/jiaowu.service),适用于 +使用 systemd 的 Linux 发行版。示例假定自包含发布包位于 `/opt/jiaowu`,服务使用 +无登录权限的 `jiaowu` 账号。程序会自动读取 `/opt/jiaowu/.env`,因此服务单元没有再 +配置 `EnvironmentFile=`。 + +以 Debian/Ubuntu 为例,先创建账号并设置文件权限: + +```bash +sudo useradd --system \ + --home-dir /opt/jiaowu \ + --shell /usr/sbin/nologin \ + jiaowu + +sudo chown -R root:jiaowu /opt/jiaowu +sudo chmod 0750 /opt/jiaowu +sudo chmod 0750 /opt/jiaowu/Jiaowu.Api +sudo chmod 0640 /opt/jiaowu/.env +``` + +如果账号已存在,`useradd` 会报错,可以跳过该命令。RHEL 系发行版的 `nologin` 通常 +位于 `/sbin/nologin`,请按服务器实际路径调整。如果连接串使用私有 CA,还要确保 +`jiaowu` 组对 `SslCa` 指向的证书文件具有读取权限。首次启动前,先停止旧实例,并以 +服务账号执行迁移;仅专用空演示库需要执行第二条灌数命令: + +```bash +sudo -u jiaowu /opt/jiaowu/Jiaowu.Api --migrate-only + +sudo -u jiaowu /opt/jiaowu/Jiaowu.Api \ + --seed-demo-data \ + --confirm-production-demo-data +``` + +演示数据成功后,从 `/opt/jiaowu/.env` 删除临时的 `SeedAdmin__*` 配置。随后安装并 +验证服务单元: + +```bash +sudo install \ + --owner=root \ + --group=root \ + --mode=0644 \ + deploy/systemd/jiaowu.service \ + /etc/systemd/system/jiaowu.service + +sudo systemd-analyze verify /etc/systemd/system/jiaowu.service +sudo systemctl daemon-reload +sudo systemctl enable --now jiaowu.service +``` + +查看状态、实时日志和数据库就绪探针: + +```bash +sudo systemctl status jiaowu.service --no-pager +sudo journalctl --unit=jiaowu.service --follow +curl --fail http://127.0.0.1:8080/health/ready +``` + +更新程序时应先 `sudo systemctl stop jiaowu.service`,替换发布文件并执行 +`--migrate-only`,确认迁移成功后再运行 `sudo systemctl start jiaowu.service`。 +服务以失败重启策略运行,但不会在正常退出或管理员主动停止后自行拉起。 + 数据库应明确使用 `utf8mb4`;MySQL 8.4 的默认排序规则为 `utf8mb4_0900_ai_ci`。新建数据库时可执行: diff --git a/deploy/systemd/jiaowu.service b/deploy/systemd/jiaowu.service new file mode 100644 index 0000000..1657ff3 --- /dev/null +++ b/deploy/systemd/jiaowu.service @@ -0,0 +1,34 @@ +[Unit] +Description=Jiaowu Academic Affairs System +Wants=network-online.target +After=network-online.target + +[Service] +Type=simple +User=jiaowu +Group=jiaowu +WorkingDirectory=/opt/jiaowu +ExecStart=/opt/jiaowu/Jiaowu.Api + +Restart=on-failure +RestartSec=5s +TimeoutStopSec=30s +SyslogIdentifier=jiaowu + +Environment=DOTNET_EnableDiagnostics=0 +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectSystem=full +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +RestrictSUIDSGID=true +LockPersonality=true +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 + +[Install] +WantedBy=multi-user.target