This repository has been archived on 2026-05-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
obsidian/BACKEND/部署与运维基础.md
T

225 lines
5.0 KiB
Markdown
Raw Normal View History

2026-04-24 23:45:19 +08:00
---
tags: [后端, 部署, 运维, 基础]
create time: 2026-04-24 18:41
---
# 部署与运维基础
## 概述
写完代码只是第一步,让代码在生产环境中稳定运行才是真正的工作。部署与运维涵盖了从构建、容器化、反向代理到监控的所有环节。
思考题:为什么本地运行正常的代码,部署到服务器就出问题?最常见的坑有哪些?
## 正文
### 1. 环境变量 — 环境差异的桥梁
```bash
# 不同环境配置不同的变量
# .env.production
DATABASE_HOST=db.production.com
DATABASE_PORT=5432
DATABASE_USER=admin
DATABASE_PASSWORD=secret
JWT_SECRET=very-long-secret-key
PORT=8080
LOG_LEVEL=warn
```
```go
// Go 中读取环境变量
import "os"
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080" // 默认值
}
logLevel := os.Getenv("LOG_LEVEL")
// ...
}
```
> **核心原则:** 12-Factor App 原则——配置必须存储在环境变量中,绝不能硬编码到代码里。同一份代码,换环境只需换变量。
> **提问:** 为什么数据库密码不能写在代码里或提交到 Git?`.env` 文件应该加入 `.gitignore` 吗?
### 2. Nginx — 反向代理与负载均衡
```nginx
server {
listen 80;
server_name api.example.com;
# 反向代理到 Go 服务
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 前端静态文件
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html; # SPA 路由支持
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
```
```mermaid
sequenceDiagram
participant C as 客户端
participant N as Nginx:80
participant G as Go:8080
participant F as 静态文件
C->>N: GET /api/users
N->>G: proxy_pass → :8080/api/users
G-->>N: JSON 响应
N-->>C: 返回数据
C->>N: GET /index.html
N->>F: 读取本地文件
F-->>N: HTML 文件
N-->>C: 返回页面
```
> **思考:** Nginx 既能做反向代理又能提供静态文件服务。为什么要把 API 和前端静态文件放在一起部署,而不是分开?
### 3. Docker — 容器化部署
```dockerfile
# 多阶段构建(减小镜像体积)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
# 最终镜像
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
# 安全:不用 root 运行
RUN adduser -D appuser
USER appuser
CMD ["./server"]
```
```bash
# 构建镜像
docker build -t myapp:latest .
# 运行容器
docker run -d \
--name myapp \
-p 8080:8080 \
-e DATABASE_HOST=db \
-e JWT_SECRET=secret \
myapp:latest
```
### 4. Docker Compose — 多服务编排
```yaml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_HOST=postgres
- DATABASE_PORT=5432
- DATABASE_USER=postgres
- DATABASE_PASSWORD=secret
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
restart: unless-stopped
volumes:
pgdata:
```
### 5. 持续集成/持续部署(CI/CD)基础
```yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to registry
run: |
docker tag myapp:${{ github.sha }} registry.example.com/myapp:${{ github.sha }}
docker push registry.example.com/myapp:${{ github.sha }}
- name: Deploy to server
run: ssh deploy@server "docker pull registry.example.com/myapp:${{ github.sha }} && docker-compose up -d"
```
### 6. 常用运维命令
```bash
# Docker 常用
docker ps # 查看运行中的容器
docker logs -f myapp # 查看容器日志
docker exec -it myapp sh # 进入容器
docker-compose up -d # 启动所有服务
# Go 服务
kill -SIGTERM $(pgrep server) # 优雅停止
go tool pprof http://localhost:6060/debug/pprof/heap # 内存分析
```
## 关联笔记
- [[Go 后端基础]] — Go 应用的代码实现
- [[API 设计]] — 部署的 API 需要按规范设计
- [[30.areas/finance/Investment lessons/2024.Current trading lessons.md]]