Repository navigation
177 lines (151 loc) · 6.63 KB
/
Copy pathdeploy.yml
File metadata and controls
177 lines (151 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
name: Deploy to Production
# push 到 dev 分支(或手动触发):构建 → 上传 → 原子切换 → 健康检查
on:
push:
branches: [dev]
workflow_dispatch:
permissions:
contents: read
env:
NODE_VERSION: "24.20.0"
concurrency:
group: knowforge-production
cancel-in-progress: false
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout source
uses: actions/checkout@v6
# ── 前端:类型检查 + lint + SSR 构建 ──
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/web/pnpm-lock.yaml
- name: Install web dependencies
working-directory: app/web
run: pnpm install --frozen-lockfile
- name: Typecheck, test and lint web
working-directory: app/web
run: |
pnpm exec tsc --noEmit
pnpm test
pnpm exec next lint
- name: Build web (SSR standalone)
working-directory: app/web
env:
NEXT_DIST_DIR: .next-build
run: pnpm build
- name: Package embedded web runtime
run: deploy/package-web-runtime.sh "$NODE_VERSION" linux amd64 server/internal/webbundle/assets/web-runtime.tar.gz
# ── 单文件:Go API + Next.js standalone + Node.js 24 ──
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: server/go.mod
cache-dependency-path: server/go.sum
- name: Vet and test backend
working-directory: server
run: |
go vet ./...
go test ./...
- name: Build Linux backend
working-directory: server
env:
CGO_ENABLED: "0"
GOOS: linux
GOARCH: amd64
COMMIT_SHA: ${{ github.sha }}
run: |
mkdir -p ../release
go build -trimpath \
-ldflags="-s -w \
-X 'knowforge/server/internal/app.Commit=${COMMIT_SHA::7}' \
-X 'knowforge/server/internal/app.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)'" \
-o ../release/knowforge-server .
# ── 打包发布:只有一个应用二进制 + systemd unit + env ──
- name: Assemble release
env:
# 改名后优先用新密钥 KNOWFORGE_ENV_FILE;未创建时回退到旧密钥 INFO_SPHERE_ENV_FILE,
# 让既有部署无需先改密钥即可继续发布(env 内容里的 INFO_SPHERE_* 变量名由二进制启动时兼容读取)。
KNOWFORGE_ENV_FILE: ${{ secrets.KNOWFORGE_ENV_FILE }}
INFO_SPHERE_ENV_FILE: ${{ secrets.INFO_SPHERE_ENV_FILE }}
run: |
ENV_CONTENT="${KNOWFORGE_ENV_FILE:-$INFO_SPHERE_ENV_FILE}"
test -n "$ENV_CONTENT"
cp deploy/knowforge-api.service deploy/knowforge.sudoers release/
printf '%s\n' "$ENV_CONTENT" > release/knowforge.env
chmod 600 release/knowforge.env
(cd release && sha256sum knowforge-server > SHA256SUMS)
ls -la release/
- name: Upload release to server
uses: appleboy/scp-action@v1.0.0
with:
host: ${{ secrets.SSH_PRIVATE_HOST }}
username: ${{ secrets.SSH_PRIVATE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "release/*"
target: "/tmp/knowforge-release-${{ github.sha }}"
strip_components: 1
- name: Activate release
uses: appleboy/ssh-action@v1.2.5
env:
RELEASE_SHA: ${{ github.sha }}
with:
host: ${{ secrets.SSH_PRIVATE_HOST }}
username: ${{ secrets.SSH_PRIVATE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
envs: RELEASE_SHA
script: |
set -eu
deploy_root=/var/www/knowforge
staged_dir=/tmp/knowforge-release-$RELEASE_SHA
release_dir=$deploy_root/releases/$RELEASE_SHA
test -f "$staged_dir/knowforge-server"
test -s "$staged_dir/knowforge.env"
# 目录骨架
sudo install -d -m 755 "$deploy_root/releases" "$release_dir" /etc/knowforge
sudo install -d -m 755 -o www-data -g www-data /var/lib/knowforge /var/lib/knowforge/uploads
sudo install -d -m 755 -o www-data -g www-data /var/www/knowforge/static
# 既有部署的数据仍在 /var/lib/infosphere:不强制迁移,systemd 同时放行新旧目录,
# 二进制按 env 里的 KNOWFORGE_DATA/INFO_SPHERE_DATA 就地读写,升级零数据迁移风险。
# 发布单文件
sudo cp -a "$staged_dir/." "$release_dir/"
sudo chmod 755 "$release_dir/knowforge-server"
# 配置与服务
sudo install -m 600 "$release_dir/knowforge.env" /etc/knowforge/knowforge.env
sudo install -m 644 "$release_dir/knowforge-api.service" /etc/systemd/system/knowforge-api.service
sudo install -m 440 "$release_dir/knowforge.sudoers" /etc/sudoers.d/knowforge
sudo visudo -c >/dev/null
# 原子切换 current
sudo ln -sfn "$release_dir" "$deploy_root/current.next"
sudo mv -Tf "$deploy_root/current.next" "$deploy_root/current"
# 停止并禁用旧品牌单元(infosphere-*)与早期独立 Web unit,避免端口 6969/6900 冲突与残留
sudo systemctl disable --now infosphere-api.service infosphere-web.service knowforge-web.service 2>/dev/null || true
sudo systemctl daemon-reload
sudo systemctl enable knowforge-api.service
sudo systemctl restart knowforge-api.service
# 健康检查:单服务包含当前 commit,内嵌 Web 与 Go 页面代理均可访问
attempt=0
until curl -fsS http://127.0.0.1:6969/api/v1/health | grep -q "\"commit\":\"${RELEASE_SHA::7}\"" \
&& curl -fsS -o /dev/null http://127.0.0.1:6900/ \
&& curl -fsS -o /dev/null http://127.0.0.1:6969/; do
attempt=$((attempt + 1))
if [ "$attempt" -ge 15 ]; then
sudo systemctl status knowforge-api.service --no-pager || true
sudo journalctl -u knowforge-api.service -n 30 --no-pager || true
exit 1
fi
sleep 2
done
# 清理:仅保留最近 5 个版本
sudo bash -c "ls -1dt $deploy_root/releases/*/ | tail -n +6 | xargs -r rm -rf"
rm -rf "$staged_dir"
echo "KnowForge 部署完成: $release_dir"