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

5.0 KiB

tags, create time
tags create time
后端
部署
运维
基础
2026-04-24 18:41

部署与运维基础

概述

写完代码只是第一步,让代码在生产环境中稳定运行才是真正的工作。部署与运维涵盖了从构建、容器化、反向代理到监控的所有环节。

思考题:为什么本地运行正常的代码,部署到服务器就出问题?最常见的坑有哪些?

正文

1. 环境变量 — 环境差异的桥梁

# 不同环境配置不同的变量
# .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 中读取环境变量
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 — 反向代理与负载均衡

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";
    }
}
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 — 容器化部署

# 多阶段构建(减小镜像体积)
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"]
# 构建镜像
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 — 多服务编排

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)基础

# .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. 常用运维命令

# 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  # 内存分析

关联笔记