Docker容器化技术现在已经非常流行了几乎每个开发者都在用Docker来搭建开发环境部署应用但是很多人只是会简单地用Docker跑个容器对Docker容器化部署的完整流程从开发到测试到生产没有太多的了解导致部署的时候经常遇到各种问题比如环境不一致配置管理混乱版本管理不清等等。

其实Docker容器化部署有一套完整的流程和最佳实践掌握了这些能让部署更高效更稳定更可靠。我用Docker做容器化部署很多年了从开发环境到生产环境都有丰富的经验踩了很多坑也总结了很多经验今天就来分享一下Docker容器化部署的实战经验从开发到生产的完整流程全面分享希望能帮大家更好地使用Docker做好容器化部署。

一、Docker容器化部署的优势

先说说为什么要用Docker做容器化部署它有哪些优势。

1. 环境一致性

Docker最大的优势就是环境一致性把应用和它的运行环境一起打包成镜像不管在开发环境测试环境还是生产环境运行的都是同一个镜像环境完全一致不会出现"在我机器上能跑"的问题这大大减少了因为环境不一致导致的bug和问题。

2. 快速部署

Docker部署非常快镜像已经打包好了应用和环境只需要拉取镜像启动容器就能运行不需要再安装依赖配置环境等等部署时间从几小时缩短到几分钟甚至几秒大大提高了部署效率。

3. 隔离性好

Docker容器之间是隔离的每个容器有自己的文件系统网络进程空间互不影响一个容器出问题不会影响其他容器也不会影响宿主机安全性和稳定性都很好。

4. 资源利用率高

Docker容器共享宿主机的内核资源占用很少启动很快一台服务器能跑很多容器资源利用率很高比虚拟机节省很多资源也节省成本。

5. 易于扩展和迁移

Docker容器很容易扩展需要更多实例的时候只需要启动更多容器就行也很容易迁移把镜像传到另一台服务器启动容器就行不需要重新配置环境很方便。

二、开发环境的容器化

Docker容器化部署的第一步是开发环境的容器化让开发人员在本地用Docker搭建一致的开发环境。

1. Dockerfile编写

首先要为应用编写Dockerfile定义应用的运行环境和构建过程比如一个PHP应用的Dockerfile:

FROM php:7.4-fpm

# 安装依赖
RUN apt-get update && apt-get install -y \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libzip-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd pdo_mysql zip opcache

# 安装redis扩展
RUN pecl install redis && docker-php-ext-enable redis

# 设置工作目录
WORKDIR /var/www/html

# 复制代码
COPY . /var/www/html

# 设置权限
RUN chown -R www-data:www-data /var/www/html

# 暴露端口
EXPOSE 9000

# 启动php-fpm
CMD ["php-fpm"]

Dockerfile要注意这些:

  • 基础镜像要选择合适的版本不要用latest要用具体的版本号。
  • 尽量减少镜像层数合并RUN指令减少镜像大小。
  • 利用构建缓存把不经常变的步骤放在前面经常变的步骤放在后面提高构建速度。
  • 清理不需要的文件和缓存减少镜像大小。
  • 不要在镜像里放敏感信息比如密码密钥等等要通过环境变量或者配置文件注入。

2. docker-compose编排

开发环境一般有多个服务比如Web服务器PHPMySQLRedis等等用docker-compose来编排这些服务很方便。

docker-compose.yml示例:

version: '3'
services:
  nginx:
    image: nginx:1.21
    ports:
      - "80:80"
    volumes:
      - ./:/var/www/html
      - ./docker/nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - php
    networks:
      - app-network

  php:
    build: ./docker/php
    volumes:
      - ./:/var/www/html
    networks:
      - app-network

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
      MYSQL_USER: app
      MYSQL_PASSWORD: app
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - app-network

  redis:
    image: redis:6
    ports:
      - "6379:6379"
    networks:
      - app-network

networks:
  app-network:

volumes:
  mysql_data:

开发环境的docker-compose要注意:

  • 代码目录要挂载到容器里这样本地修改代码容器里立即生效不用重新构建镜像。
  • 数据库数据要用数据卷持久化不然容器删除数据就丢了。
  • 端口映射要注意不要和宿主机的端口冲突。
  • 服务之间用docker-compose的服务名通信不用IP很方便。

3. 开发工作流

开发环境容器化之后开发工作流是这样的:

  1. 开发人员克隆代码到本地。
  2. 运行docker-compose up -d启动所有服务。
  3. 本地修改代码容器里立即生效测试验证。
  4. 开发完成提交代码到版本库。

这样所有开发人员的环境都是一致的不会出现环境不一致的问题新人上手也很快只需要安装Docker运行docker-compose up就能开始开发不用花很多时间搭建环境。

三、CI/CD,自动化构建和部署

开发完成之后就需要自动化构建和部署了也就是CI/CD持续集成持续部署Docker和CI/CD结合能实现自动化构建测试部署大大提高效率。

1. 镜像构建和仓库

首先代码提交之后CI系统会自动拉取代码构建Docker镜像然后把镜像推送到镜像仓库比如Docker Hub阿里云容器镜像服务Harbor私有仓库等等。

镜像要打标签一般用版本号或者Gitcommit ID作为标签比如v1.0.0或者git-abc1234这样能清楚地知道镜像对应的代码版本也方便回滚。

.dockerignore文件也很重要把不需要打包进镜像的文件排除比如.gitnode_modulesvendor测试文件文档等等减少镜像大小也避免把敏感信息打包进去。

2. 自动化测试

镜像构建完成之后要运行自动化测试比如单元测试集成测试等等确保代码没有问题测试通过之后才能部署测试不通过就停止部署通知开发人员修复问题。

自动化测试是CI/CD中非常重要的一环能保证代码质量避免有问题的代码部署到生产环境。

3. 自动化部署

测试通过之后就自动部署到测试环境或者生产环境部署的方式有很多种比如:

  • 简单的SSH到服务器拉取镜像重启容器。
  • 用Docker Swarm或者Kubernetes编排部署。
  • 用CI/CD工具的部署插件比如JenkinsGitLab CIGitHub Actions等等。

部署的时候要注意零停机部署也就是滚动更新先启动新的容器验证没问题再停止旧的容器这样不会影响用户访问不会停机。

四、生产环境的容器化部署

生产环境的容器化部署和开发环境不一样要更注重稳定性安全性高可用等等。

1. 镜像管理

生产环境的镜像要严格管理:

  • 镜像要从可信的镜像仓库拉取不要随便用未知的镜像。
  • 镜像要扫描漏洞确保没有安全漏洞。
  • 镜像要固定版本不要用latest要用具体的版本号或者commit ID。
  • 镜像要尽量小减少攻击面也提高拉取速度。

2. 配置管理

生产环境的配置不能打包在镜像里要通过环境变量或者配置文件挂载注入这样同一个镜像能在不同的环境运行用不同的配置也避免敏感信息泄露。

敏感信息比如数据库密码API密钥等等要用Secret管理比如Docker Swarm 的 secret或者Kubernetes 的 Secret或者专门的配置中心比如Consuletcd等等不要明文写在配置文件里。

3. 数据持久化

生产环境有状态的服务比如数据库消息队列等等数据要持久化用数据卷或者挂载宿主机目录确保容器删除重建数据不丢失同时要定期备份数据防止数据丢失。

无状态的服务比如Web应用API服务等等不要在容器里存数据所有数据都存到数据库或者对象存储里这样容器可以随时删除重建方便扩展和迁移。

4. 网络和安全

生产环境的网络和安全很重要:

  • 容器之间用自定义网络通信不要用默认的bridge网络更安全。
  • 不需要对外暴露的端口不要映射到宿主机比如数据库Redis只让应用容器访问不要对外暴露。
  • 用防火墙或者安全组限制端口访问只开放需要的端口。
  • 容器不要用root用户运行要用非root用户更安全。
  • 定期更新镜像和宿主机系统修复安全漏洞。

5. 监控和日志

生产环境一定要有监控和日志:

  • 监控容器的CPU内存磁盘网络等等资源使用情况有异常及时告警。
  • 监控应用的健康状态响应时间错误率等等确保应用正常运行。
  • 收集容器的日志集中存储方便排查问题比如用ELKEFK等等日志系统。
  • 有告警机制出现问题及时通知运维人员快速处理。

6. 高可用和扩展

生产环境要考虑高可用和扩展:

  • 应用要无状态能水平扩展需要更多资源的时候启动更多容器就行。
  • 用负载均衡把请求分发到多个应用容器提高并发能力也实现高可用一个容器挂了其他容器还能继续服务。
  • 数据库要做主从复制读写分离甚至集群保证高可用和性能。
  • 容器编排工具比如Docker SwarmKubernetes能自动重启失败的容器自动扩展自动故障转移大大提高可用性。

五、踩坑经验

最后分享一些我用Docker做容器化部署踩过的坑和经验。

1. 不要把数据存在容器里

这是最常见的坑很多新手把数据库数据存在容器里结果容器删除重建数据就丢了一定要用数据卷或者挂载宿主机目录持久化数据重要的数据还要定期备份。

2. 镜像不要用latest

不要用latest标签的镜像因为latest会变化可能今天是一个版本明天就变成另一个版本可能不兼容导致问题要用具体的版本号或者commit ID固定版本稳定可靠。

3. 注意时区问题

Docker镜像默认时区一般是UTC和国内差8小时会导致日志时间不对应用时间不对要设置时区挂载/etc/localtime或者设置环境变量TZ=Asia/Shanghai。

4. 注意文件权限问题

挂载宿主机目录到容器可能会有文件权限问题容器里的用户和宿主机的用户UID不一样导致没有权限读写文件要注意用户权限或者在Dockerfile里指定用户UID和宿主机一致。

5. 不要在容器里跑多个进程

一个容器最好只跑一个主进程不要在一个容器里跑NginxPHPMySQL多个进程那样不符合Docker的最佳实践也不好管理不好扩展应该每个服务一个容器用docker-compose或者编排工具管理多个容器。

6. 注意资源限制

生产环境要给容器设置资源限制CPU内存等等防止某个容器占用太多资源影响其他容器和宿主机也防止内存泄漏导致宿主机OOM崩溃。

7. 日志不要只存在容器里

容器的日志不要只存在容器里容器删除日志就丢了要把日志输出到stdout/stderrDocker会收集或者用日志驱动发送到集中的日志系统方便查看和排查问题。

六、写在最后

Docker容器化部署实战:从开发到生产的完整流程。

Docker容器化部署是现在开发和运维的标配能大大提高部署效率保证环境一致性提高系统稳定性和可扩展性是每个开发者和运维都必须掌握的技能。

这篇文章我们从Docker的优势开发环境容器化CI/CD自动化生产环境部署踩坑经验等等方面分享了Docker容器化部署的实战经验和完整流程希望能帮大家更好地使用Docker做好容器化部署。

当然Docker容器化部署还有很多高级的内容比如Kubernetes容器编排服务网格等等这篇文章只是介绍了基础的流程和最佳实践更多的内容需要大家在实际使用中不断学习和探索。

最后用一句话结尾:

"Docker让部署变得简单高效可靠掌握了容器化部署你就能从容应对各种部署需求。"

祝大家都能用好Docker部署顺利!