Docker 已经成为现代软件开发和运维领域不可或缺的工具。它通过容器化技术,将应用及其依赖打包在一起,实现了“一次构建,处处运行”的理想。本教程将带你一步步探索 Docker 的世界,从核心概念到实战部署。
1. Docker 核心概念:镜像与容器
在开始之前,我们必须理解两个最核心的概念:
- 镜像 (Image): Docker 镜像是一个只读的模板,它包含了运行应用程序所需的一切:代码、运行时、库、环境变量和配置文件。你可以把镜像看作是安装一个软件所需的光盘或安装包。镜像是静态的。
- 容器 (Container): 容器是镜像的一个运行实例。当你运行一个镜像,你就启动了一个容器。容器是动态的,你可以启动、停止、删除它。每个容器都是一个隔离的、轻量级的运行环境。从同一个镜像可以创建出任意多个独立的容器。
简单来说:镜像是类,容器是类的实例。
2. Docker 镜像管理
拉取镜像
# 推荐使用明确的版本号,而不是 :latest
docker pull nginx:1.27
最佳实践:总是使用明确的版本标签(如 1.27),而不是 latest。这能保证你的部署是可预测和可重复的。
查看本地镜像
docker images
# 或者 docker image ls
删除镜像
# 通过名称:标签删除
docker rmi nginx:1.27
# 通过镜像ID删除
docker rmi c8b931b34226
如果你想清理所有当前没有任何容器正在使用的镜像,可以使用 prune 命令,这是最安全高效的方式
# 删除所有未被任何容器引用的镜像
docker image prune -a
3. Docker 容器的生命周期
容器是 Docker 的核心,掌握其生命周期管理至关重要。
运行容器
docker run -d --name my-nginx-container -p 8080:80 nginx:1.27
参数解释:
-d (--detach): 后台运行容器。
--name: 为容器指定一个易于识别的名称。
-p (--publish): 将宿主机的端口映射到容器的端口。格式为 宿主机端口:容器端口。这里我们将宿主机的 8080 端口映射到容器的 80 端口。
nginx:1.27: 指定用来创建容器的镜像。
现在,打开你的浏览器访问 http://localhost:8080,你将看到 Nginx 的欢迎页面。
查看容器
# 查看正在运行的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
停止与启动容器
# 停止容器
docker stop my-nginx-container
# 再次启动已停止的容器
docker start my-nginx-container
删除容器
删除一个不再需要的容器。注意:删除前必须先停止容器。
docker rm my-nginx-container
如果你想一次性清理所有已停止的容器,可以使用 prune 命令:
docker container prune
4. Docker 数据持久化:挂载
容器本身是无状态的,当容器被删除后,容器内部产生的数据也会随之丢失。为了持久化存储数据,我们需要使用数据挂载。
4.1 数据卷 (Volume) – 官方推荐
数据卷是由 Docker 管理的、用于持久化数据的区域。它独立于容器的生命周期。
# 创建一个数据卷
docker volume create my-nginx-data
# 运行容器并挂载数据卷
docker run -d --name my-nginx-volume -p 8081:80 -v my-nginx-data:/usr/share/nginx/html nginx:1.27
参数解释:
-v my-nginx-data:/usr/share/nginx/html: 将我们创建的 my-nginx-data 数据卷挂载到容器内的 /usr/share/nginx/html 目录。现在,所有写入这个目录的数据都会被保存在数据卷中,即使容器被删除,数据依然存在。
4.2 绑定挂载 (Bind Mount)
绑定挂载是将宿主机上的一个文件或目录直接映射到容器中。这在开发环境中同步代码非常有用。
# 将宿主机当前目录下的 `my-site` 文件夹挂载到容器中
docker run -d --name my-nginx-bind -p 8082:80 -v $(pwd)/my-site:/usr/share/nginx/html nginx:1.27
参数解释:
-v $(pwd)/my-site:/usr/share/nginx/html: 将你本地的 my-site 目录内容直接展示在 Nginx 服务中。你在本地修改 my-site 里的 index.html,刷新浏览器就能立刻看到效果。
5. Docker 网络
Docker 为容器提供了多种网络模式,让容器之间以及容器与外界可以通信。
# 查看所有网络
docker network ls
你会看到 Docker 默认创建的几个网络:bridge, host, none。
bridge (桥接模式): 默认模式。Docker 会创建一个虚拟网桥,所有连接到这个网络的容器都会被分配一个独立的 IP 地址,它们可以通过 IP 地址互相通信。
host (主机模式): 容器直接共享宿主机的网络,没有网络隔离。性能最好,但牺牲了安全性。
none (无网络模式): 容器拥有自己的网络栈,但不进行任何网络配置。这是一个完全“断网”的容器,用于绝对安全隔离的计算任务。
对于大多数应用,默认的 bridge 网络已经足够。同一个 bridge 网络下的容器可以通过它们的容器名称直接通信。
6. 使用 Docker Compose 管理多容器应用
当你的应用需要多个容器协同工作时(例如一个 Web 服务 + 一个 Redis 数据库),手动管理 docker run 命令会变得非常繁琐。Docker Compose 就是解决这个问题的利器。它允许你通过一个 YAML 文件来定义和管理整个多容器应用。
6.1 编写 docker-compose.yml 文件
下面是一个部署 Redis 服务的简单例子
# docker-compose.yml
version: '3.8' # 定义文件版本
services: # 定义所有服务
redis-server: # 服务的名称
image: 'redis:7.2-alpine' # 使用的镜像
container_name: my-app-redis # 容器名
restart: always # 容器退出后总是自动重启
ports:
- "6379:6379" # 端口映射
volumes:
- redis-data:/data # 挂载命名数据卷以持久化数据
volumes: # 在顶层声明数据卷
redis-data:
6.2 常用 Docker Compose 命令
确保你在 docker-compose.yml 文件所在的目录中运行以下命令。
启动应用
docker compose up -d
查看服务状态
docker compose ps
停止并移除应用
这条命令会停止并删除 services 中定义的所有容器、网络。由于我们定义的是命名数据卷,数据卷 redis-data 不会被删除。
docker compose down
如果你想在 down 的同时删除数据卷,可以添加 --volumes 标志。
更新服务
当镜像源更新后(例如 redis:7.3-alpine 发布了),更新服务非常简单:
拉取新镜像: docker compose pull
重新创建服务: docker compose up -d
Compose 会智能地只更新那些镜像有变化的的服务。
总结
恭喜你!通过这篇教程,你已经掌握了 Docker 最核心的实战技能。你现在应该能够:
- 管理镜像的拉取和清理。
- 熟练操作容器的整个生命周期。
- 使用数据卷或绑定挂载实现数据持久化。
- 理解基本的网络模式。
- 利用 Docker Compose 高效地编排和管理多容器应用。