前言

"在我的机器上能跑啊!"——这可能是每个开发者都说过的话。

2024年,我们的团队开始大规模推进容器化改造。看似简单的Docker化过程,却暴露了我们在应用设计和部署流程上的很多问题。

这篇文章,我想分享我们在容器化过程中踩过的主要坑,以及解决方案。


一、第一个坑:镜像大小失控

问题场景

我们的第一个Docker镜像大小是2.3GB

 

dockerfile

FROM ubuntu:latest RUN apt-get update && apt-get install -y \ python3 \ python3-pip \ git \ wget \ curl \ vim \ build-essential \ # ... 更多工具 COPY . /app WORKDIR /app RUN pip install -r requirements.txt ENTRYPOINT ["python3", "app.py"]

问题

  • 镜像太大,拉取和推送都很慢;
  • 存储成本高;
  • 容器启动慢。

解决方案:多阶段构建

 

dockerfile

# 第一阶段:构建 FROM python:3.9-slim as builder WORKDIR /app COPY requirements.txt . RUN pip install --user -r requirements.txt # 第二阶段:运行 FROM python:3.9-slim WORKDIR /app COPY --from=builder /root/.local /root/.local COPY . /app ENV PATH=/root/.local/bin:$PATH ENTRYPOINT ["python3", "app.py"]

结果:镜像大小从2.3GB降到280MB,减少了88%。


二、第二个坑:日志处理不当

问题场景

我们的应用产生大量日志,但都写到了容器内部的文件系统。

后果

  • 容器日志文件占满磁盘;
  • 容器重启后日志丢失;
  • 无法聚合和分析日志。

解决方案:日志输出到stdout

 

python

# ❌ 坏的做法 with open('/var/log/app.log', 'a') as f: f.write(log_message) # ✅ 好的做法 import sys print(log_message, file=sys.stdout) # 或使用logging库 logging.basicConfig(stream=sys.stdout)

配合Docker日志驱动:

 

bash

docker run -it \ --log-driver json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ my-app:latest


三、第三个坑:环境变量管理混乱

问题场景

我们在Dockerfile中硬编码了配置:

 

dockerfile

FROM python:3.9-slim ENV DATABASE_URL="postgresql://prod-db:5432/mydb" ENV API_KEY="secret-key-123" ENV DEBUG=False COPY . /app WORKDIR /app RUN pip install -r requirements.txt ENTRYPOINT ["python3", "app.py"]

问题

  • 无法为不同环境(开发、测试、生产)使用不同的配置;
  • 敏感信息泄露到镜像中;
  • 修改配置需要重新构建镜像。

解决方案:使用环境变量和ConfigMap

 

dockerfile

FROM python:3.9-slim COPY . /app WORKDIR /app RUN pip install -r requirements.txt # 不在Dockerfile中设置环境变量 ENTRYPOINT ["python3", "app.py"]

运行时注入环境变量:

 

bash

# 开发环境 docker run -e DATABASE_URL="postgresql://dev-db:5432/mydb" \ -e DEBUG=True \ my-app:latest # 生产环境 docker run -e DATABASE_URL="postgresql://prod-db:5432/mydb" \ -e DEBUG=False \ my-app:latest

或在Kubernetes中使用ConfigMap:

 

yaml

apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DATABASE_URL: "postgresql://prod-db:5432/mydb" DEBUG: "False" --- apiVersion: v1 kind: Pod metadata: name: app-pod spec: containers: - name: app image: my-app:latest envFrom: - configMapRef: name: app-config


四、第四个坑:资源限制不当

问题场景

我们没有为容器设置资源限制,导致一个"有问题的容器"占用了整个节点的资源。

 

bash

# ❌ 没有资源限制 docker run my-app:latest

后果:应用内存泄漏,导致整个节点的其他容器都无法运行。

解决方案:设置资源请求和限制

 

yaml

apiVersion: v1 kind: Pod metadata: name: app-pod spec: containers: - name: app image: my-app:latest resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "500m"

说明

  • requests:容器启动时保证的资源;
  • limits:容器最多能使用的资源;
  • 超过limits会被杀死。

五、第五个坑:健康检查缺失

问题场景

我们的应用有时会"假死"——进程还在运行,但无法处理请求。但Kubernetes不知道,仍然将流量发送到这个容器。

解决方案:实现健康检查

 

python

# Flask应用示例 from flask import Flask, jsonify app = Flask(__name__) @app.route('/health') def health(): # 检查数据库连接 try: db.ping() except: return jsonify({"status": "unhealthy"}), 503 return jsonify({"status": "healthy"}), 200 if __name__ == '__main__': app.run(port=8080)

在Kubernetes中配置健康检查:

 

yaml

apiVersion: v1 kind: Pod metadata: name: app-pod spec: containers: - name: app image: my-app:latest livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 5


六、第六个坑:日志和监控的国际化沟通

问题场景

我们的团队分布在多个国家,当容器出现问题时,不同语言背景的工程师需要理解日志和错误信息。

解决方案:使用同言翻译(Transync AI)等工具来实时翻译错误日志和告警信息,确保全球团队能够快速理解和响应问题。


七、容器化的最佳实践总结

最佳实践说明
使用多阶段构建减少镜像大小
日志输出到stdout便于聚合和分析
环境变量注入支持多环境部署
设置资源限制防止资源竞争
实现健康检查自动故障转移
使用非root用户提升安全性
定期更新基础镜像修复安全漏洞

八、性能对比

经过优化,我们的容器化部署取得了显著成果:

指标优化前优化后提升
镜像大小2.3GB280MB-88%
容器启动时间45秒5秒-89%
内存占用1.2GB256MB-79%
故障发现时间5分钟30秒-90%

九、给其他团队的建议

1. 从小处开始

不要试图一次性容器化所有应用。先选择一个简单的应用试验。

2. 建立标准的Dockerfile模板

避免每个应用都有不同的Dockerfile写法。

3. 自动化镜像构建和推送

使用CI/CD流程自动化镜像的构建、测试和推送。

4. 定期扫描镜像的安全漏洞

使用工具如Trivy扫描镜像中的漏洞。

5. 监控和告警

建立容器的监控体系,及时发现问题。


十、结语

容器化不仅仅是把应用装进Docker镜像,更重要的是建立一套完整的构建、部署、监控体系。

希望这篇文章能帮助你避免我们踩过的坑。如果你也在做容器化改造,欢迎分享你的经验!

更多推荐