【运维】Docker 入门
文章目录
- 基本概念
- Docker 的定义
- Docker 的核心组件
- Docker 的运行机制
- Docker 管理
- Windows 安装 Docker
- Docker 配置
- 镜像管理
- 拉取镜像
- 查看本地镜像
- 搜索镜像
- 构建自定义镜像
- 镜像导出与导入
- 查看镜像详细信息
- 给镜像打标签
- 删除镜像
- 容器管理
- 运行容器
- 启停容器
- 进入容器
- 删除容器
- 监控容器
- 容器与宿主机文件传输
- 容器提交为镜像
- 数据持久化
- 数据卷 volume
- 绑定挂载
- 数据卷 vs 绑定挂载
- 临时文件系统 tmpfs
- 数据备份与恢复
- 网络管理
- 查看和管理网络
- 容器加入网络
- 容器间通信
- 端口映射
- 使用 host 网络模式
- 容器 DNS 配置
- Docker Compose
- Docker Compose 常用命令
- Docker Compose 示例配置
- 其他
更好的阅读体验:https://wiki.dwj601.cn/develop/operation/docker/
本文记录 Docker 的入门笔记。更详细的内容见 Docker 官方文档。
*注:网络问题请自行配置代理,这里不再赘述。
基本概念
Docker 的定义
Docker 是一个开源的容器化平台,可以把应用程序和它需要的所有依赖打包在一起,形成一个标准化的单元。这样无论在哪台机器上运行,都能保持一致的行为。简单来说,Docker 就像是给软件打包的「集装箱」,让软件可以方便地在不同环境中运输和运行。
容器与虚拟机的区别。虚拟机是在硬件层面进行虚拟化,每个虚拟机都包含完整的操作系统,启动时间较久,占用空间较大。而容器是在操作系统层面进行虚拟化,多个容器共享同一个操作系统内核,启动时间较短,占用空间较小。可以通俗地类比为租房的场景:虚拟机就是一栋楼(主机)中的每一层,而容器是一层中的每一间,通过操作系统的调度,让你做饭、洗澡不和同一层的其他租户冲突,看上去就像租了一层楼。
Docker 解决的核心问题。Docker 主要解决了「在我电脑上能运行,为什么到你电脑上就不行了」这个经典问题。通过容器技术,开发环境、测试环境和生产环境可以完全一致,避免了因为系统版本、依赖库版本不同而导致的各种问题。同时,Docker 让应用部署变得非常简单快速,不需要复杂的安装配置过程,直接启动容器就能运行应用。这对于需要快速扩展的服务特别有用,比如电商网站在促销时需要临时增加服务器处理能力,用 Docker 可以在几秒钟内启动多个应用实例。
Docker 的核心组件
Docker 主要由镜像 (Image)、容器 (Container) 和仓库 (Registry) 三个核心部分组成。
镜像 (Image)。镜像是一个只读的应用模板,包含了运行应用所需的一切:代码、运行环境、系统工具、库文件等。你可以把镜像理解成软件的安装包,它定义了容器应该是什么样子。镜像一旦创建就不能修改,如果需要更新,就要重新构建一个新的镜像。这种不可变的特性保证了环境的一致性。镜像通过版本标签来管理,比如 nginx:1.21 和 nginx:latest 代表 nginx 的不同版本。
容器 (Container)。容器是镜像运行起来后的实例,是应用真正运行的地方。如果说镜像是"类",那么容器就是"对象"。同一个镜像可以创建多个容器,它们互不干扰,各自拥有独立的文件系统和网络环境。容器在运行时可以修改文件、写入数据,但这些改动只存在于容器的生命周期内,删除容器后这些改动也会消失,除非你使用数据卷来持久化保存数据。
仓库 (Registry)。仓库是集中存放镜像的地方,类似于 GitHub 之于代码、应用商店之于软件。最常用的是 Docker Hub 官方仓库,上面有大量现成的镜像可以直接使用。企业也可以搭建私有仓库来存放内部的镜像。当你需要某个镜像时,Docker 会自动从仓库下载;当你构建好自己的镜像后,也可以推送到仓库与他人分享。
Docker 的运行机制
分层文件系统。Docker 镜像采用分层结构,就像搭积木一样一层层叠加。最底层是基础操作系统,往上依次是运行环境、依赖库、应用代码等。每一层都是只读的,新的层只记录与上一层的差异。这种设计带来很多好处:多个镜像可以共享相同的底层,节省存储空间;构建镜像时如果某一层没有变化,可以使用缓存,加快构建速度;传输镜像时只需要传输差异的层,节省网络带宽。当容器运行时,会在这些只读层之上添加一个可写层,所有的修改都发生在这一层。
客户端-服务端架构。Docker 采用客户端-服务端模式工作。当你在命令行输入 docker run 这样的命令时,Docker 客户端会把请求发送给 Docker 服务端(也叫 Docker Daemon,即 Docker 守护进程)。服务端负责实际的工作:管理镜像、创建和运行容器、处理网络和存储等。它们之间通过 REST API 通信,这意味着客户端和服务端可以在不同的机器上,你可以在本地电脑上控制远程服务器上的 Docker。这种架构使得 Docker 可以很容易地集成到各种自动化工具和平台中,比如 Kubernetes 就是通过 Docker API 来管理容器的。
Docker 管理
Windows 安装 Docker
其他平台安装 Docker 详见 Install Docker Engine。
安装步骤:
- 安装 WSL2;
- 进入 Docker 官网,下载 Docker Desktop for Windows;
- 运行安装程序,默认安装在 C 盘,也可以自定义调整安装路径。安装过程中会提示启用 WSL2 功能,确保勾选该选项。
注意事项:
- 建议为安装盘预留 50GB 以上的空间;
- 首次启动可能需要重启计算机;
- 确保 Windows 10 版本在 2004 及以上,或 Windows 11。
验证安装:
docker --version
docker-compose --version
正常显示版本号就表示安装成功。启动 Docker Desktop 后就可以使用所有的 Docker 命令了,当然也可以利用 Docker Desktop 进行可视化操作。
Docker 配置
可以通过 Docker Desktop 进行配置:
- 打开 Docker Desktop;
- 点击右上角设置图标;
- 选择 Docker Engine;
- 在 JSON 配置文件中添加对应内容;
- 点击 “Apply & Restart” 应用配置。
也可以直接编辑 Docker 的配置文件 /etc/docker/daemon.json 进行配置。
常见的配置如下:
{"registry-mirrors": ["https://docker.m.daocloud.io","https://docker.1panel.live","https://hub.rat.dev"],"max-concurrent-downloads": 10,"max-concurrent-uploads": 5
}
之后重启 Docker 服务即可:
sudo systemctl daemon-reload
sudo systemctl restart docker
镜像管理
Docker 镜像是容器运行的基础模板,包含了应用程序及其运行环境。
拉取镜像
从 Docker Hub 或其他镜像仓库拉取镜像:
# 拉取最新版本
docker pull <镜像名># 拉取指定版本
docker pull <镜像名>:<标签># 示例
docker pull ubuntu:22.04
docker pull nginx:latest
查看本地镜像
# 查看所有本地镜像
docker images# 查看特定镜像
docker images <镜像名># 显示完整镜像 ID
docker images --no-trunc
搜索镜像
# 在 Docker Hub 搜索镜像
docker search <关键词># 示例
docker search python
构建自定义镜像
使用 Dockerfile 构建镜像:
# 在 Dockerfile 所在目录执行
docker build -t <镜像名>:<标签> .# 指定 Dockerfile 路径
docker build -t myapp:v1.0 -f /path/to/Dockerfile .
Dockerfile 示例:
FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
镜像导出与导入
# 导出镜像为 tar 文件
docker save -o <文件名.tar> <镜像名># 从 tar 文件导入镜像
docker load -i <文件名.tar># 示例
docker save -o ubuntu.tar ubuntu:22.04
docker load -i ubuntu.tar
查看镜像详细信息
# 查看镜像的详细配置
docker inspect <镜像名或ID># 查看镜像的构建历史
docker history <镜像名或ID>
给镜像打标签
# 为镜像添加新标签
docker tag <源镜像>:<源标签> <目标镜像>:<目标标签># 示例
docker tag myapp:latest myapp:v1.0
删除镜像
# 删除单个镜像
docker rmi <镜像ID或镜像名># 强制删除(即使有容器在使用)
docker rmi -f <镜像ID># 删除所有未使用的镜像
docker image prune# 删除所有镜像
docker rmi $(docker images -q)
容器管理
容器是镜像的运行实例。
运行容器
基本运行命令:
# 交互式运行容器
docker run -it <镜像名> /bin/bash# 后台运行容器
docker run -d <镜像名># 指定容器名称
docker run --name <容器名> -itd <镜像名> /bin/bash
高级运行命令示例:
# 带 GPU 支持和目录挂载
docker run --gpus all -itd \--ipc=host \--name <容器名> \-v <宿主机路径>:<容器路径> \<镜像名> /bin/bash# 端口映射和环境变量
docker run -d \--name web-server \-p 8080:80 \-e MYSQL_ROOT_PASSWORD=password \nginx:latest# 自动重启和资源限制
docker run -d \--name app \--restart always \--memory="512m" \--cpus="1.0" \myapp:latest
常用参数说明:
docker run [OPTIONS] <镜像名> [COMMAND]# -d: 后台运行(detached mode)
# -it: 交互式运行(-i 保持 STDIN 打开,-t 分配伪终端)
# --name: 指定容器名称
# -p: 端口映射(宿主机端口:容器端口)
# -v: 挂载目录或数据卷
# --rm: 容器停止后自动删除
# -e: 设置环境变量
# --network: 指定网络
# --restart: 重启策略(no/on-failure/always/unless-stopped)
启停容器
# 停止运行中的容器
docker stop <容器名或ID># 强制停止容器
docker kill <容器名或ID># 启动已停止的容器
docker start <容器名或ID># 重启容器
docker restart <容器名或ID># 暂停容器
docker pause <容器名或ID># 恢复暂停的容器
docker unpause <容器名或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 rm <容器名或ID># 强制删除运行中的容器
docker rm -f <容器名或ID># 删除所有已停止的容器
docker container prune# 删除所有容器
docker rm -f $(docker ps -aq)
监控容器
查看容器状态:
# 查看正在运行的容器
docker ps# 查看所有容器(包括已停止的)
docker ps -a# 查看最近创建的容器
docker ps -l# 只显示容器 ID
docker ps -q# 显示容器大小
docker ps -s
查看容器日志:
# 查看容器的标准输出/错误日志
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 cp <容器名或ID>:<容器路径> <宿主机路径># 从宿主机复制文件到容器
docker cp <宿主机路径> <容器名或ID>:<容器路径># 示例
docker cp mycontainer:/app/log.txt ./log.txt
docker cp ./config.yaml mycontainer:/app/config.yaml
容器提交为镜像
# 将容器当前状态保存为新镜像
docker commit <容器名或ID> <新镜像名>:<标签># 示例
docker commit mycontainer myapp:v2.0# 添加提交说明和作者信息
docker commit -m "Added new features" -a "Your Name" mycontainer myapp:v2.0
数据持久化
Docker 容器的文件系统是临时的,容器删除后数据会丢失。数据持久化有两种主要方式:
- 数据卷 (Volume):Docker 管理的持久化存储,存储在宿主机的 Docker 目录下,生命周期独立于容器;
- 绑定挂载 (Bind Mount):将宿主机目录或文件直接挂载到容器中,适合开发环境或需要直接访问宿主机文件的场景。
数据卷 volume
创建和管理数据卷:
# 创建数据卷
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 <镜像名>
数据卷 vs 绑定挂载
| 特性 | 数据卷 | 绑定挂载 |
|---|---|---|
| 管理方式 | Docker 管理 | 用户手动管理 |
| 存储位置 | Docker 专用目录 | 任意宿主机路径 |
| 性能 | 较好 | 取决于文件系统 |
| 适用场景 | 生产环境数据持久化 | 开发环境、配置文件 |
| 可移植性 | 高 | 低 |
临时文件系统 tmpfs
在内存中创建临时存储,容器停止后数据消失,适合存储敏感临时数据。
# 使用 tmpfs 挂载
docker run -d \--name app \--tmpfs /tmp:rw,size=100m \myapp:latest
数据备份与恢复
# 备份数据卷
docker run --rm \-v <卷名>:/source \-v $(pwd):/backup \ubuntu tar czf /backup/backup.tar.gz -C /source .# 恢复数据卷
docker run --rm \-v <卷名>:/target \-v $(pwd):/backup \ubuntu tar xzf /backup/backup.tar.gz -C /target
网络管理
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 网络模式
# 容器直接使用宿主机网络
docker run -d --network host nginx:latest# 注意:host 模式下不需要 -p 参数,容器端口直接暴露在宿主机
容器 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:latestports:- "8080:80"volumes:- ./html:/usr/share/nginx/htmlnetworks:- app-networkdb:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: passwordMYSQL_DATABASE: mydbvolumes:- db-data:/var/lib/mysqlnetworks:- app-networknetworks:app-network:driver: bridgevolumes:db-data:
其他
容器无法访问外网:
# 检查 DNS 配置
docker run --rm busybox nslookup google.com# 配置 DNS
# 在 /etc/docker/daemon.json 中添加
{"dns": ["8.8.8.8", "8.8.4.4"]
}
磁盘空间不足:
# 清理未使用的镜像、容器、网络
docker system prune -a# 查看磁盘使用情况
docker system df
端口已被占用:
# 查看端口占用情况(Windows)
netstat -ano | findstr :8080# Linux
lsof -i :8080
最佳实践:
- 使用 .dockerignore 文件:排除不需要的文件,减小镜像体积;
- 最小化镜像层数:合并 RUN 命令,减少镜像大小;
- 使用多阶段构建:分离构建环境和运行环境;
- 不要在容器中存储重要数据:始终使用数据卷持久化;
- 使用健康检查:确保容器正常运行;
- 限制容器资源:避免单个容器占用过多资源;
- 定期更新镜像:保持安全性和稳定性;
- 使用标签管理镜像版本:避免使用 latest 标签。
安全建议:
- 不要以 root 用户运行容器;
- 定期扫描镜像漏洞;
- 使用官方或可信镜像;
- 限制容器权限(例如 --cap-drop);
- 使用网络隔离;
- 加密敏感数据(使用 Docker Secrets)。
