什么是Docker,为什么要用它
Docker是一个容器化技术,它可以将应用程序及其所有依赖项打包在一个标准化的单元中,即容器。这类似于一个轻量级的虚拟机,但其启动速度更快、资源开销更小。
在容器化普及之前,部署应用时常面临环境不一致的挑战,例如开发、测试、生产环境中的运行时版本(如Python 3.8、3.7、3.9)不匹配。Docker通过将环境与代码一同打包,从根本上解决了“在我机器上能运行”的经典问题。
此外,容器化显著提升了资源利用率。传统方式可能在一台服务器上仅部署单个应用,而利用Docker,可以同时运行多个相互隔离的容器,从而更高效地利用硬件资源。
安装Docker
在Ubuntu系统上安装Docker的步骤如下:
# 更新包索引
sudo apt update
# 安装必要的包
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 设置稳定版仓库
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker Engine
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
安装完成后,为避免每次执行命令都需sudo,建议将当前用户加入docker组:
sudo usermod -aG docker $USER
执行此命令后,需要重新登录系统或执行 newgrp docker 使配置生效。
对于CentOS系统,安装过程类似,主要区别是使用yum包管理器。Windows和macOS用户可直接下载并安装图形化工具Docker Desktop。
Docker的基本概念
在深入操作前,理解三个核心概念至关重要:
- 镜像(Image):一个只读模板,包含了运行应用所需的一切:代码、运行时、库、环境变量和配置文件。例如,
ubuntu:20.04镜像提供了Ubuntu 20.04操作系统的基本文件系统。
- 容器(Container):镜像的一个运行实例。你可以从同一个镜像创建多个容器,就像用同一个类实例化多个对象。
- 仓库(Repository):用于存放镜像的集中存储服务。Docker Hub是全球最大的公共仓库,你也可以搭建私有仓库。
常用Docker命令
镜像相关命令
查看本地已有的镜像:
docker images

从仓库拉取镜像:
docker pull nginx:latest
docker pull ubuntu:20.04

删除本地镜像:
docker rmi nginx:latest
根据当前目录的Dockerfile构建镜像:
docker build -t myapp:v1.0 .
容器相关命令
运行容器:
# 运行测试容器
docker run hello-world
# 以交互模式运行并进入bash
docker run -it ubuntu:20.04 /bin/bash
# 以后台模式运行
docker run -d nginx:latest
# 端口映射:将宿主机8080端口映射到容器80端口
docker run -d -p 8080:80 nginx:latest
查看容器状态:
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a

控制容器生命周期:
docker stop container_id
docker start container_id
docker restart container_id
进入正在运行的容器:
docker exec -it container_id /bin/bash
删除容器:
docker rm container_id
查看容器日志:
docker logs container_id
docker logs -f container_id # 实时跟踪日志
实战案例:部署一个Web应用
让我们通过部署一个简单的基于Python的Flask应用来串联上述概念。
- 创建应用文件
app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return '<h1>Hello from Docker!</h1>'
@app.route('/health')
def health():
return {'status': 'ok'}
if name == 'main':
app.run(host='0.0.0.0', port=5000)
2. 创建依赖文件 `requirements.txt`:
Flask==2.3.3
3. 编写 `Dockerfile`:
```dockerfile
# 使用Python 3.9精简版作为基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY app.py .
# 声明容器运行时监听的端口
EXPOSE 5000
# 容器启动命令
CMD ["python", "app.py"]
-
构建镜像:
docker build -t flask-app:v1.0 .
-
运行容器:
docker run -d -p 5000:5000 --name my-flask-app flask-app:v1.0
现在,访问 http://localhost:5000 即可看到运行的应用。这个简单示例涵盖了构建、运行和端口映射等核心操作。
数据持久化和卷(Volume)
容器本质上是无状态的,停止或删除容器后,其内部产生的数据也会丢失。为了实现数据持久化,Docker提供了以下几种方式:
绑定挂载(Bind Mount)
将宿主机的目录或文件直接挂载到容器内。
docker run -d -v /host/path:/container/path nginx:latest
例如,运行MySQL容器时持久化数据:
docker run -d \
--name mysql-server \
-e MYSQL_ROOT_PASSWORD=mypassword \
-v /opt/mysql-data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0
这样,容器内的 /var/lib/mysql 数据将保存在宿主机的 /opt/mysql-data 目录中。
Docker卷(Volume)
由Docker管理的存储方式,比绑定挂载更易于备份和迁移。
# 创建卷
docker volume create mydata
# 使用卷
docker run -d -v mydata:/data nginx:latest
# 查看所有卷
docker volume ls
临时文件系统(tmpfs)
将数据存储在内存中,容器停止后数据即消失,适合存放临时缓存。
docker run -d --tmpfs /tmp nginx:latest
Docker网络详解
Docker的网络功能是实现容器间以及容器与外部世界通信的关键。其底层利用了Linux的网络命名空间实现隔离。
默认网络模式
Docker为容器提供了几种网络模式:
- bridge模式(默认):容器通过虚拟网桥
docker0连接到宿主机网络,拥有独立的IP,可与其他容器通信。
- host模式:容器直接使用宿主机的网络栈,没有网络隔离,性能最佳。
- none模式:容器没有任何网络接口,完全隔离。
- container模式:容器共享另一个容器的网络命名空间。
查看现有网络:
docker network ls
通常会看到 bridge、host、none 三个默认网络。

自定义网络
创建自定义网络能实现更灵活的服务发现和网络策略。
创建并使用自定义bridge网络:
# 创建网络
docker network create mynetwork
# 指定子网的创建方式
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--ip-range=172.20.240.0/20 \
--gateway=172.20.0.1 \
mynetwork2
# 在指定网络中运行容器
docker run -d --network mynetwork --name web nginx:latest
关键优势:在自定义网络中,容器可以通过容器名直接相互访问,这解决了默认bridge网络需要通过IP或--link(已不推荐)通信的痛点。
端口映射
将容器内部的端口暴露给宿主机外部访问。
# 基本映射
docker run -d -p 8080:80 nginx:latest
# 映射多个端口
docker run -d -p 8080:80 -p 8443:443 nginx:latest
# 映射到宿主机特定IP
docker run -d -p 127.0.0.1:8080:80 nginx:latest
# 随机映射
docker run -d -P nginx:latest
容器间通信实例:多服务应用
假设我们有一个包含前端、后端和数据库的应用:
# 创建自定义网络
docker network create webapp --subnet=172.18.0.0/16
# 启动数据库(不暴露外部端口)
docker run -d \
--name database \
--network webapp \
-e MYSQL_ROOT_PASSWORD=rootpass \
mysql:8.0
# 启动后端API(依赖数据库,可通过`database`主机名访问)
docker run -d \
--name api \
--network webapp \
-e DATABASE_HOST=database \
my-api:latest
# 启动前端(暴露80端口,可通过`api`主机名访问后端)
docker run -d \
--name frontend \
--network webapp \
-p 80:80 \
-e API_HOST=api \
my-frontend:latest
此架构实现了服务间通过容器名通信,网络逻辑清晰,且只有前端服务对外暴露端口。
环境变量和配置
为应用注入配置的常用方式:
- 命令行直接设置:
docker run -d -e NODE_ENV=production node-app:latest
- 使用环境变量文件:创建
.env 文件,内容如 KEY=VALUE,运行命令:
docker run -d --env-file .env mysql:8.0
- 在Dockerfile中定义默认值:
FROM node:16
ENV NODE_ENV=production
ENV PORT=3000
Docker Compose:管理多容器应用
当应用由多个服务(如Web、数据库、缓存等)组成时,使用Docker Compose可以通过一个YAML文件定义和运行所有容器。
安装
较新版本的Docker Desktop已内置Compose。Linux系统可单独安装:
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
编写docker-compose.yml
以下示例定义了一个包含Web应用、MySQL、Redis和Nginx的服务栈,并展示了网络分层设计:
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- DATABASE_URL=mysql://user:password@db:3306/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- backend
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
volumes:
- mysql_data:/var/lib/mysql
networks:
- backend
redis:
image: redis:7-alpine
networks:
- backend
nginx:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- web
networks:
- frontend
networks:
frontend:
backend:
internal: true # 后端网络禁止外部直接访问
volumes:
mysql_data:
常用Compose命令
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
# 停止并移除所有资源
docker-compose down
生产环境最佳实践
镜像优化
安全考虑
日志管理
配置日志驱动,避免日志文件无限增长。
docker run -d \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx:latest
总结
Docker通过容器化技术,为应用提供了从开发到部署的一致性环境,极大地简化了依赖管理和部署流程。本文从核心概念入手,涵盖了安装、基本命令、镜像构建、数据持久化、网络配置等基础内容,并深入探讨了使用Docker Compose编排多服务应用,以及生产环境下的镜像优化、安全与监控等最佳实践。
特别在网络方面,理解并善用自定义网络和容器发现机制,是构建复杂分布式应用的关键。掌握这些知识和实践,将帮助开发者和运维人员更高效地利用容器技术,构建稳定、可扩展的现代化应用架构,这也是现代云原生技术栈的重要基石。