【WebWiki】17 · DevOps 与部署
09 DevOps 与部署
后端工程师不止要会写代码,还要能让代码稳定地「跑起来、跑得好、出问题能救」。本章覆盖日常最常用的 Linux 命令、容器化(Docker)、编排(Kubernetes)、反向代理(Nginx)与持续交付(CI/CD)全流程。
1. Linux 常用命令(后端生存包)
服务器上 90% 的问题都能用下面这几组命令定位。建议背熟。
进程与端口
# 查看所有进程(常用组合:按 CPU/内存排序)
ps aux | sort -k3 -rn | head # 按 CPU 占用前 10
ps aux --sort=-%mem | head # 按内存占用前 10
# 实时看进程资源(q 退出)
top
htop # 更友好(需安装)
# 根据端口反查进程(排查“端口被占用”)
netstat -tunlp | grep 8080 # 老机器常用
ss -tunlp | grep 8080 # 新版推荐,更快
lsof -i:8080 # 查看占用 8080 的进程
# 根据进程名查
ps -ef | grep java
# 杀进程(温柔 → 强制)
kill 12345 # SIGTERM,给进程清理机会
kill -9 12345 # SIGKILL,强制(慎用,可能丢数据)
pkill -f 'java -jar app' # 按名字批量杀
# 后台运行 + 日志重定向 + 脱离终端(生产启动 jar 常用)
nohup java -jar app.jar > app.log 2>&1 &
踩坑:
netstat在新版最小化系统可能没装,用ss替代;lsof也常需单独安装(yum install lsof/apt install lsof)。
文件与日志
# 目录与文件
ls -lh # 人类可读大小
ll -ah # 含隐藏文件
du -sh /var/log/* # 各目录占用
df -h # 磁盘分区使用率(排查“磁盘满”)
# 查找
find /opt -name "*.log" # 按名找
find /opt -size +100M # 大于 100M 的文件
find /opt -mtime -1 # 1 天内修改的
locate nginx.conf # 基于索引秒查(先 updatedb)
# 文本搜索(日志排错核心)
grep -n "ERROR" app.log # 带行号
grep -rn "OutOfMemory" /opt/logs # 递归目录
grep -C 5 "Exception" app.log # 上下各 5 行上下文
grep -E "ERROR|WARN" app.log # 正则多关键字
zgrep "timeout" app.log.1.gz # 搜压缩日志
# 实时看日志尾部(线上排查首选)
tail -f app.log # 持续刷新
tail -1000f app.log # 先看最后 1000 行再跟随
# 查看/分页
cat file | less # 分页看大文件
head -20 file
# 编辑
vim app.yml # 常用:i 进入编辑,Esc 后 :wq 保存,:q! 强退
# 压缩与传输
tar -zcvf app.tar.gz /opt/app # 打包
tar -zxvf app.tar.gz # 解包
scp app.jar root@10.0.0.2:/opt/ # 本机→远程
rsync -avz /opt/app/ root@2:/opt/app/ # 增量同步(断点续传友好)
性能三连
# 1) CPU / 负载
uptime # 1/5/15 分钟平均负载(≈核数说明饱和)
top -H -p <pid> # 看某进程的线程级 CPU
# 2) 内存
free -h # 看 available,不要只看 free(cache 可回收)
cat /proc/meminfo
# 3) 磁盘 IO
iostat -x 1 # 看 %util、await(磁盘是否瓶颈)
vmstat 1 # 综合 CPU/内存/IO/上下文切换
df -h # 磁盘剩余
# 网络
ping host
telnet host 3306 # 验证端口连通(无 telnet 用 nc)
nc -zv host 3306
iftop # 实时流量(需装)
排错思路:接口超时先
uptime/free/df三连排除资源瓶颈;再ss -tunlp看端口监听;再tail -f看应用日志;最后iostat看是不是磁盘 IO 拖垮。
1.1、Shell 脚本实战(运维自动化)
把重复操作写成脚本,避免手抖。一个「自动备份 + 清理旧备份」的示例:
#!/bin/bash
# backup.sh —— 每日凌晨备份 MySQL 并保留 7 天
set -e # 任何命令失败立即退出
BACKUP_DIR=/data/backup
DATE=$(date +%Y%m%d_%H%M%S)
DB_USER=root
DB_PASS='YourPass'
mkdir -p "$BACKUP_DIR"
echo "[$(date)] 开始备份..."
mysqldump -u"$DB_USER" -p"$DB_PASS" --single-transaction --all-databases \
| gzip > "$BACKUP_DIR/all_$DATE.sql.gz"
echo "[$(date)] 备份完成: $BACKUP_DIR/all_$DATE.sql.gz"
# 删除 7 天前的备份
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete
echo "[$(date)] 清理 7 天前备份完成"
chmod +x backup.sh
# 加入定时任务:每天 2:30 执行
crontab -e
# 30 2 * * * /opt/scripts/backup.sh >> /data/backup/backup.log 2>&1
常用
crontab格式:分 时 日 月 周 命令。如0 */2 * * *每两小时;*/5 * * * *每 5 分钟。
另一个「检测服务存活,挂了自动拉起」的守护脚本:
#!/bin/bash
# watchdog.sh —— 检测 8080 端口,挂了就重启
PORT=8080
if ! ss -tunlp | grep -q ":$PORT"; then
echo "[$(date)] 服务 $PORT 未监听,尝试重启"
systemctl restart myapp
# 也可发告警:curl -X POST https://hook/alert -d "服务宕机"
fi
2. Docker 核心用法
Docker 把应用及其依赖打包成镜像(Image),运行起来叫容器(Container),实现「一次构建,处处运行」。
2.1、核心概念
- 镜像 Image:只读模板(类似安装盘),由一层层只读层组成;
- 容器 Container:镜像的运行实例,可读写层在镜像之上;
- 仓库 Registry:存镜像的地方(Docker Hub、阿里云 ACR、Harbor);
- Volume:数据卷,把容器里数据持久化到宿主机,避免容器删了数据没;
- Network:容器间通信网络(bridge/host/none)。
2.2、日常命令
# 镜像
docker images # 列出本地镜像
docker pull mysql:8.0 # 拉取
docker build -t myapp:1.0 . # 当前目录 Dockerfile 构建
docker rmi myapp:1.0 # 删镜像
docker tag myapp:1.0 registry.com/myapp:1.0 # 打标签(推仓库用)
# 容器
docker run -d -p 8080:8080 --name myapp myapp:1.0 # 后台启动并映射端口
docker ps # 运行中的容器
docker ps -a # 含已退出的
docker logs -f myapp # 看日志
docker exec -it myapp bash # 进容器终端排错
docker stop myapp && docker rm myapp
docker rm -f $(docker ps -aq) # 清掉所有容器(慎用)
# 资源与清理
docker stats # 实时看容器 CPU/内存
docker system df # 镜像/容器/卷占用
docker system prune -a # 清掉无用镜像、容器(释放空间)
2.3、数据卷与网络
# 挂载数据卷(MySQL 数据持久化)
docker run -d -p 3306:3306 \
-v /data/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql mysql:8.0
# 自定义网络,让容器用名字互访
docker network create mynet
docker run -d --network mynet --name redis redis:7
docker run -d --network mynet --name app myapp:1.0 # app 内可直接 ping redis
docker-compose.yml —— 本地开发环境标准配置
一条 docker-compose up 拉起整套依赖(MySQL + Redis + 应用),免去找各安装包。
version: "3.8"
services:
mysql:
image: mysql:8.0
container_name: dev-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: demo
ports:
- "3306:3306"
volumes:
- ./mysql-data:/var/lib/mysql # 数据持久化到本地
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
redis:
image: redis:7
container_name: dev-redis
ports:
- "6379:6379"
volumes:
- ./redis-data:/data
app:
build: ./app # 用 ./app/Dockerfile 构建
container_name: dev-app
depends_on:
- mysql
- redis
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/demo
SPRING_REDIS_HOST: redis
networks:
- default
# 启动:docker-compose up -d 停止:docker-compose down 看日志:docker-compose logs -f app
depends_on只保证启动顺序,不保证 MySQL 已「就绪可连」。应用需自身带重试连接;或用healthcheck+depends_on: condition: service_healthy做就绪等待。
3. Java 应用镜像化
Dockerfile —— 多阶段构建,产物小、层次缓存友好
# ---- 阶段一:构建 ----
FROM maven:3.8-openjdk-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline # 先下依赖,利用层缓存(改代码不重下)
COPY src ./src
RUN mvn package -DskipTests -o
# ---- 阶段二:运行(只拿 jar,镜像不含 maven/jdk 编译环境)----
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=build /build/target/*.jar app.jar
# 用非 root 用户跑,安全
RUN useradd -m appuser && chown -R appuser /app
USER appuser
EXPOSE 8080
# 加上时区、JVM 调优
ENV TZ=Asia/Shanghai
ENTRYPOINT ["java", "-Xms256m", "-Xmx512m", "-Duser.timezone=Asia/Shanghai", "-jar", "app.jar"]
多阶段构建好处:最终镜像只含 JRE + jar,体积从 1G+ 降到 200M 左右,且不含源码与构建工具,更安全。
配合.dockerignore跳过无关文件,加速构建、减小上下文:
# .dockerignore
target
.git
*.md
Dockerfile
构建与运行:
docker build -t myapp:1.0 .
docker run -d -p 8080:8080 --name myapp myapp:1.0
镜像优化小贴士:基础镜像用
slim/alpine;COPY顺序把不常变的放前面以复用缓存层;尽量RUN合并、清理 apt 缓存;生产可考虑distroless或jlink定制极小运行时。
4. Kubernetes 核心对象
当容器多了、要扩缩容、要自愈,就用 Kubernetes(K8s)做编排。它把多个 Docker 主机组成一个集群统一调度。
4.1、核心对象
| 对象 | 作用 |
|---|---|
| Pod | 最小调度单位,包含一个或多个紧密协作的容器(共享网络/存储) |
| Deployment | 管理 Pod 副本数与滚动更新(声明式:要 3 个副本,K8s 维持) |
| Service | 给一组 Pod 提供稳定访问入口与负载均衡(ClusterIP/NodePort/LoadBalancer) |
| Ingress | 七层路由,把外部域名/路径转发到 Service(替代手写 Nginx) |
| ConfigMap | 配置(非敏感),挂载为文件或环境变量 |
| Secret | 敏感配置(密码/token),base64 存储 |
| Namespace | 资源逻辑隔离(dev/test/prod) |
| PersistentVolume | 持久化存储 |
4.2、示例:部署一个 Java 应用
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: prod
spec:
replicas: 3 # 3 个 Pod 副本
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: registry.com/myapp:1.0
ports:
- containerPort: 8080
resources:
requests: { cpu: "100m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }
readinessProbe: # 就绪探针:能接流量才进 Service
httpGet: { path: /health, port: 8080 }
initialDelaySeconds: 10
livenessProbe: # 存活探针:失败则重启 Pod
httpGet: { path: /health, port: 8080 }
periodSeconds: 15
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
namespace: prod
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: ClusterIP
kubectl apply -f deployment.yaml -f service.yaml
kubectl get pods -n prod
kubectl logs -f deploy/myapp -n prod
kubectl scale deploy/myapp --replicas=5 -n prod # 扩缩容
kubectl set image deploy/myapp myapp=registry.com/myapp:2.0 -n prod # 滚动更新
kubectl rollout undo deploy/myapp -n prod # 回滚
探针很重要:没有
readinessProbe,Pod 一启动就接流量,可能还没初始化完就报错;没有livenessProbe,假死(线程卡死但进程在)不会被重启。
5. Nginx 常用配置
Nginx 是高性能 Web 服务器 / 反向代理 / 负载均衡器。后端最常用它做「反向代理 + 负载均衡 + 静态资源 + HTTPS」。
5.1、反向代理(把请求转发给后端)
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://127.0.0.1:8080; # 转发到本地 Java 应用
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;
}
}
5.2、负载均衡(upstream 多节点)
upstream backend {
# 默认轮询;weight 加权;ip_hash 按 IP 粘滞(会话保持)
server 10.0.0.1:8080 weight=2;
server 10.0.0.2:8080 weight=1;
server 10.0.0.3:8080 backup; # 备份节点,主全挂才上
# server 10.0.0.4:8080 down; # 临时摘流
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
负载均衡策略:
round-robin(轮询,默认)、weight(加权)、ip_hash(同 IP 落同节点,解决无状态 Session 问题)、least_conn(转给连接最少的)、hash $request_uri(按 URL 一致性哈希,配合缓存命中)。
5.3、HTTPS / SSL 配置
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://backend;
}
}
# HTTP 强制跳 HTTPS
server {
listen 80;
server_name www.example.com;
return 301 https://$host$request_uri;
}
5.4、静态资源、缓存与 gzip
server {
listen 80;
location /static/ {
root /data/www; # 实际路径 /data/www/static/...
expires 30d; # 浏览器缓存 30 天
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://backend;
}
# 开启 gzip,省流量
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 1k;
}
5.5、限流与 location 匹配
# 限流:每 IP 每秒 10 次
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
server {
location /api/ {
limit_req zone=one burst=20 nodelay; # 突发 20 允许,其余 503
proxy_pass http://backend;
}
}
location匹配优先级(高频考点):=精确 >^~前缀 >~/~*正则 > 普通前缀。例如location = /只匹配根,location /api前缀匹配,location ~ \.php$正则。
改完配置:
nginx -t校验语法 →nginx -s reload热加载(不中断连接)。
6. CI/CD 流水线
CI(持续集成):频繁合代码 + 自动构建测试;CD(持续交付/部署):自动打包、部署到各环境。目标是「小步快跑、出问题快回滚」。

6.1、Jenkins 流水线(Pipeline as Code)
Jenkinsfile 把流水线写成代码,随仓库走:
pipeline {
agent any
environment {
REGISTRY = 'registry.com'
}
stages {
stage('拉代码') {
steps { git 'https://github.com/team/app.git' }
}
stage('构建测试') {
steps {
sh 'mvn clean package -DskipTests=false'
}
}
stage('单元测试') {
steps { sh 'mvn test' }
}
stage('构建镜像') {
steps {
sh "docker build -t $REGISTRY/myapp:${BUILD_NUMBER} ."
sh "docker push $REGISTRY/myapp:${BUILD_NUMBER}"
}
}
stage('部署到测试环境') {
steps {
sh "kubectl set image deploy/myapp myapp=$REGISTRY/myapp:${BUILD_NUMBER} -n test"
}
}
stage('人工确认') {
steps { input message: '确认发布到生产?' } // 卡点,需人点
}
stage('部署生产') {
steps {
sh "kubectl set image deploy/myapp myapp=$REGISTRY/myapp:${BUILD_NUMBER} -n prod"
}
}
}
post {
failure { echo '流水线失败,发钉钉/邮件告警' }
success { echo '发布成功' }
}
}
Jenkins 关键概念:Master/ Agent(构建节点)、Stage/Step、凭据管理(Credentials 存密码/Token,不要在 Jenkinsfile 明文写)、Webhook(Git 推送触发构建)。
6.2、GitHub Actions 示例(更轻量)
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build & Test
run: mvn clean verify
- name: Login & Push Image
run: |
docker build -t registry.com/myapp:${{ github.sha }} .
docker push registry.com/myapp:${{ github.sha }}
6.3、完整 CI/CD 流程示例
开发者 push 代码
→ Git 仓库 Webhook 触发 Jenkins
→ 阶段1 拉代码 + Maven 编译 + 单测(失败即红,阻断)
→ 阶段2 打 Docker 镜像 + 推镜像仓库(标签用 commit id / 构建号)
→ 阶段3 部署到 test 命名空间(K8s)
→ 自动化接口测试 / 人工验收
→ 阶段4 人工卡点确认
→ 阶段5 滚动更新到 prod(kubectl set image,零停机)
→ 阶段6 健康检查 + 监控观察;异常一键回滚(kubectl rollout undo)
7. 监控告警体系
「能跑」还不够,要「看得清、出了事能马上知道」。
- 指标监控:Prometheus 定时拉取各组件
/metrics指标,Grafana 画图看板(CPU、QPS、RT、JVM、容器资源)。 - 日志:ELK(Elasticsearch + Logstash + Kibana)或 Loki 集中收集,按
level=ERROR检索、TraceId 串联链路。 - 链路追踪:SkyWalking / Zipkin,定位跨服务慢调用。
- 告警:Prometheus Alertmanager / 夜莺 / Grafana Alert 触发,通知到钉钉、企业微信、电话。常见阈值:CPU > 85% 持续 5min、接口错误率 > 1%、P99 > 1s、磁盘 > 90%、容器重启次数突增。
- 健康检查:应用暴露
/health(liveness/readiness),K8s 探针 + Nginx 健康检查联动。
黄金四指标:延迟(Latency)、流量(Traffic)、错误(Errors)、饱和度(Saturation)——所有监控看板围绕这四件事设计。
8. 一个典型上线流程
把前面所有能力串起来,一次规范的互联网服务上线长这样:
- 开发:本地
docker-compose起依赖,写完代码 + 单测,push 到 Git 分支并发 MR; - CI:MR 合入 main 触发流水线,编译 + 单测 + 代码扫描,挂了打回;
- 镜像:通过后打镜像推仓库,镜像扫描(Trivy)查漏洞;
- 预发/测试环境:自动部署到 test 命名空间,跑接口/回归测试;
- 审批:测试通过后,流水线在「生产发布」阶段人工卡点,值班确认;
- 生产发布:
kubectl set image滚动更新(先起新 Pod,就绪探针通过后切流量,再下旧 Pod),零停机; - 观察:Grafana 看 RT/错误率/资源,日志查异常;前 30 分钟重点盯盘;
- 回滚预案:异常时
kubectl rollout undo秒级回退,或切 Nginx upstream 摘流; - 复盘:如有故障,记录时间线、根因、改进项。
上线三原则:可回滚(任何发布都必须能快速回退)、可灰度(先小流量再全量)、可观测(发布前后指标对比)。没有这三样的发布就是「裸奔」。
9. 小结
- Linux:
ps/ss/lsof/top/free/df/tail/grep+crontab脚本化是后端日常; - Docker:镜像/容器/卷/网络四件套,多阶段 Dockerfile 让 Java 镜像又小又安全;
- K8s:Deployment/Service/Ingress/ConfigMap 编排,探针保障自愈,滚动更新零停机;
- Nginx:反向代理 + upstream 负载均衡 + SSL + 限流 + gzip,是流量入口标准答案;
- CI/CD:Jenkins/GitHub Actions 把「构建-测试-打包-部署-回滚」自动化,配合监控告警形成闭环;
- 上线本质是「可回滚、可灰度、可观测」的工程纪律,工具只是手段。

浙公网安备 33010602011771号