1. Docker入门:从安装到第一个容器
第一次接触Docker时,我被它"一次构建,随处运行"的理念深深吸引。想象一下,你开发的应用能像乐高积木一样,在任何地方都能完美运行,不再有"在我电脑上好好的"这种尴尬。下面我就带大家从零开始,一步步掌握Docker的核心用法。
1.1 环境准备与安装
在开始之前,我们需要确保系统满足Docker的基本要求。以CentOS 7为例,内核版本需要3.10以上。可以通过以下命令检查:
uname -r如果版本符合要求,安装过程其实非常简单:
# 安装必要依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加Docker仓库 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装Docker引擎 yum install docker-ce docker-ce-cli containerd.io # 启动Docker服务 systemctl start docker安装完成后,运行一个简单的测试命令验证是否安装成功:
docker run hello-world这个命令会从Docker Hub拉取一个测试镜像并运行,如果看到"Hello from Docker!"的欢迎信息,说明你的Docker已经准备就绪了。
1.2 配置阿里云镜像加速
在国内使用Docker时,直接从Docker Hub拉取镜像可能会很慢。阿里云提供了免费的镜像加速服务,配置方法如下:
- 登录阿里云容器镜像服务控制台
- 获取专属加速器地址
- 创建或修改/etc/docker/daemon.json文件:
{ "registry-mirrors": ["https://你的加速器地址.mirror.aliyuncs.com"] }- 重启Docker服务使配置生效:
systemctl daemon-reload systemctl restart docker配置完成后,镜像下载速度会有显著提升。我曾经测试过,一个500MB的基础镜像,使用加速器后下载时间从10分钟缩短到30秒左右。
2. Docker核心概念与日常操作
理解了Docker的基本概念,才能更好地使用它。Docker有三大核心概念:镜像(Image)、容器(Container)和仓库(Registry)。简单来说,镜像像是软件的安装包,容器是运行中的软件实例,仓库则是存放镜像的地方。
2.1 镜像管理实战
镜像是Docker的基石,所有容器都来自镜像。常用的镜像操作包括:
# 搜索镜像 docker search nginx # 拉取镜像(不指定tag默认使用latest) docker pull nginx:1.21 # 查看本地镜像 docker images # 删除镜像(需要先停止并删除相关容器) docker rmi nginx:1.21在实际项目中,我建议始终指定镜像的版本号,而不是使用latest。这样可以避免因版本更新导致的兼容性问题。曾经有个项目因为使用了latest标签,结果新版本镜像不兼容旧配置,导致生产环境出问题。
2.2 容器生命周期管理
容器是Docker的核心,掌握容器的生命周期管理至关重要。下面是一些常用操作:
# 运行一个交互式容器(退出后容器停止) docker run -it --name my_ubuntu ubuntu /bin/bash # 运行守护式容器(后台运行) docker run -d --name my_nginx -p 8080:80 nginx # 查看运行中的容器 docker ps # 查看所有容器(包括已停止的) docker ps -a # 停止容器 docker stop my_nginx # 启动已停止的容器 docker start my_nginx # 进入运行中的容器 docker exec -it my_nginx /bin/bash # 删除容器 docker rm my_nginx这里有个实用技巧:使用--restart参数可以让容器在异常退出时自动重启,非常适合生产环境:
docker run -d --restart unless-stopped --name my_nginx nginx3. 数据持久化与容器通信
默认情况下,容器内的数据是临时的,容器删除后数据也会丢失。但在实际应用中,我们经常需要持久化存储数据,比如数据库文件、日志等。
3.1 数据卷(Volume)使用指南
数据卷是Docker推荐的持久化数据方案。它有几个特点:
- 数据卷可以在容器间共享和重用
- 对数据卷的修改会立即生效
- 数据卷会一直存在,即使容器被删除
创建和使用数据卷非常简单:
# 创建数据卷 docker volume create my_volume # 查看数据卷详情 docker volume inspect my_volume # 使用数据卷 docker run -d -v my_volume:/app/data --name my_app my_image # 挂载主机目录(开发时特别有用) docker run -d -v /host/path:/container/path --name my_app my_image在开发过程中,我经常使用主机目录挂载的方式,这样可以在主机上使用熟悉的IDE编辑代码,同时在容器中运行应用,实现代码修改即时生效。
3.2 容器网络与通信
Docker提供了多种网络模式,默认情况下容器使用bridge网络:
# 查看网络列表 docker network ls # 创建自定义网络 docker network create my_network # 将容器连接到网络 docker run -d --network=my_network --name app1 my_image docker run -d --network=my_network --name app2 my_image在同一个自定义网络中的容器可以通过容器名互相访问,这在微服务架构中非常有用。比如app1可以直接通过http://app2:8080访问app2的服务,而不需要知道具体IP地址。
4. 生产环境实战:部署MySQL服务
现在让我们用一个实际案例来巩固所学知识。我们将部署一个生产可用的MySQL服务,包含数据持久化、网络配置和权限设置。
4.1 MySQL容器部署
docker run -d \ --name mysql_prod \ -p 3306:3306 \ -v mysql_data:/var/lib/mysql \ -v mysql_conf:/etc/mysql/conf.d \ -e MYSQL_ROOT_PASSWORD=secure_password \ -e MYSQL_DATABASE=app_db \ -e MYSQL_USER=app_user \ -e MYSQL_PASSWORD=user_password \ --network app_network \ --restart unless-stopped \ mysql:5.7 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci这个命令做了以下几件事:
- 创建并启动一个名为mysql_prod的容器
- 将容器的3306端口映射到主机的3306端口
- 使用两个数据卷分别存储数据和配置
- 设置环境变量配置root密码、创建数据库和用户
- 将容器连接到app_network网络
- 设置容器自动重启
- 指定MySQL字符集为utf8mb4,支持完整的Unicode字符
4.2 生产环境优化建议
在生产环境使用MySQL容器时,还需要考虑以下几点:
- 备份策略:定期备份数据卷
docker run --rm -v mysql_data:/volume -v /backup:/backup alpine \ tar czf /backup/mysql_data_$(date +%Y%m%d).tar.gz -C /volume ./- 性能调优:通过配置文件调整MySQL参数
# 在mysql_conf数据卷中创建my.cnf文件 echo "[mysqld] innodb_buffer_pool_size=1G innodb_log_file_size=256M" > /var/lib/docker/volumes/mysql_conf/_data/my.cnf- 监控:使用工具如Prometheus监控MySQL性能指标
5. Dockerfile最佳实践
虽然可以直接使用现成的镜像,但在实际项目中,我们通常需要定制自己的镜像。Dockerfile就是用来定义镜像构建过程的脚本。
5.1 编写高效的Dockerfile
下面是一个Python应用的Dockerfile示例:
# 使用官方Python基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 先复制requirements.txt并安装依赖 # 这样可以利用Docker的缓存层,避免每次代码修改都重新安装依赖 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 设置环境变量 ENV FLASK_APP=app.py ENV FLASK_ENV=production # 暴露端口 EXPOSE 5000 # 定义启动命令 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]这个Dockerfile遵循了几个最佳实践:
- 使用官方基础镜像
- 合理利用缓存层(先复制requirements.txt)
- 明确设置工作目录
- 使用生产环境配置
- 指定非root用户运行(通过基础镜像已实现)
5.2 多阶段构建
对于需要编译的应用,可以使用多阶段构建来减小最终镜像大小:
# 构建阶段 FROM golang:1.16 AS builder WORKDIR /go/src/app COPY . . RUN go build -o myapp # 运行阶段 FROM alpine:latest WORKDIR /root/ COPY --from=builder /go/src/app/myapp . CMD ["./myapp"]这样最终的镜像只包含运行所需的二进制文件,而不包含编译工具链,可以显著减小镜像体积。我曾经将一个Go应用的镜像从300MB减小到只有10MB。
6. Docker Compose编排多容器应用
在实际项目中,我们经常需要同时管理多个相关联的容器。Docker Compose就是解决这个问题的工具,它允许我们使用YAML文件定义和管理多容器应用。
6.1 编写docker-compose.yml
下面是一个典型的Web应用+MySQL的Compose文件示例:
version: '3.8' services: web: build: . ports: - "5000:5000" volumes: - .:/code environment: FLASK_ENV: development depends_on: - db networks: - app_network db: image: mysql:5.7 volumes: - mysql_data:/var/lib/mysql - mysql_conf:/etc/mysql/conf.d environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: app_db MYSQL_USER: app_user MYSQL_PASSWORD: userpass networks: - app_network volumes: mysql_data: mysql_conf: networks: app_network: driver: bridge这个配置文件定义了两个服务:
- web服务:从当前目录构建镜像,映射5000端口,挂载代码目录,连接到db服务
- db服务:使用MySQL 5.7镜像,配置数据卷和环境变量
6.2 Compose常用命令
# 启动所有服务(后台运行) docker-compose up -d # 查看服务状态 docker-compose ps # 查看服务日志 docker-compose logs -f web # 停止服务 docker-compose down # 重建并启动服务 docker-compose up -d --build使用Compose的一个巨大优势是可以一键部署整个应用栈。我在多个项目中都使用这种模式,特别是在开发环境中,新成员只需克隆代码库,运行docker-compose up就能获得完整的开发环境,大大减少了环境配置时间。
7. CI/CD中的Docker实践
Docker在持续集成和持续部署(CI/CD)中扮演着重要角色。它可以确保从开发到生产的环境一致性,避免"在我机器上能跑"的问题。
7.1 基于Docker的CI流程
一个典型的基于Docker的CI流程可能包含以下步骤:
- 代码提交触发构建
- CI服务器拉取代码
- 构建Docker镜像
- 运行测试
- 推送镜像到镜像仓库
- 部署到测试环境
- 人工验证后部署到生产
在GitHub Actions中,可以这样实现:
name: CI Pipeline on: [push] jobs: build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build Docker image run: docker build -t myapp:${{ github.sha }} . - name: Run tests run: docker run myapp:${{ github.sha }} pytest - name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Push to Docker Hub run: | docker tag myapp:${{ github.sha }} myrepo/myapp:${{ github.sha }} docker push myrepo/myapp:${{ github.sha }}7.2 生产环境部署策略
在生产环境部署Docker容器时,有几种常见策略:
- 蓝绿部署:运行两套相同的生产环境,交替切换流量
- 滚动更新:逐步替换旧版本的容器
- 金丝雀发布:先向一小部分用户发布新版本
使用Docker Swarm或Kubernetes可以方便地实现这些部署策略。例如,在Kubernetes中实现滚动更新:
kubectl set image deployment/myapp myapp=myrepo/myapp:new-version在实际项目中,我建议至少使用Docker Swarm来管理生产环境容器,它提供了服务发现、负载均衡和滚动更新等关键功能,比直接使用Docker Engine更适合生产环境。