mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
Add release config validation workflow
This commit is contained in:
parent
b1aeb3c8a2
commit
7a0d40736c
4 changed files with 217 additions and 3 deletions
5
Makefile
5
Makefile
|
|
@ -1,4 +1,4 @@
|
|||
.PHONY: help dev dev-all dev-down dev-all-down dev-all-reset build test clean web-install dev-server dev-web build-web test-web typecheck-web lint-web generate-api db-reset
|
||||
.PHONY: help dev dev-all dev-down dev-all-down dev-all-reset build test clean web-install dev-server dev-web build-web test-web typecheck-web lint-web generate-api db-reset validate-release-config
|
||||
|
||||
DEV_DIR := .dev
|
||||
DEV_SERVER_PID := $(DEV_DIR)/server.pid
|
||||
|
|
@ -142,3 +142,6 @@ db-reset: ## 重置数据库
|
|||
docker compose down -v --remove-orphans
|
||||
docker compose up -d --wait --remove-orphans postgres
|
||||
cd server && ./mvnw flyway:migrate -pl skillhub-app
|
||||
|
||||
validate-release-config: ## 校验发布环境变量文件(默认 .env.release)
|
||||
./scripts/validate-release-config.sh .env.release
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ Recommended image tags:
|
|||
Start the runtime:
|
||||
|
||||
```bash
|
||||
make validate-release-config
|
||||
docker compose --env-file .env.release -f compose.release.yml up -d
|
||||
```
|
||||
|
||||
|
|
@ -152,6 +153,7 @@ Recommended production baseline:
|
|||
- keep PostgreSQL / Redis bound to `127.0.0.1`
|
||||
- use external S3 / OSS via `SKILLHUB_STORAGE_S3_*`
|
||||
- rotate or disable the bootstrap admin after initial setup
|
||||
- run `make validate-release-config` before `docker compose up -d`
|
||||
|
||||
If the GHCR package remains private, run `docker login ghcr.io` before
|
||||
`docker compose up -d`.
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ make dev-all-reset
|
|||
|
||||
```bash
|
||||
cp .env.release.example .env.release
|
||||
make validate-release-config
|
||||
docker compose --env-file .env.release -f compose.release.yml up -d
|
||||
```
|
||||
|
||||
|
|
@ -114,6 +115,9 @@ docker compose --env-file .env.release -f compose.release.yml up -d
|
|||
- `.env.release.example`
|
||||
- 运行时变量模板
|
||||
- 包含镜像名、镜像版本、端口、数据库凭证、外部 OSS、站点公网地址和首登管理员参数
|
||||
- `scripts/validate-release-config.sh`
|
||||
- 在启动前校验 `.env.release`
|
||||
- 可提前拦截占位值、URL 格式错误、缺失的 OSS 凭据、危险的明文默认值
|
||||
|
||||
### 5.3 镜像标签约定
|
||||
|
||||
|
|
@ -168,7 +172,32 @@ docker compose --env-file .env.release -f compose.release.yml up -d
|
|||
- 前端反代和运行时 API 地址通过 `SKILLHUB_API_UPSTREAM` / `SKILLHUB_WEB_API_BASE_URL` 注入
|
||||
- 如果要开放真实登录,再补充 `OAUTH2_GITHUB_CLIENT_ID` / `OAUTH2_GITHUB_CLIENT_SECRET`
|
||||
|
||||
## 8 可观测性
|
||||
## 8 裸金属上线清单
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 准备服务器基础环境
|
||||
- 安装 Docker Engine 与 Docker Compose Plugin
|
||||
- 配置公网 HTTPS 入口,确保最终访问域名已经确定
|
||||
- 打开 `80` / `443`,避免直接暴露 `5432` / `6379`
|
||||
2. 填写 `.env.release`
|
||||
- `SKILLHUB_PUBLIC_BASE_URL` 填最终 HTTPS 域名,且不要带尾部 `/`
|
||||
- `SKILLHUB_STORAGE_PROVIDER=s3`
|
||||
- 按云厂商 OSS / S3 兼容参数填写 `SKILLHUB_STORAGE_S3_*`
|
||||
- 设置非默认的 `POSTGRES_PASSWORD` 与 `BOOTSTRAP_ADMIN_PASSWORD`
|
||||
3. 启动前校验
|
||||
- 运行 `make validate-release-config`
|
||||
- 确认没有 `replace-me`、`change-this-*`、`ChangeMe!2026` 之类的占位值
|
||||
4. 首次启动
|
||||
- 运行 `docker compose --env-file .env.release -f compose.release.yml up -d`
|
||||
- 检查 `docker compose --env-file .env.release -f compose.release.yml ps`
|
||||
- 检查 `curl -i http://127.0.0.1:8080/actuator/health`
|
||||
5. 首登收尾
|
||||
- 使用 `BOOTSTRAP_ADMIN_USERNAME` / `BOOTSTRAP_ADMIN_PASSWORD` 登录
|
||||
- 立即修改管理员密码
|
||||
- 如果后续完全走 OAuth,可将 `BOOTSTRAP_ADMIN_ENABLED=false`
|
||||
|
||||
## 9 可观测性
|
||||
|
||||
| 维度 | 方案 |
|
||||
|------|------|
|
||||
|
|
@ -176,7 +205,7 @@ docker compose --env-file .env.release -f compose.release.yml up -d
|
|||
| 日志 | 容器 stdout / stderr |
|
||||
| 指标 | Spring Boot Actuator,后续可接 Prometheus |
|
||||
|
||||
## 9 数据迁移
|
||||
## 10 数据迁移
|
||||
|
||||
Flyway 仍是唯一 schema 变更入口:
|
||||
|
||||
|
|
|
|||
180
scripts/validate-release-config.sh
Executable file
180
scripts/validate-release-config.sh
Executable file
|
|
@ -0,0 +1,180 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
ENV_FILE="${1:-.env.release}"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "ERROR: env file not found: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while IFS= read -r raw_line || [ -n "$raw_line" ]; do
|
||||
line=$(printf '%s' "$raw_line" | tr -d '\r')
|
||||
case "$line" in
|
||||
""|\#*) continue ;;
|
||||
esac
|
||||
export "$line"
|
||||
done < "$ENV_FILE"
|
||||
|
||||
errors=0
|
||||
warnings=0
|
||||
|
||||
error() {
|
||||
errors=$((errors + 1))
|
||||
echo "ERROR: $*" >&2
|
||||
}
|
||||
|
||||
warn() {
|
||||
warnings=$((warnings + 1))
|
||||
echo "WARN: $*" >&2
|
||||
}
|
||||
|
||||
require_non_empty() {
|
||||
var_name="$1"
|
||||
eval "var_value=\${$var_name:-}"
|
||||
if [ -z "$var_value" ]; then
|
||||
error "$var_name is required"
|
||||
fi
|
||||
}
|
||||
|
||||
reject_values() {
|
||||
var_name="$1"
|
||||
shift
|
||||
eval "var_value=\${$var_name:-}"
|
||||
if [ -z "$var_value" ]; then
|
||||
return 0
|
||||
fi
|
||||
for bad in "$@"; do
|
||||
if [ "$var_value" = "$bad" ]; then
|
||||
error "$var_name still uses placeholder/default value: $bad"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
validate_url() {
|
||||
var_name="$1"
|
||||
eval "var_value=\${$var_name:-}"
|
||||
if [ -z "$var_value" ]; then
|
||||
return 0
|
||||
fi
|
||||
case "$var_value" in
|
||||
http://*|https://*) ;;
|
||||
*) error "$var_name must start with http:// or https://" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_no_trailing_slash() {
|
||||
var_name="$1"
|
||||
eval "var_value=\${$var_name:-}"
|
||||
case "$var_value" in
|
||||
*/) error "$var_name must not have a trailing slash" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_boolean() {
|
||||
var_name="$1"
|
||||
eval "var_value=\${$var_name:-}"
|
||||
case "$var_value" in
|
||||
""|true|false) ;;
|
||||
*) error "$var_name must be true or false" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_port() {
|
||||
var_name="$1"
|
||||
eval "var_value=\${$var_name:-}"
|
||||
if [ -z "$var_value" ]; then
|
||||
return 0
|
||||
fi
|
||||
case "$var_value" in
|
||||
*[!0-9]*|"") error "$var_name must be numeric" ;;
|
||||
*)
|
||||
if [ "$var_value" -lt 1 ] || [ "$var_value" -gt 65535 ]; then
|
||||
error "$var_name must be between 1 and 65535"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
require_non_empty SKILLHUB_PUBLIC_BASE_URL
|
||||
validate_url SKILLHUB_PUBLIC_BASE_URL
|
||||
validate_no_trailing_slash SKILLHUB_PUBLIC_BASE_URL
|
||||
|
||||
reject_values POSTGRES_PASSWORD "change-this-postgres-password" "skillhub_demo" "skillhub_dev"
|
||||
reject_values BOOTSTRAP_ADMIN_PASSWORD "replace-this-admin-password" "ChangeMe!2026" "Admin@2026"
|
||||
reject_values SKILLHUB_STORAGE_S3_ACCESS_KEY "replace-me"
|
||||
reject_values SKILLHUB_STORAGE_S3_SECRET_KEY "replace-me"
|
||||
|
||||
validate_boolean SESSION_COOKIE_SECURE
|
||||
validate_boolean BOOTSTRAP_ADMIN_ENABLED
|
||||
validate_boolean SKILLHUB_STORAGE_S3_FORCE_PATH_STYLE
|
||||
validate_boolean SKILLHUB_STORAGE_S3_AUTO_CREATE_BUCKET
|
||||
|
||||
validate_port POSTGRES_PORT
|
||||
validate_port REDIS_PORT
|
||||
validate_port API_PORT
|
||||
validate_port WEB_PORT
|
||||
|
||||
require_non_empty POSTGRES_DB
|
||||
require_non_empty POSTGRES_USER
|
||||
require_non_empty POSTGRES_PASSWORD
|
||||
|
||||
storage_provider="${SKILLHUB_STORAGE_PROVIDER:-}"
|
||||
case "$storage_provider" in
|
||||
s3)
|
||||
require_non_empty SKILLHUB_STORAGE_S3_ENDPOINT
|
||||
require_non_empty SKILLHUB_STORAGE_S3_BUCKET
|
||||
require_non_empty SKILLHUB_STORAGE_S3_ACCESS_KEY
|
||||
require_non_empty SKILLHUB_STORAGE_S3_SECRET_KEY
|
||||
require_non_empty SKILLHUB_STORAGE_S3_REGION
|
||||
validate_url SKILLHUB_STORAGE_S3_ENDPOINT
|
||||
validate_url SKILLHUB_STORAGE_S3_PUBLIC_ENDPOINT
|
||||
;;
|
||||
local)
|
||||
warn "SKILLHUB_STORAGE_PROVIDER=local is only suitable for non-production or temporary validation"
|
||||
;;
|
||||
"")
|
||||
error "SKILLHUB_STORAGE_PROVIDER is required"
|
||||
;;
|
||||
*)
|
||||
error "SKILLHUB_STORAGE_PROVIDER must be either local or s3"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "${SKILLHUB_WEB_API_BASE_URL:-}" ]; then
|
||||
validate_url SKILLHUB_WEB_API_BASE_URL
|
||||
validate_no_trailing_slash SKILLHUB_WEB_API_BASE_URL
|
||||
fi
|
||||
|
||||
if [ -n "${DEVICE_AUTH_VERIFICATION_URI:-}" ]; then
|
||||
validate_url DEVICE_AUTH_VERIFICATION_URI
|
||||
fi
|
||||
|
||||
if [ "${SESSION_COOKIE_SECURE:-true}" != "true" ]; then
|
||||
warn "SESSION_COOKIE_SECURE is not true; only acceptable behind plain HTTP during temporary local verification"
|
||||
fi
|
||||
|
||||
if [ "${POSTGRES_BIND_ADDRESS:-127.0.0.1}" != "127.0.0.1" ]; then
|
||||
warn "POSTGRES_BIND_ADDRESS is not 127.0.0.1; confirm database exposure is intended"
|
||||
fi
|
||||
|
||||
if [ "${REDIS_BIND_ADDRESS:-127.0.0.1}" != "127.0.0.1" ]; then
|
||||
warn "REDIS_BIND_ADDRESS is not 127.0.0.1; confirm Redis exposure is intended"
|
||||
fi
|
||||
|
||||
oauth_id="${OAUTH2_GITHUB_CLIENT_ID:-}"
|
||||
oauth_secret="${OAUTH2_GITHUB_CLIENT_SECRET:-}"
|
||||
if [ -n "$oauth_id" ] && [ -z "$oauth_secret" ]; then
|
||||
error "OAUTH2_GITHUB_CLIENT_SECRET is required when OAUTH2_GITHUB_CLIENT_ID is set"
|
||||
fi
|
||||
if [ -n "$oauth_secret" ] && [ -z "$oauth_id" ]; then
|
||||
error "OAUTH2_GITHUB_CLIENT_ID is required when OAUTH2_GITHUB_CLIENT_SECRET is set"
|
||||
fi
|
||||
|
||||
if [ "$errors" -gt 0 ]; then
|
||||
echo "Release config validation failed: $errors error(s), $warnings warning(s)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Release config validation passed with $warnings warning(s)."
|
||||
Loading…
Add table
Reference in a new issue