Docker
本文记录 Docker 的入门笔记。更详细的内容见 Docker 官方文档。
*注:网络问题请自行配置代理,这里不再赘述。
基本概念¶
Docker 是一个开源的容器化平台,可以把应用程序和它需要的所有依赖打包在一起,形成一个标准化的单元,方便在不同环境中运行,解决了「在我电脑上能运行,为什么到你电脑上就不行了」这个经典问题。同时,Docker 让应用部署变得非常简单快速,不需要复杂的安装配置过程,直接启动容器就能运行应用。
容器与虚拟机的区别
虚拟机是在硬件层面进行虚拟化,每个虚拟机都包含完整的操作系统,启动时间较久,占用空间较大;而容器是在操作系统层面进行虚拟化,多个容器共享同一个操作系统内核,启动时间较短,占用空间较小。可以通俗地类比为租房的场景:虚拟机就是单独租了一间房,卧室、卫生间、厨房一应俱全;而容器就是合租,卫生间、厨房都要和别人共用,通过操作系统的调度,让你洗澡、做饭不和其他合租户冲突,看上去就像独租。
Docker 主要由镜像 (Image)、容器 (Container) 和仓库 (Registry) 三部分组成,下面分别介绍。
镜像¶
镜像 (Image) 是一个只读的应用模板,包含了运行应用所需的一切——代码、运行环境、系统工具、库文件等。为了保证环境的一致性,镜像一旦创建就不能修改,如果需要更新,就要重新构建一个新的镜像。同一个软件的所有镜像通过版本标签来管理,比如 nginx:1.21 和 nginx:latest 代表 nginx 的不同版本。
容器¶
容器 (Container) 是镜像运行起来后的实例(运行时,Runtime)。同一个镜像可以创建多个容器,它们互不干扰,各自拥有独立的文件系统和网络环境。
仓库¶
仓库 (Registry) 是集中存放镜像的地方,用来分发和管理各个用户或组织上传的镜像,类似于 GitHub 之于代码、应用商店之于软件。最常用的是 Docker Hub 官方仓库,企业也可以搭建私有仓库来存放内部的镜像。
Docker 管理¶
安装 Docker¶
其他平台安装 Docker 详见 Install Docker Engine。
验证安装:
配置 Docker¶
1)常见配置:
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://hub.rat.dev"
],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5
}
2)配置操作:
3)重启 Docker:
镜像管理¶
镜像包含了应用程序及其运行环境。
拉取镜像¶
从远程镜像仓库拉取镜像到本地:
# 拉取最新版本
docker pull <镜像名>
# 拉取指定版本的镜像
docker pull <镜像名>:<标签>
# 示例(著名的开源备忘录系统)
docker pull neosmemo/memos:0.25.3
查看镜像¶
# 查看所有本地镜像
docker images
# 查看特定镜像
docker images <镜像名>
# 显示完整镜像 ID
docker images --no-trunc
# 查看镜像的详细配置
docker inspect <镜像名或ID>
# 查看镜像的构建历史
docker history <镜像名或ID>
删除镜像¶
# 删除单个镜像
docker rmi <镜像 ID 或镜像名>
# 强制删除(即使有容器在使用)
docker rmi -f <镜像 ID>
# 删除所有未使用的镜像
docker image prune
# 删除所有镜像
docker rmi $(docker images -q)
容器管理¶
容器是镜像的运行实例。
运行容器¶
# 基本命令
docker run [OPTIONS] <镜像名>
# 后台运行容器
docker run -d <镜像名>
# 指定容器名称
docker run --name <容器名> <镜像名>
# 自动重启
docker run --restart always <镜像名>
# 设置环境变量
docker run -e MYSQL_ROOT_PASSWORD=<password> <镜像名>
常见参数说明(上述没涉及到的后面会慢慢揭晓):
-d:后台运行(detached mode)-it:交互式运行(-i 保持 STDIN 打开,-t 分配伪终端)--name:指定容器名称-p:端口映射(宿主机端口:容器端口)-v:挂载目录或数据卷--rm:容器停止后自动删除-e:设置环境变量--network:指定网络--restart:重启策略(no/on-failure/always/unless-stopped)
查看容器¶
监控容器🤨¶
查看容器日志:
# 查看容器的日志
docker logs <容器名或容器 ID>
# 实时查看日志
docker logs -f <容器名或容器 ID>
# 查看最近 100 行日志
docker logs --tail 100 <容器名或容器 ID>
# 查看带时间戳的日志
docker logs -t <容器名或容器 ID>
# 查看指定时间后的日志
docker logs --since 2024-01-01T10:00:00 <容器名或容器 ID>
查看容器详情:
# 查看容器详细配置
docker inspect <容器名或容器 ID>
# 查看特定信息(使用 --format)
docker inspect --format='{{.NetworkSettings.IPAddress}}' <容器名或容器 ID>
# 查看容器内进程
docker top <容器名或容器 ID>
# 查看容器资源使用情况
docker stats <容器名或容器 ID>
# 实时监控所有容器资源
docker stats
启停容器¶
# 停止运行中的容器
docker stop <容器名或容器 ID>
# 强制停止容器
docker kill <容器名或容器 ID>
# 启动已停止的容器
docker start <容器名或容器 ID>
# 重启容器
docker restart <容器名或容器 ID>
# 暂停容器
docker pause <容器名或容器 ID>
# 恢复暂停的容器
docker unpause <容器名或容器 ID>
Tip
重新运行容器不需要重新添加 docker run 时设置的参数,因为这些配置都被持久化在对应的容器元数据中了,Linux 中容器元数据的持久化路径为 /var/lib/docker/containers/<CONTAINER_ID>/。
进入容器🤨¶
# 进入正在运行的容器(推荐方式)
docker exec -it <容器名或ID> /bin/bash
# 如果容器中没有 bash,可以使用 sh
docker exec -it <容器名或ID> /bin/sh
# 以 root 用户进入
docker exec -it -u root <容器名或ID> /bin/bash
# 执行单条命令
docker exec <容器名或ID> ls -la /app
容器与宿主机文件传输¶
# 从容器复制文件到宿主机
docker cp <容器名或容器 ID>:<容器路径> <宿主机路径>
# 从宿主机复制文件到容器
docker cp <宿主机路径> <容器名或容器 ID>:<容器路径>
# 示例
docker cp mycontainer:/app/log.txt ./log.txt
docker cp ./config.yaml mycontainer:/app/config.yaml
删除容器¶
# 删除已停止的容器
docker rm <容器名或ID>
# 强制删除运行中的容器
docker rm -f <容器名或ID>
# 删除所有已停止的容器
docker container prune
数据管理¶
Docker 容器的文件系统是临时的,容器删除后数据会丢失,所以有必要进行数据持久化。Docker 的数据持久化有数据卷 (Volume) 和绑定挂载 (Bind Mount) 两种方式。两者的区别主要体现在:
| 特性 | 数据卷 | 绑定挂载 |
|---|---|---|
| 管理方式 | Docker 管理 | 用户手动管理 |
| 存储位置 | Docker 专用目录(Linux 上是 /var/lib/docker/volumes/) |
任意宿主机路径 |
| 性能 | 较好 | 取决于文件系统 |
| 适用场景 | 生产环境 | 开发环境、配置文件 |
| 可移植性 | 高 | 低 |
数据卷¶
管理数据卷:
# 创建数据卷
docker volume create <卷名>
# 查看所有数据卷
docker volume ls
# 查看数据卷详细信息
docker volume inspect <卷名>
# 删除数据卷
docker volume rm <卷名>
# 删除所有未使用的数据卷
docker volume prune
使用数据卷:
# 运行容器时挂载数据卷
docker run -d \
--name db-container \
-v <卷名>:<容器路径> \
mysql:latest
# 示例:MySQL 数据持久化
docker volume create mysql-data
docker run -d \
--name mysql \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
mysql:latest
# 多个容器共享同一数据卷
docker run -d --name app1 -v shared-data:/data myapp:latest
docker run -d --name app2 -v shared-data:/data myapp:latest
绑定挂载¶
# 基本语法
docker run -v <宿主机绝对路径>:<容器路径> <镜像名>
# 示例:挂载代码目录(开发环境)
docker run -d \
--name web-dev \
-v /home/user/project:/app \
-p 8080:80 \
nginx:latest
# 只读挂载(防止容器修改宿主机文件)
docker run -v /host/path:/container/path:ro <镜像名>
# 挂载单个文件
docker run -v /host/config.yaml:/app/config.yaml <镜像名>
网络管理¶
Docker 的网络功能允许容器之间以及容器与外部进行通信。Docker 支持多种网络模式:
- bridge(桥接网络):默认模式,容器通过虚拟网桥连接,可访问外部网络;
- host(主机网络):容器直接使用宿主机网络栈,性能最好但隔离性差;
- none(无网络):容器没有网络连接;
- container:与其他容器共享网络命名空间;
- 自定义网络:用户创建的网络,支持容器名称解析。
查看和管理网络¶
# 查看所有网络
docker network ls
# 查看网络详细信息
docker network inspect <网络名>
# 创建自定义桥接网络
docker network create <网络名>
# 创建指定子网的网络
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-network
# 删除网络
docker network rm <网络名>
# 删除所有未使用的网络
docker network prune
容器加入网络¶
# 创建容器时指定网络
docker run --name <容器A> --network <网络名> -itd <镜像名>
# 将已存在的容器连接到网络
docker network connect <网络名> <容器名>
# 断开容器与网络的连接
docker network disconnect <网络名> <容器名>
容器间通信¶
在同一自定义网络中的容器可以通过容器名相互访问:
# 创建自定义网络
docker network create app-network
# 启动数据库容器
docker run -d \
--name mysql-db \
--network app-network \
-e MYSQL_ROOT_PASSWORD=password \
mysql:latest
# 启动应用容器
docker run -d \
--name web-app \
--network app-network \
-e DB_HOST=mysql-db \
myapp:latest
# 在 web-app 容器中可以直接通过 mysql-db 访问数据库
# 例如:mysql -h mysql-db -u root -p
测试容器间连通性:
# 进入容器 A
docker exec -it <容器A> /bin/bash
# 通过容器名 ping 容器 B
ping <容器B>
# 或者直接执行
docker exec <容器A> ping -c 3 <容器B>
端口映射¶
将容器端口映射到宿主机,使外部可以访问容器服务:
# 基本端口映射
docker run -d -p <宿主机端口>:<容器端口> <镜像名>
# 示例
docker run -d -p 8080:80 nginx:latest
# 映射到所有网络接口
docker run -d -p 0.0.0.0:8080:80 nginx:latest
# 映射到指定 IP
docker run -d -p 192.168.1.100:8080:80 nginx:latest
# 映射多个端口
docker run -d \
-p 8080:80 \
-p 8443:443 \
nginx:latest
# 映射 UDP 端口
docker run -d -p 53:53/udp dns-server:latest
# 随机映射端口
docker run -d -P nginx:latest
# 查看端口映射
docker port <容器名或ID>
使用 host 网络模式¶
容器 DNS 配置¶
# 自定义 DNS 服务器
docker run -d \
--dns 8.8.8.8 \
--dns 8.8.4.4 \
nginx:latest
# 添加 hosts 记录
docker run -d \
--add-host myhost:192.168.1.100 \
nginx:latest
Docker Compose¶
Docker Compose 是用于定义和运行多容器 Docker 应用的工具,通过 YAML 文件配置应用服务。Docker 一般自带。
Docker Compose 常用命令¶
# 启动所有服务
docker-compose up -d
# 停止所有服务
docker-compose down
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs -f
# 重启服务
docker-compose restart
# 构建镜像
docker-compose build
# 扩展服务实例
docker-compose up -d --scale web=3
Docker Compose 示例配置¶
创建 docker-compose.yml 文件:
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
networks:
- app-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: mydb
volumes:
- db-data:/var/lib/mysql
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db-data:
其他¶
容器无法访问外网:
# 检查 DNS 配置
docker run --rm busybox nslookup google.com
# 配置 DNS
# 在 /etc/docker/daemon.json 中添加
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
磁盘空间不足:
端口已被占用:
最佳实践:
- 使用 .dockerignore 文件:排除不需要的文件,减小镜像体积;
- 最小化镜像层数:合并 RUN 命令,减少镜像大小;
- 使用多阶段构建:分离构建环境和运行环境;
- 不要在容器中存储重要数据:始终使用数据卷持久化;
- 使用健康检查:确保容器正常运行;
- 限制容器资源:避免单个容器占用过多资源;
- 定期更新镜像:保持安全性和稳定性;
- 使用标签管理镜像版本:避免使用 latest 标签。
安全建议:
- 不要以 root 用户运行容器;
- 定期扫描镜像漏洞;
- 使用官方或可信镜像;
- 限制容器权限(例如 --cap-drop);
- 使用网络隔离;
- 加密敏感数据(使用 Docker Secrets)。