Skip to content

Commit

Permalink
chore: exit code 1
Browse files Browse the repository at this point in the history
  • Loading branch information
lvqq committed Dec 8, 2024
1 parent 075be73 commit 0debafa
Show file tree
Hide file tree
Showing 2 changed files with 360 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"start": "pnpm dev",
"build:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider vuepress build src --dest dist",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vuepress build src --dest dist",
"postbuild": "bash -c '[ -z \"$VERCEL\" ] && mv -f ./dist/* /var/www/html/blog/'"
"postbuild": "bash -c '[ -z \"$VERCEL\" ] && mv -f ./dist/* /var/www/html/blog/ || true'"
},
"engines": {
"node": ">=18.0.0"
Expand Down
359 changes: 359 additions & 0 deletions src/_posts/Server/02-deploy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
---
category: Server
tags:
- Full Stack
date: 2024-12-07
title: 全栈项目从上线、部署到运维
vssue-title: 全栈项目从上线、部署到运维
---

本文主要记录了全栈项目上线、部署、运维的整个流程,仅供参考

<!-- more -->

## 基本信息

### 项目选型
- React
- NestJS
- MySQL

### 服务器
- 阿里云 ECS
- Debain 10.13

## 环境安装

### Git
安装 git:
```bash
sudo apt update
sudo apt install git
```

生成 ssh key 后配置到 Github 中:
```bash
ssh-keygen -t ed25519 -C "youremail@email.com"
```

### MySQL
下载 MySQL 5.7,或者前往[官网](https://downloads.mysql.com/archives/community/)寻找合适的版本:
```bash
curl -OL https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
```

然后解压缩:
```bash
sudo tar -xzf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz -C /usr/local
```

重命名目录:
```bash
cd /user/local
sudo mv mysql-5.7.44-linux-glibc2.12-x86_64 mysql
```

创建 MySQL 用户和组:
```bash
sudo groupadd mysql
sudo useradd -r -g mysql -s /bin/false mysql
```

初始化数据库:
```bash
cd /usr/local/mysql
sudo mkdir mysql-files
sudo chmod 750 mysql-files
sudo chown -R mysql:mysql ./
sudo bin/mysqld --initialize --user=mysql
```

此时终端中会显示随机生成的密码:
```
[Note] A temporary password is generated for root@localhost: %sqwtmz5p(Xe
```

设置权限和目录:
```bash
sudo chown -R root .
sudo chown -R mysql data mysql-files
```

安装启动脚本:
```bash
sudo cp support-files/mysql.server /etc/init.d/mysql
sudo chmod +x /etc/init.d/mysql
sudo update-rc.d mysql defaults
```

启动 MySQL 服务:
```bash
sudo systemctl start mysql
```

查询 MySQL 服务状态:
```bash
sudo systemctl status mysql
```

修改密码:
```bash
# 登录 root
mysql -u root -p

# 执行 SQL
ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';
```

### MySQL 远程连接
创建一个新的用户用于远程连接:
```bash
# % 表示任意地址,也可以指定具体的 ip
CREATE USER 'remote'@'%' IDENTIFIED BY 'newpassword'
```

授予权限:
```bash
# 所有数据库:
GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%';

# 特定数据库
GRANT ALL PRIVILEGES ON exampledb.* TO 'newuser'@'%';
```

刷新权限:
```bash
FLUSH PRIVILEGES;
```

配置 MySQL 允许远程连接,编辑或新建 `/etc/mysql/my.cnf``/etc/my.cnf`
```bash
[mysqld]
bind-address = 0.0.0.0
```

然后重启 MySQL 服务:
```bash
sudo systemctl restart mysql
```

### NodeJS
安装 nvm 来管理 NodeJS 版本,官方的安装方式对于网络连通性有要求,采用下面的方法:
```bash
git clone https://github.com/nvm-sh/nvm.git
bash nvm/install.sh
```

安装 NodeJS 20:
```bash
nvm install 20
```

设置 npm 镜像:
```bash
echo 'registry=https://registry.npmmirror.com/' > ~/.npmrc
```

### Nginx
安装 Nginx:
```bash
sudo apt install nginx
```

## 服务部署
### NodeJS 服务
使用 `pm2` 来启动 NodeJS 服务:
```bash
pm2 start ecosystem.config.js --env production
```

配置文件示例:
```js
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'my-app',
script: 'dist/main.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};
```

### Nginx
配置 Nginx 转发服务端接口:
```bash
cd /etc/nginx/sites-available/
vi api.myhost.com
```

配置文件中添加:
```nginx
server {
listen 80;
server_name api.myhost.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
新建软连接以启动对应配置:
```bash
sudo ln -s /etc/nginx/sites-available/api.myhost.com /etc/nginx/sites-enabled/
```

重启 Nginx 应用配置:
```bash
sudo systemctl restart nginx
```

配置 Nginx 转发前端静态资源,流程和前面一致,仅 Nginx 配置略有不同:
```nginx
server {
listen 80;
server_name www.example.com;
root /root/projects/example/dist;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
```

### HTTPS 证书申请
通过 certbot 申请 SSL 证书,安装对应 pkg:
```bash
sudo apt install certbot python3-certbot-nginx
```

根据提示完成配置,将自动下载证书,完成 nginx 配置并重启:
```bash
sudo certbot --nginx -d api.myhost.com
```

证书有效期只有 3 个月,可以通过脚本实现自动续签,参考 [certbot-dns-aliyun](https://github.com/justjavac/certbot-dns-aliyun)
```bash
# 安装 certbot-dns-aliyun
wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
sudo cp alidns.sh /usr/local/bin
sudo chmod +x /usr/local/bin/alidns.sh
sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
rm alidns.sh
```

测试证书续期:
```bash
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
```

正式续期时去掉 `--dry-run`
```bash
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"
```

设置定时任务:
```bash
crontab -e
```

设置每天凌晨 1 点 1 分执行:
```bash
1 1 */1 * * certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --deploy-hook "nginx -s reload"
```

查询 crontab 执行记录:
```bash
grep CRON /var/log/syslog
```

### CD
`Github Workflow` 为例,实现自动化部署。新建 `.github/workflows/deploy.yml`
```yaml
name: Deploy to Server

on:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up SSH
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

- name: Run deployment script
run: |
ssh -o StrictHostKeyChecking=no user@your-server-ip << 'EOF'
cd /path/to/your/repo
git pull origin main
pnpm install
pnpm run build
pm2 restart your-app-name
EOF
```
新建一个用户用于托管 CD 流程:
```bash
sudo adduser deploy
```

给用户设置某个目录的所有权:
```bash
sudo chown -R deploy:deploy /var/www/html
```

切换至对应用户:
```bash
sudo su - deploy
```


## 服务运维
### 日志
使用 `pm2-logrotate` 来划分 pm2 中的 NestJS 日志
```bash
# 安装 pm2-logrotate
pm2 install pm2-logrotate
```

使日志按每小时划分:
```bash
# 设置日志文件名
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-00-00
pm2 set pm2-logrotate:rotateInterval "0 * * * *"
```

使用自定义的 logger 来实现 ORM 日志按小时划分:
```ts
class CustomLogger implements Logger {
private getLogFileName(): string {
const now = dayjs().set('minute', 0).set('second', 0);
return path.join(LOG_DIR, `ormlogs-${now.format('YYYY-MM-DD_HH-mm-ss')}.log`);
}

// ...
}
```

0 comments on commit 0debafa

Please sign in to comment.