只有3个开发,别碰K8s!单机Docker救了我们的命

我曾以为拥抱云原生就是要在第一时间上 Kubernetes(K8s),搞微服务,弄Service Mesh。直到2021年,我带着一个5人的技术团队,因为盲目上K8s,在某次大促前夕,因为Etcd集群的一个节点故障导致整个控制面瘫痪,我们修了整整一夜,业务停摆了6个小时。

那个凌晨4点,看着依然红一片的监控面板,我意识到一个残酷的真相:对于没有专职运维的中小团队,复杂的架构不是护城河,而是随时会爆炸的地雷。

也就是从那时起,我开始推行"极简容器化"策略。今天想和大家复盘一下,我们是如何仅靠单机Docker和Docker Compose,就解决了90%的运维痛点,让团队从此告别"在我电脑上明明能运行"的扯皮。

拒绝过度设计:Docker Compose 才是中小团队的瑞士军刀

很多技术负责人(包括曾经的我)都有"大厂崇拜症"。看到大厂都在用K8s,觉得自己不用就落伍了。但现实是,你的业务量可能连单机32G内存都跑不满,却要花一半的服务器资源去跑K8s的组件。

观点: 只要你的机器数量还在个位数,Docker Compose 就足够了。它能解决服务编排、网络隔离、一键拉起,而且配置文件简单到连刚入职的实习生都能看懂。

真实案例: 2022年,我接手了一个SaaS项目,前任留下了3套环境(开发、测试、生产),部署全靠文档里的20多步手动命令。每次发版,后端老张都要盯着屏幕敲半小时命令,少敲一个参数就报错。

我接手后的第一件事,不是重构代码,而是写了一个 docker-compose.yml

我们将Nginx、API服务、Redis、MySQL全部编排进去。

改造结果:

  • 部署时间: 从30分钟缩短到3分钟。
  • 事故率: 因环境配置不一致导致的Bug归零。
  • 硬件成本: 退订了专门用于跑K8s管理节点的2台服务器,每月省下1000多块。

硬核方法: 不要把数据库放在物理机,服务放在Docker里,要"全员容器化"。包括你的Nginx网关、定时任务脚本。这是我用了很多年的一个原则:除了Docker Daemon和SSH,宿主机上不要安装任何业务软件。

统一开发环境:终结"环境不一致"的内耗

除了部署,Docker在开发阶段的价值被严重低估了。你一定经历过新人入职,光是配环境就要花2天时间:Python版本不对、Node依赖冲突、本地Redis没启动…

观点: 开发环境即生产环境。让Docker接管本地开发流程,是提升团队效率最立竿见影的手段。

真实场景: 去年团队扩招,来了个前端小李。以前新人入职,我要专门派个老员工指导他装环境。这次,我只丢给他一个Git仓库地址,说了一句:“Clone下来,运行 make dev。”

小李很惊讶,因为这行命令背后,执行了 docker-compose -f docker-compose.dev.yml up。15分钟后,所有依赖(包括不仅限于数据库、消息队列、模拟的第三方服务Mock)全部在他的Macbook上跑了起来,热更新功能也配置好了。

落地细节: 为了让大家少敲命令,我强制要求每个项目根目录必须有一个 Makefile。这不仅是偷懒,更是将操作"标准化"。

# Makefile 示例
.PHONY: dev build deploy

dev:
    # 本地开发模式,挂载源代码
    docker-compose -f docker-compose.yml -f docker-compose.override.yml up

build:
    # 构建生产镜像
    docker build -t my-app:latest .

shell:
    # 快速进入容器调试
    docker-compose exec app /bin/bash

这套机制运行了两年,最大的好处是:开发人员再也不用在本地安装乱七八糟的语言环境了,电脑干干净净。

穷人的CI/CD:Shell脚本+Git Hook足够用

说到自动化部署,很多人第一反应是搭建Jenkins,或者配置复杂的GitLab CI Runner。这些都很棒,但对于只有两三个后端的小团队,维护Jenkins本身就是负担。

观点: 在资源受限时,越原始的工具越可靠。一个精心编写的Shell脚本,配合Git,就是最稳健的CD系统。

实操复盘: 我们目前的生产环境部署,并没有用昂贵的商业CI/CD工具。我们的流程简单到令人发指,但极其稳定:

  1. 本地构建: 开发者本地(或一台专门的构建机)Build镜像,推送到私有仓库(阿里云/腾讯云的免费版镜像仓库就很好用)。
  2. 触发更新: 通过SSH登录到目标服务器,执行一个部署脚本。

为了防止误操作,我写了一个 deploy.sh,放在服务器上。

#!/bin/bash
# 简单的零停机更新策略(虽然会有短暂中断,但对小业务可接受)

IMAGE_NAME="registry.cn-hangzhou.aliyuncs.com/myteam/backend:latest"

echo "Step 1: Pulling latest image..."
docker pull $IMAGE_NAME

echo "Step 2: Stopping old container..."
docker-compose down

![配图](https://picsum.photos/800/450?random=1768390391607)

echo "Step 3: Starting new container..."
docker-compose up -d

echo "Step 4: Pruning unused images..."
docker image prune -f

echo "Deployment Done!"

你可能会质疑:这不还是会停机吗? 是的,docker-compose downup 会有几秒的中断。但请扪心自问:你的业务真的每秒都有几百万上下吗?如果是在深夜低峰期发布,或者配合Nginx的重试机制,这几秒钟用户根本无感。

反思: 我们曾尝试搞蓝绿部署,配置了一堆复杂的Nginx Lua脚本,结果因为配置错误导致流量切不过去。后来回退到这个"笨办法",反而再没出过岔子。技术选型要匹配团队的掌控力,而不是匹配PPT的酷炫程度。

总结与落地指南

小团队做容器化,核心不在于"技术先进性",而在于"可维护性"。单机Docker + Docker Compose + Shell脚本,这个组合就像一把AK47,结构简单、皮实耐用,哪怕扔进泥潭里捞出来还能打响。

如果你现在正被繁杂的运维工作缠身,建议按以下步骤行动:

  1. 第一周: 挑选一个边缘服务(如内部管理后台),编写 Dockerfiledocker-compose.yml,跑通本地运行。
  2. 第二周: 编写 Makefile,将启动、停止、日志查看等高频操作封装成命令,强迫团队使用。
  3. 第三周: 购买一个云厂商的容器镜像服务(很多都有免费额度),打通"本地构建 -> 推送镜像 -> 服务器拉取"的流程。

最后,分享一个我常用的 Dockerfile 黄金模板(以Node.js为例),直接复制微调即可避开很多坑(如时区、权限问题):

# 使用具体版本号,别用 latest
FROM node:18-alpine 

# 设置时区,防止日志时间差8小时
RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

WORKDIR /app

# 分层构建技巧:先拷 package.json,利用缓存加速
COPY package*.json ./
RUN npm ci --only=production

COPY . .

# 不要用 root 用户运行应用
USER node

![配图](https://picsum.photos/800/450?random=1768390394652)

CMD ["node", "src/index.js"]

记住,DevOps的尽头不是K8s,而是早点下班。