Docker是2016年最火爆的技术之一,它彻底改变了应用部署的方式。在Docker出现之前,部署一个应用需要安装各种依赖、配置环境、处理兼容性问题,过程繁琐且容易出错。有了Docker,我们可以把应用和它的所有依赖打包成一个镜像,然后在任何支持Docker的环境中一键运行,真正实现"一次构建,到处运行"。
2016年,Docker已经从一个新兴技术发展成为容器化的事实标准,被越来越多的公司采用,从创业公司到大型企业,都在使用Docker进行应用部署和运维。微服务架构的兴起,更是让Docker成为必备技能。作为程序员,掌握Docker已经不是加分项,而是必备项。
今天就来详细讲解Docker入门与实战,从基础概念到生产环境部署,帮助你快速掌握容器化部署技术。
一、Docker基础概念
1. 什么是Docker
Docker是一个开源的容器化平台,它可以让开发者把应用和它的所有依赖打包成一个轻量级、可移植的容器,然后在任何支持Docker的环境中运行。
Docker的核心思想是"Build, Ship, and Run Any App, Anywhere"(构建、交付、运行任何应用,在任何地方)。它解决了"在我机器上能跑"的问题,让应用部署变得简单、快速、可移植。
2. 容器 vs 虚拟机
很多人会把Docker容器和虚拟机混淆,其实它们有本质的区别:
| 对比项 | 容器(Docker) | 虚拟机(VM) |
|---|---|---|
| 虚拟化级别 | 操作系统级虚拟化 | 硬件级虚拟化 |
| 内核 | 共享宿主机内核 | 每个VM有独立内核 |
| 体积 | 小(MB级) | 大(GB级) |
| 启动速度 | 快(秒级) | 慢(分钟级) |
| 性能 | 接近原生 | 有性能损耗 |
| 资源占用 | 低 | 高 |
| 隔离性 | 进程级隔离 | 完全隔离 |
简单来说,虚拟机是在硬件层面模拟一台完整的计算机,而容器是在操作系统层面隔离进程,共享宿主机的内核。容器更轻量、更快速、更高效,但是隔离性不如虚拟机。
3. Docker的核心组件
- 镜像(Image):只读模板,包含运行应用所需的代码、运行时、库、环境变量、配置文件等。镜像是容器的基础,一个镜像可以创建多个容器。
- 容器(Container):镜像的运行实例,是一个独立的、可执行的应用环境。容器可以被创建、启动、停止、删除,每个容器之间是隔离的。
- 仓库(Registry):存储和分发镜像的地方。Docker Hub是官方的公共仓库,也可以搭建私有仓库(如Harbor)。
- Dockerfile:用来构建镜像的文本文件,包含一系列指令,描述如何构建镜像。
- 数据卷(Volume):用于持久化数据,容器删除后数据卷中的数据不会丢失。
- 网络(Network):容器之间的通信网络,Docker提供了多种网络模式。
4. Docker的优势
- 快速部署:容器启动只需几秒,大大缩短部署时间
- 环境一致性:开发、测试、生产环境一致,避免"在我机器上能跑"的问题
- 轻量高效:容器体积小、启动快、资源占用低
- 可移植性:一次构建,到处运行,支持公有云、私有云、物理机、虚拟机
- 微服务友好:每个微服务可以打包成一个容器,独立部署、独立扩展
- 版本管理:镜像支持版本管理,可以回滚到任意版本
- 生态丰富:Docker Hub上有大量现成的镜像,可以直接使用
二、Docker安装与配置
1. 安装Docker
Docker支持Linux、Windows、macOS等多种操作系统。2016年,Docker在Linux上的支持最完善,Windows和macOS通过Docker Toolbox或Docker for Windows/Mac运行。
Ubuntu/Debian安装:
# 更新包索引
sudo apt-get update
# 安装依赖
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 添加Docker仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 更新包索引并安装Docker
sudo apt-get update
sudo apt-get install -y docker-ce
# 启动Docker并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 验证安装
sudo docker --version
sudo docker run hello-worldCentOS/RHEL安装:
# 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装Docker
sudo yum install -y docker-ce
# 启动Docker并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker2. 配置Docker
配置镜像加速器(国内必配): 由于国内网络原因,从Docker Hub拉取镜像很慢,建议配置国内镜像加速器。
# 创建或修改Docker配置文件
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
# 重启Docker
sudo systemctl daemon-reload
sudo systemctl restart docker将当前用户加入docker组(免sudo):
sudo usermod -aG docker $USER
# 重新登录后生效三、Docker基本操作
1. 镜像操作
# 搜索镜像
docker search nginx
# 拉取镜像(默认latest标签)
docker pull nginx
docker pull nginx:1.21
docker pull ubuntu:16.04
# 查看本地镜像
docker images
# 删除镜像
docker rmi nginx:1.21
docker rmi -f nginx # 强制删除
# 导出镜像为tar文件
docker save -o nginx.tar nginx:latest
# 从tar文件导入镜像
docker load -i nginx.tar
# 给镜像打标签
docker tag nginx:latest mynginx:1.02. 容器操作
# 运行容器
docker run nginx # 前台运行
docker run -d nginx # 后台运行(守护进程)
docker run -d --name mynginx nginx # 指定容器名
docker run -d -p 8080:80 nginx # 端口映射(宿主机8080 -> 容器80)
docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx # 挂载数据卷
docker run -it ubuntu /bin/bash # 交互式运行(进入容器)
docker run --rm nginx # 容器停止后自动删除
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop mynginx
docker stop <容器ID>
# 启动已停止的容器
docker start mynginx
# 重启容器
docker restart mynginx
# 进入运行中的容器
docker exec -it mynginx /bin/bash
docker exec -it mynginx nginx -t # 在容器中执行命令
# 查看容器日志
docker logs mynginx
docker logs -f mynginx # 实时跟踪日志
docker logs --tail 100 mynginx # 查看最后100行
# 查看容器详情
docker inspect mynginx
# 查看容器资源使用情况
docker stats
# 删除容器(容器必须先停止)
docker rm mynginx
docker rm -f mynginx # 强制删除(即使在运行)
docker rm $(docker ps -aq) # 删除所有已停止的容器
# 复制文件到容器/从容器复制
docker cp index.html mynginx:/usr/share/nginx/html/
docker cp mynginx:/etc/nginx/nginx.conf ./四、Dockerfile编写
Dockerfile是用来构建镜像的文本文件,包含一系列指令。掌握Dockerfile编写是Docker的核心技能。
1. Dockerfile常用指令
| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM ubuntu:16.04 |
| MAINTAINER | 维护者信息(已弃用,用LABEL) | MAINTAINER name <email> |
| LABEL | 元数据标签 | LABEL maintainer="name" |
| RUN | 构建时执行命令 | RUN apt-get update && apt-get install -y nginx |
| CMD | 容器启动时默认执行的命令 | CMD ["nginx", "-g", "daemon off;"] |
| ENTRYPOINT | 容器启动时执行的命令(不可被覆盖) | ENTRYPOINT ["nginx"] |
| EXPOSE | 声明容器监听的端口 | EXPOSE 80 443 |
| ENV | 设置环境变量 | ENV NODE_ENV=production |
| ADD | 复制文件到容器(支持URL和解压) | ADD app.tar.gz /app/ |
| COPY | 复制文件到容器(推荐) | COPY index.html /var/www/html/ |
| VOLUME | 声明数据卷 | VOLUME ["/data"] |
| WORKDIR | 设置工作目录 | WORKDIR /app |
| USER | 设置运行用户 | USER www-data |
| ARG | 构建参数 | ARG VERSION=1.0 |
| .dockerignore | 排除不需要的文件 | 类似.gitignore |
2. Dockerfile示例:Nginx
# 基础镜像
FROM ubuntu:16.04
# 维护者
LABEL maintainer="dev@example.com"
# 安装Nginx
RUN apt-get update && \
apt-get install -y nginx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 复制配置文件和网站文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY html/ /var/www/html/
# 声明端口
EXPOSE 80
# 启动Nginx(前台运行)
CMD ["nginx", "-g", "daemon off;"]3. Dockerfile示例:PHP+Apache
FROM php:7.4-apache
# 安装PHP扩展
RUN docker-php-ext-install pdo pdo_mysql mysqli
# 启用Apache重写模块
RUN a2enmod rewrite
# 复制应用代码
COPY src/ /var/www/html/
# 设置权限
RUN chown -R www-data:www-data /var/www/html/
EXPOSE 80
CMD ["apache2-foreground"]4. Dockerfile最佳实践
- 使用官方基础镜像:优先使用Docker Hub上的官方镜像,安全可靠
- 固定镜像版本:不要用latest,用具体版本号如ubuntu:16.04,确保可重现
- 合并RUN指令:多个RUN指令合并成一个,减少镜像层数
- 清理缓存:apt-get install后执行apt-get clean和rm -rf /var/lib/apt/lists/*,减小镜像体积
- 使用COPY而非ADD:COPY更简单透明,ADD有额外功能(URL、解压)容易混淆
- 利用构建缓存:把不常变化的指令放在前面,常变化的放在后面,充分利用缓存
- 使用.dockerignore:排除不需要的文件(如.git、node_modules、日志等),减小构建上下文
- 多阶段构建:编译环境和运行环境分离,减小最终镜像体积(Docker 17.05+支持)
- 不要在镜像中存储敏感信息:密码、密钥等用环境变量或配置文件注入,不要写在Dockerfile中
- 以非root用户运行:创建普通用户,用USER指令切换,提高安全性
5. 构建镜像
# 构建镜像(.是Dockerfile所在目录)
docker build -t myapp:1.0 .
# 指定Dockerfile路径
docker build -f /path/to/Dockerfile -t myapp:1.0 .
# 构建时传递参数
docker build --build-arg VERSION=1.0 -t myapp:1.0 .
# 不使用缓存构建
docker build --no-cache -t myapp:1.0 .五、数据卷(Volume)
容器是临时的,容器删除后数据会丢失。对于需要持久化的数据(如数据库数据、用户上传文件、日志等),需要使用数据卷。
1. 数据卷类型
- 匿名卷:只指定容器内路径,Docker自动在宿主机创建目录
``bash docker run -d -v /var/lib/mysql mysql ``
- 命名卷:给卷起个名字,方便管理
``bash docker run -d -v mysql_data:/var/lib/mysql mysql ``
- 绑定挂载:直接挂载宿主机目录到容器
``bash docker run -d -v /host/data:/container/data nginx ``
2. 数据卷操作
# 创建数据卷
docker volume create myvolume
# 查看数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect myvolume
# 删除数据卷
docker volume rm myvolume
# 删除所有未使用的数据卷
docker volume prune
# 运行容器时挂载数据卷
docker run -d -v myvolume:/data nginx
# 挂载宿主机目录(绑定挂载)
docker run -d -v /host/path:/container/path nginx
# 只读挂载
docker run -d -v /host/path:/container/path:ro nginx3. 数据卷注意事项
- 数据卷独立于容器,删除容器不会删除数据卷
- 多个容器可以共享同一个数据卷
- 绑定挂载可以方便地在宿主机和容器之间共享文件,适合开发环境
- 命名卷更适合生产环境,由Docker管理,更安全
- 数据库等有状态应用一定要用数据卷持久化数据
六、Docker网络
Docker提供了多种网络模式,容器之间可以通过网络通信。
1. Docker网络模式
- bridge(默认):每个容器连接到默认的docker0网桥,容器之间可以通过IP通信
- host:容器共享宿主机的网络栈,性能高但隔离性差
- none:容器没有网络,完全隔离
- container:容器共享另一个容器的网络栈
- 自定义网络:用户创建的bridge网络,支持容器名解析(DNS),推荐使用
2. 网络操作
# 查看网络
docker network ls
# 创建自定义网络
docker network create mynetwork
# 查看网络详情
docker network inspect mynetwork
# 运行容器时指定网络
docker run -d --name app --network mynetwork nginx
# 连接容器到网络
docker network connect mynetwork container2
# 断开容器与网络的连接
docker network disconnect mynetwork container2
# 删除网络
docker network rm mynetwork
# 删除所有未使用的网络
docker network prune3. 容器间通信
在同一个自定义网络中,容器可以通过容器名互相访问(Docker内置DNS):
# 创建网络
docker network create appnet
# 运行MySQL容器
docker run -d --name db --network appnet -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 运行Web容器,连接到同一个网络,可以用容器名db访问MySQL
docker run -d --name web --network appnet -p 8080:80 mywebapp
# 在web容器中,数据库主机名就是db七、Docker Compose
Docker Compose是用来定义和运行多容器应用的工具。通过一个YAML文件配置应用的所有服务,然后一条命令启动所有服务。
1. 安装Docker Compose
# 下载Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker-compose --version2. docker-compose.yml示例
一个典型的Web应用(Nginx + PHP + MySQL):
version: '3'
services:
# Nginx服务
nginx:
image: nginx:1.21
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./html:/var/www/html
depends_on:
- php
networks:
- appnet
# PHP服务
php:
build: ./php
volumes:
- ./html:/var/www/html
depends_on:
- mysql
networks:
- appnet
# MySQL服务
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: apppass
volumes:
- mysql_data:/var/lib/mysql
networks:
- appnet
# 数据卷
volumes:
mysql_data:
# 网络
networks:
appnet:
driver: bridge3. Docker Compose常用命令
# 启动所有服务(后台运行)
docker-compose up -d
# 启动并构建镜像
docker-compose up -d --build
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs
docker-compose logs -f nginx
docker-compose logs --tail 100
# 停止服务
docker-compose stop
# 启动已停止的服务
docker-compose start
# 重启服务
docker-compose restart
docker-compose restart nginx
# 停止并删除容器、网络(保留数据卷)
docker-compose down
# 停止并删除容器、网络、数据卷(危险!数据会丢失)
docker-compose down -v
# 进入服务容器
docker-compose exec php /bin/bash
# 构建镜像
docker-compose build
docker-compose build --no-cache
# 查看配置
docker-compose config
# 拉取镜像
docker-compose pull4. Docker Compose最佳实践
- 用环境变量管理配置(如数据库密码),不要硬编码
- 用dependson定义服务启动顺序(注意:dependson只保证启动顺序,不保证服务就绪)
- 用数据卷持久化数据库等有状态服务的数据
- 用自定义网络隔离不同应用
- 开发环境用绑定挂载,生产环境用命名卷
- 不同环境用不同的compose文件(docker-compose.yml + docker-compose.prod.yml)
八、生产环境部署
1. 镜像管理
- 搭建私有仓库:生产环境建议搭建私有Docker仓库(如Harbor),存储自己的镜像
- 镜像版本管理:用Git commit hash或版本号作为镜像标签,不要用latest
- 安全扫描:用Trivy、Clair等工具扫描镜像漏洞
- 最小化镜像:用Alpine等轻量基础镜像,减小镜像体积和攻击面
2. 容器编排
单机用Docker Compose,多机/集群用Kubernetes(K8s)。2016年,Kubernetes已经成为容器编排的事实标准,但是对于中小团队,Docker Compose已经足够。
3. 日志管理
- 容器日志输出到stdout/stderr,用docker logs查看
- 生产环境用ELK(Elasticsearch + Logstash + Kibana)或EFK收集和分析日志
- 用log driver把日志发送到远程日志服务
4. 监控
- 用docker stats查看容器资源使用
- 生产环境用Prometheus + Grafana监控容器和宿主机
- 设置告警,及时发现问题
5. 安全
- 以非root用户运行容器
- 不要在镜像中存储敏感信息,用环境变量或Secret注入
- 限制容器资源(CPU、内存),防止单个容器占用过多资源
``bash docker run -d --memory=512m --cpus=1 nginx ``
- 只读挂载根文件系统,只给需要写的目录挂载可写卷
- 定期更新基础镜像,修复安全漏洞
6. CI/CD集成
- 代码提交后,CI自动构建镜像、运行测试
- 测试通过后,推送镜像到私有仓库
- CD自动部署到生产环境(蓝绿部署、滚动更新)
- 常见工具:Jenkins、GitLab CI、GitHub Actions、Drone
九、常见问题与解决方案
1. 容器启动后立即退出
- 原因:容器没有前台进程,Docker容器需要一个前台进程保持运行
- 解决:确保CMD或ENTRYPOINT启动的是前台进程,如nginx -g "daemon off;"
2. 端口映射不生效
- 检查容器内应用是否监听0.0.0.0而不是127.0.0.1
- 检查防火墙是否开放端口
- 用docker ps确认端口映射是否正确
3. 数据丢失
- 原因:没有用数据卷持久化数据,容器删除后数据丢失
- 解决:数据库等有状态服务一定要用数据卷
4. 镜像体积太大
- 用Alpine等轻量基础镜像
- 合并RUN指令,清理包缓存
- 用多阶段构建,只把编译产物复制到最终镜像
- 用.dockerignore排除不需要的文件
5. 容器时间不对
- 原因:容器默认用UTC时间
- 解决:挂载宿主机时区文件
``bash docker run -v /etc/localtime:/etc/localtime:ro nginx ``
总结
Docker是2016年最火爆的技术之一,它彻底改变了应用部署的方式。本文从基础概念、安装配置、基本操作、Dockerfile编写、数据卷、网络、Docker Compose、生产环境部署等方面,详细讲解了Docker入门与实战。
核心要点总结:
- 镜像和容器:镜像是只读模板,容器是镜像的运行实例
- Dockerfile:用Dockerfile构建镜像,遵循最佳实践(合并RUN、清理缓存、利用缓存、.dockerignore)
- 数据卷:有状态服务用数据卷持久化数据,容器删除数据不丢失
- 网络:用自定义网络,容器之间可以通过容器名通信
- Docker Compose:用YAML文件定义多容器应用,一条命令启动所有服务
- 生产环境:私有仓库、镜像版本管理、日志监控、安全加固、CI/CD集成
Docker的学习曲线不算陡峭,但是要精通需要大量实践。建议从简单的应用开始,逐步尝试更复杂的场景。Docker不仅仅是一个工具,更是一种思维方式——它改变了我们开发、测试、部署应用的方式。
在微服务和云原生的时代,Docker已经成为程序员的必备技能。希望本文能帮助你快速入门Docker,在实际项目中用好容器化技术。
最后,记住Docker的核心理念:"Build, Ship, and Run Any App, Anywhere"。一次构建,到处运行。这就是Docker的魅力所在。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录