Skip to content

Commit 0debafa

Browse files
committed
chore: exit code 1
1 parent 075be73 commit 0debafa

File tree

2 files changed

+360
-1
lines changed

2 files changed

+360
-1
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"start": "pnpm dev",
1010
"build:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider vuepress build src --dest dist",
1111
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vuepress build src --dest dist",
12-
"postbuild": "bash -c '[ -z \"$VERCEL\" ] && mv -f ./dist/* /var/www/html/blog/'"
12+
"postbuild": "bash -c '[ -z \"$VERCEL\" ] && mv -f ./dist/* /var/www/html/blog/ || true'"
1313
},
1414
"engines": {
1515
"node": ">=18.0.0"

src/_posts/Server/02-deploy.md

+359
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
---
2+
category: Server
3+
tags:
4+
- Full Stack
5+
date: 2024-12-07
6+
title: 全栈项目从上线、部署到运维
7+
vssue-title: 全栈项目从上线、部署到运维
8+
---
9+
10+
本文主要记录了全栈项目上线、部署、运维的整个流程,仅供参考
11+
12+
<!-- more -->
13+
14+
## 基本信息
15+
16+
### 项目选型
17+
- React
18+
- NestJS
19+
- MySQL
20+
21+
### 服务器
22+
- 阿里云 ECS
23+
- Debain 10.13
24+
25+
## 环境安装
26+
27+
### Git
28+
安装 git:
29+
```bash
30+
sudo apt update
31+
sudo apt install git
32+
```
33+
34+
生成 ssh key 后配置到 Github 中:
35+
```bash
36+
ssh-keygen -t ed25519 -C "[email protected]"
37+
```
38+
39+
### MySQL
40+
下载 MySQL 5.7,或者前往[官网](https://downloads.mysql.com/archives/community/)寻找合适的版本:
41+
```bash
42+
curl -OL https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
43+
```
44+
45+
然后解压缩:
46+
```bash
47+
sudo tar -xzf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz -C /usr/local
48+
```
49+
50+
重命名目录:
51+
```bash
52+
cd /user/local
53+
sudo mv mysql-5.7.44-linux-glibc2.12-x86_64 mysql
54+
```
55+
56+
创建 MySQL 用户和组:
57+
```bash
58+
sudo groupadd mysql
59+
sudo useradd -r -g mysql -s /bin/false mysql
60+
```
61+
62+
初始化数据库:
63+
```bash
64+
cd /usr/local/mysql
65+
sudo mkdir mysql-files
66+
sudo chmod 750 mysql-files
67+
sudo chown -R mysql:mysql ./
68+
sudo bin/mysqld --initialize --user=mysql
69+
```
70+
71+
此时终端中会显示随机生成的密码:
72+
```
73+
[Note] A temporary password is generated for root@localhost: %sqwtmz5p(Xe
74+
```
75+
76+
设置权限和目录:
77+
```bash
78+
sudo chown -R root .
79+
sudo chown -R mysql data mysql-files
80+
```
81+
82+
安装启动脚本:
83+
```bash
84+
sudo cp support-files/mysql.server /etc/init.d/mysql
85+
sudo chmod +x /etc/init.d/mysql
86+
sudo update-rc.d mysql defaults
87+
```
88+
89+
启动 MySQL 服务:
90+
```bash
91+
sudo systemctl start mysql
92+
```
93+
94+
查询 MySQL 服务状态:
95+
```bash
96+
sudo systemctl status mysql
97+
```
98+
99+
修改密码:
100+
```bash
101+
# 登录 root
102+
mysql -u root -p
103+
104+
# 执行 SQL
105+
ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';
106+
```
107+
108+
### MySQL 远程连接
109+
创建一个新的用户用于远程连接:
110+
```bash
111+
# % 表示任意地址,也可以指定具体的 ip
112+
CREATE USER 'remote'@'%' IDENTIFIED BY 'newpassword'
113+
```
114+
115+
授予权限:
116+
```bash
117+
# 所有数据库:
118+
GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%';
119+
120+
# 特定数据库
121+
GRANT ALL PRIVILEGES ON exampledb.* TO 'newuser'@'%';
122+
```
123+
124+
刷新权限:
125+
```bash
126+
FLUSH PRIVILEGES;
127+
```
128+
129+
配置 MySQL 允许远程连接,编辑或新建 `/etc/mysql/my.cnf``/etc/my.cnf`
130+
```bash
131+
[mysqld]
132+
bind-address = 0.0.0.0
133+
```
134+
135+
然后重启 MySQL 服务:
136+
```bash
137+
sudo systemctl restart mysql
138+
```
139+
140+
### NodeJS
141+
安装 nvm 来管理 NodeJS 版本,官方的安装方式对于网络连通性有要求,采用下面的方法:
142+
```bash
143+
git clone https://github.com/nvm-sh/nvm.git
144+
bash nvm/install.sh
145+
```
146+
147+
安装 NodeJS 20:
148+
```bash
149+
nvm install 20
150+
```
151+
152+
设置 npm 镜像:
153+
```bash
154+
echo 'registry=https://registry.npmmirror.com/' > ~/.npmrc
155+
```
156+
157+
### Nginx
158+
安装 Nginx:
159+
```bash
160+
sudo apt install nginx
161+
```
162+
163+
## 服务部署
164+
### NodeJS 服务
165+
使用 `pm2` 来启动 NodeJS 服务:
166+
```bash
167+
pm2 start ecosystem.config.js --env production
168+
```
169+
170+
配置文件示例:
171+
```js
172+
// ecosystem.config.js
173+
module.exports = {
174+
apps: [
175+
{
176+
name: 'my-app',
177+
script: 'dist/main.js',
178+
instances: 'max',
179+
exec_mode: 'cluster',
180+
env: {
181+
NODE_ENV: 'development'
182+
},
183+
env_production: {
184+
NODE_ENV: 'production'
185+
}
186+
}
187+
]
188+
};
189+
```
190+
191+
### Nginx
192+
配置 Nginx 转发服务端接口:
193+
```bash
194+
cd /etc/nginx/sites-available/
195+
vi api.myhost.com
196+
```
197+
198+
配置文件中添加:
199+
```nginx
200+
server {
201+
listen 80;
202+
server_name api.myhost.com;
203+
204+
location / {
205+
proxy_pass http://localhost:3000;
206+
proxy_set_header Host $host;
207+
proxy_set_header X-Real-IP $remote_addr;
208+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
209+
proxy_set_header X-Forwarded-Proto $scheme;
210+
}
211+
}
212+
```
213+
新建软连接以启动对应配置:
214+
```bash
215+
sudo ln -s /etc/nginx/sites-available/api.myhost.com /etc/nginx/sites-enabled/
216+
```
217+
218+
重启 Nginx 应用配置:
219+
```bash
220+
sudo systemctl restart nginx
221+
```
222+
223+
配置 Nginx 转发前端静态资源,流程和前面一致,仅 Nginx 配置略有不同:
224+
```nginx
225+
server {
226+
listen 80;
227+
server_name www.example.com;
228+
229+
root /root/projects/example/dist;
230+
index index.html index.htm;
231+
232+
location / {
233+
try_files $uri $uri/ =404;
234+
}
235+
}
236+
```
237+
238+
### HTTPS 证书申请
239+
通过 certbot 申请 SSL 证书,安装对应 pkg:
240+
```bash
241+
sudo apt install certbot python3-certbot-nginx
242+
```
243+
244+
根据提示完成配置,将自动下载证书,完成 nginx 配置并重启:
245+
```bash
246+
sudo certbot --nginx -d api.myhost.com
247+
```
248+
249+
证书有效期只有 3 个月,可以通过脚本实现自动续签,参考 [certbot-dns-aliyun](https://github.com/justjavac/certbot-dns-aliyun)
250+
```bash
251+
# 安装 certbot-dns-aliyun
252+
wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
253+
sudo cp alidns.sh /usr/local/bin
254+
sudo chmod +x /usr/local/bin/alidns.sh
255+
sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
256+
rm alidns.sh
257+
```
258+
259+
测试证书续期:
260+
```bash
261+
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
262+
```
263+
264+
正式续期时去掉 `--dry-run`
265+
```bash
266+
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"
267+
```
268+
269+
设置定时任务:
270+
```bash
271+
crontab -e
272+
```
273+
274+
设置每天凌晨 1 点 1 分执行:
275+
```bash
276+
1 1 */1 * * certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --deploy-hook "nginx -s reload"
277+
```
278+
279+
查询 crontab 执行记录:
280+
```bash
281+
grep CRON /var/log/syslog
282+
```
283+
284+
### CD
285+
`Github Workflow` 为例,实现自动化部署。新建 `.github/workflows/deploy.yml`
286+
```yaml
287+
name: Deploy to Server
288+
289+
on:
290+
push:
291+
branches:
292+
- main
293+
294+
jobs:
295+
deploy:
296+
runs-on: ubuntu-latest
297+
298+
steps:
299+
- name: Checkout code
300+
uses: actions/checkout@v2
301+
302+
- name: Set up SSH
303+
uses: webfactory/[email protected]
304+
with:
305+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
306+
307+
- name: Run deployment script
308+
run: |
309+
ssh -o StrictHostKeyChecking=no user@your-server-ip << 'EOF'
310+
cd /path/to/your/repo
311+
git pull origin main
312+
pnpm install
313+
pnpm run build
314+
pm2 restart your-app-name
315+
EOF
316+
```
317+
318+
新建一个用户用于托管 CD 流程:
319+
```bash
320+
sudo adduser deploy
321+
```
322+
323+
给用户设置某个目录的所有权:
324+
```bash
325+
sudo chown -R deploy:deploy /var/www/html
326+
```
327+
328+
切换至对应用户:
329+
```bash
330+
sudo su - deploy
331+
```
332+
333+
334+
## 服务运维
335+
### 日志
336+
使用 `pm2-logrotate` 来划分 pm2 中的 NestJS 日志
337+
```bash
338+
# 安装 pm2-logrotate
339+
pm2 install pm2-logrotate
340+
```
341+
342+
使日志按每小时划分:
343+
```bash
344+
# 设置日志文件名
345+
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-00-00
346+
pm2 set pm2-logrotate:rotateInterval "0 * * * *"
347+
```
348+
349+
使用自定义的 logger 来实现 ORM 日志按小时划分:
350+
```ts
351+
class CustomLogger implements Logger {
352+
private getLogFileName(): string {
353+
const now = dayjs().set('minute', 0).set('second', 0);
354+
return path.join(LOG_DIR, `ormlogs-${now.format('YYYY-MM-DD_HH-mm-ss')}.log`);
355+
}
356+
357+
// ...
358+
}
359+
```

0 commit comments

Comments
 (0)