未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用范围与待维护事项
本文适用于已安装 Docker、能使用 Bash 的本地隔离开发环境,不是生产部署或数据库备份方案。示例弱口令不得用于真实服务,发布端口须限制访问;批量停止、删除命令执行前需核对目标。各段复用容器名,应分开执行。第三方镜像标签及启动条件尚未核验,Kafka 缺少完整配置,ETL 脚本与 my-app 镜像未提供,相关片段仅演示参数。挂载需自行准备路径与权限,复制运行中 MySQL 数据目录不保证备份一致性。
Docker 容器基本操作
abstract 本章要点
docker run的各种参数,能看懂各种启动命令- 端口映射:让宿主机访问到容器内的服务
- 目录挂载:容器和宿主机共享文件
- 容器生命周期管理:启动、停止、删除
- 进入容器内部和查看日志
容器的生命周期
Created(已创建)
│
▼ docker start
Running(运行中)◄──── docker run(直接创建并运行)
│
├──► docker pause ──► Paused(已暂停)
│ docker unpause ◄──────────────┘
│
▼ docker stop / docker kill
Stopped(已停止)
│
▼ docker rm
Deleted(已删除)
docker run:创建并启动容器
docker run 是最常用的命令,把镜像变成运行中的容器。
基础语法
docker run [参数选项] 镜像名[:标签] [容器内执行的命令]
最常用的参数
| 参数 | 全称 | 含义 |
|---|---|---|
-d |
--detach |
后台运行(detached 模式),不占用终端 |
-it |
--interactive --tty |
交互模式,进入容器终端 |
--name |
--name |
给容器起一个名字 |
-p |
--publish |
端口映射,格式 宿主机端口:容器端口 |
-v |
--volume |
目录/文件挂载 |
-e |
--env |
设置环境变量 |
--rm |
--rm |
容器退出后自动删除(适合临时任务) |
--network |
--network |
指定网络 |
--restart |
--restart |
重启策略 |
-m |
--memory |
限制内存使用 |
--cpus |
--cpus |
限制 CPU 使用 |
实际使用示例
# 最简单:前台运行一个容器(会占用终端,Ctrl+C 退出)
docker run nginx
# 后台运行 MySQL(最常用的模式)
docker run -d \
--name mysql-dev \
-e MYSQL_ROOT_PASSWORD=root123 \
-p 3306:3306 \
mysql:8.0
# 运行一个临时的 Python 容器,执行完就删除
docker run --rm python:3.11-slim python -c "print('Hello Docker')"
# 交互式进入 Ubuntu 容器(常用于调试)
docker run -it --rm ubuntu:22.04 bash
# 运行 Jupyter Notebook,挂载当前目录
docker run -d \
--name jupyter \
-p 8888:8888 \
-v $(pwd)/notebooks:/home/jovyan/work \
jupyter/pyspark-notebook:latest
# 带资源限制的运行(生产环境建议设置)
docker run -d \
--name spark-master \
--memory="4g" \
--cpus="2.0" \
bitnami/spark:3.5
端口映射详解
容器是隔离的,容器内的端口默认外部访问不到。端口映射(Port Mapping)就是把容器内的端口"打通"到宿主机。
语法格式
-p 宿主机端口:容器端口
-p 宿主机IP:宿主机端口:容器端口 # 指定绑定的宿主机 IP
-p 容器端口 # 随机分配宿主机端口
-P # 随机映射所有暴露端口
实际示例
# MySQL:宿主机 3306 → 容器 3306
docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root123 mysql:8.0
# 如果宿主机 3306 已被占用,换一个端口
docker run -d -p 13306:3306 --name mysql-test -e MYSQL_ROOT_PASSWORD=root123 mysql:8.0
# 现在通过 localhost:13306 访问这个 MySQL
# Redis:默认端口 6379
docker run -d -p 6379:6379 --name redis redis:7-alpine
# Kafka:多个端口
docker run -d \
-p 9092:9092 \
-p 9093:9093 \
--name kafka bitnami/kafka:3.7
# 多端口映射(Jupyter + 可能的 Spark UI)
docker run -d \
-p 8888:8888 \
-p 4040:4040 \
--name jupyter jupyter/pyspark-notebook
# 查看容器端口映射情况
docker port mysql
# 输出:3306/tcp -> 0.0.0.0:3306
tip 端口冲突处理
如果提示"端口已被占用"(bind: address already in use),可以:
- 换一个宿主机端口:
-p 13306:3306 - 查找并停止占用端口的进程:
lsof -i:3306(Mac/Linux)或netstat -ano | findstr 3306(Windows)
目录挂载详解
挂载(Mount/Volume)是让容器可以访问宿主机文件系统的机制,有两种方式:
| 方式 | 语法 | 说明 |
|---|---|---|
| Bind Mount(绑定挂载) | -v /宿主机路径:/容器路径 |
将宿主机目录挂载到容器,路径必须是绝对路径 |
| Named Volume(命名卷) | -v 卷名:/容器路径 |
Docker 管理的持久化存储,详见[[【技术与工具】/Docker/08-Docker网络与存储 |
Bind Mount 示例(最常用)
# 挂载数据目录:MySQL 数据存放到宿主机
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root123 \
-p 3306:3306 \
-v /data/mysql:/var/lib/mysql \
mysql:8.0
# 上述挂载将 MySQL 数据目录保存到宿主机 /data/mysql
# 以下为重复的镜像名,仅作注释保留,不应另行执行:
# mysql:8.0
# 挂载配置文件和数据目录;宿主机配置文件须事先存在
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root123 \
-v /conf/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
-v /data/mysql:/var/lib/mysql \
mysql:8.0
# Jupyter:将当前工作目录挂载进去,$(pwd) 获取当前目录的绝对路径
docker run -d \
--name jupyter \
-p 8888:8888 \
-v "$(pwd):/home/jovyan/work" \
jupyter/pyspark-notebook
# ETL 脚本:将脚本目录挂载到 /app,数据目录挂载到 /data
# 需自行提供 scripts/etl_job.py、输入数据及脚本所需依赖
docker run --rm \
-v "$(pwd)/scripts:/app" \
-v "$(pwd)/data:/data" \
python:3.11-slim \
python /app/etl_job.py
# 只读挂载(容器内只能读,不能写),:ro 表示 read-only
# 需自行提供 my-app:latest 镜像及 /conf/app.json 文件
docker run -d \
-v /conf/app.json:/app/config.json:ro \
my-app:latest
warning 挂载路径必须用绝对路径
Bind Mount 的宿主机路径必须是绝对路径(以 / 开头或用 $(pwd) 获取当前目录)。
在本文使用的 -v 语法中,绑定挂载应使用绝对路径;./data 这样的写法通常会因无效卷名报错,而 data 这样的名称表示命名卷,不是当前目录下的绑定路径。
# 错误:相对路径
docker run -v ./data:/var/lib/mysql mysql:8.0
# 正确:绝对路径
docker run -v /home/user/data:/var/lib/mysql mysql:8.0
# 或者用变量
docker run -v $(pwd)/data:/var/lib/mysql mysql:8.0
容器生命周期管理
查看容器
# 查看运行中的容器
docker ps
# 输出示例:
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# a1b2c3d4e5f6 mysql:8.0 "docker-entrypoint.s…" 2 hours ago Up 2 hours 0.0.0.0:3306->3306/tcp mysql-dev
# 查看所有容器(包括已停止的)
docker ps -a
# 只显示容器 ID
docker ps -q
# 以更易读的格式显示
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
启动/停止/重启
# 停止容器(发送配置的停止信号,通常为 SIGTERM;超时后强制终止)
# 等待时间受容器配置和平台影响:未配置时 Linux 默认 10 秒,Windows 默认 30 秒
docker stop mysql-dev
# 强制停止容器(发送 SIGKILL,立即终止)
docker kill mysql-dev
# 启动已停止的容器
docker start mysql-dev
# 重启容器
docker restart mysql-dev
# 停止所有运行中的容器
docker stop $(docker ps -q)
删除容器
# 删除已停止的容器
docker rm mysql-dev
# 强制删除运行中的容器(先 kill 再 rm)
docker rm -f mysql-dev
# 删除所有已停止的容器
docker container prune
# 删除所有容器(包括运行中的)—— 谨慎使用!
docker rm -f $(docker ps -aq)
# 停止并删除容器(常用两步操作)
docker stop mysql-dev && docker rm mysql-dev
重启策略
# 设置 always 重启策略(手动停止后暂不重启,Docker 守护进程重启后可再次启动)
docker run -d \
--restart always \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root123 \
mysql:8.0
# 重启策略选项:
# no 不自动重启(默认)
# always 总是重启
# on-failure 只在退出码非 0 时重启
# unless-stopped 停止前一直重启(手动 docker stop 不会重启)
进入容器内部
docker exec:在运行中的容器执行命令
# 进入容器的交互式 Shell(最常用)
docker exec -it mysql-dev bash
docker exec -it mysql-dev /bin/sh # 有些镜像没有 bash,用 sh
# 在容器内执行单条命令
docker exec mysql-dev mysql -uroot -proot123 -e "SHOW DATABASES;"
# 以 root 用户执行(某些操作需要 root 权限)
docker exec -u root -it mysql-dev bash
# 在容器内创建文件
docker exec mysql-dev touch /tmp/test.txt
# 查看容器内的进程
docker exec mysql-dev ps aux
docker attach:附加到容器前台进程
# 附加到容器的主进程(Ctrl+C 通常会转发 SIGINT,是否停止取决于主进程的信号处理,一般少用)
docker attach mysql-dev
# 对以 -it 创建且保持交互输入的容器,可用默认脱离键 Ctrl+P 然后 Ctrl+Q 退出而不停止容器
# 上述 mysql-dev 未以 -it 创建,不能依赖此脱离方式
tip exec vs attach 怎么选
- exec:在容器内开一个新进程执行命令,最常用,推荐
- attach:附加到容器的主进程,退出时可能导致容器停止,一般不用
查看容器日志
容器主进程及继承其输出流的进程写入 stdout/stderr 的日志通常由 Docker 日志驱动处理;docker logs 能否读取及保留多少日志取决于驱动和配置,应用只写入容器内文件的日志不会自动显示在这里。
# 查看容器日志(输出当前日志驱动仍保留且可读取的日志)
docker logs mysql-dev
# 实时跟踪日志(类似 tail -f)
docker logs -f mysql-dev
# 只看最后 50 行
docker logs --tail 50 mysql-dev
# 看最后 50 行并持续跟踪
docker logs --tail 50 -f mysql-dev
# 看某个时间之后的日志
docker logs --since 2024-01-01T00:00:00 mysql-dev
# 看最近 1 小时的日志
docker logs --since 1h mysql-dev
# 带时间戳显示
docker logs -t mysql-dev
# 查看 Kafka 启动日志,定位启动失败原因
docker logs --tail 100 kafka 2>&1 | grep -i error
容器信息查看
# 查看容器详细信息(JSON 格式,包含网络、挂载等所有配置)
docker inspect mysql-dev
# 只查看 IP 地址
docker inspect --format '{{.NetworkSettings.IPAddress}}' mysql-dev
# 查看容器资源使用情况(实时刷新)
docker stats
# 查看指定容器的资源使用
docker stats mysql-dev
# 查看容器内的进程
docker top mysql-dev
文件传输
# 从容器复制文件到宿主机
docker cp mysql-dev:/etc/mysql/my.cnf ./my.cnf
# 从宿主机复制文件到容器
docker cp ./my.cnf mysql-dev:/etc/mysql/conf.d/my.cnf
# 复制目录(仅演示文件传输,不是有效数据库备份流程)
# 运行中 MySQL 的数据文件复制不保证一致性;需另行采用数据库备份工具或一致性停机流程
docker cp mysql-dev:/var/lib/mysql ./mysql-backup
综合示例:完整的 MySQL 开发环境
# 1. 创建数据目录
mkdir -p ~/docker-data/mysql/data ~/docker-data/mysql/conf
# 2. 创建自定义配置文件
cat > ~/docker-data/mysql/conf/my.cnf <<EOF
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=200
innodb_buffer_pool_size=256M
EOF
# 3. 启动 MySQL 容器
docker run -d \
--name mysql-dev \
--restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-e MYSQL_DATABASE=dev_db \
-e MYSQL_USER=dev_user \
-e MYSQL_PASSWORD=dev123 \
-p 3306:3306 \
-v ~/docker-data/mysql/data:/var/lib/mysql \
-v ~/docker-data/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:8.0
# 4. 观察 MySQL 就绪日志(首次初始化耗时取决于环境,并非固定约 30 秒)
# 初始化期间的临时服务也可能输出该标记,首次匹配不代表最终服务已就绪
# 下一步查询须在初始化完成后成功,才能作为连接验证
docker logs -f mysql-dev 2>&1 | grep -m 1 "ready for connections"
# 5. 验证连接
docker exec -it mysql-dev mysql -uroot -proot123 -e "SHOW DATABASES;"
# 6. 从宿主机连接(使用 MySQL 客户端工具)
# Host: 127.0.0.1, Port: 3306, User: root, Password: root123
常用操作速查
| 操作 | 命令 |
|---|---|
| 后台运行容器 | docker run -d --name xxx image:tag |
| 查看运行容器 | docker ps |
| 查看所有容器 | docker ps -a |
| 进入容器 | docker exec -it xxx bash |
| 查看日志 | docker logs -f xxx |
| 停止容器 | docker stop xxx |
| 删除容器 | docker rm xxx |
| 强制删除 | docker rm -f xxx |
| 复制文件 | docker cp xxx:/path ./local |
| 查看资源 | docker stats |
info 前置知识
- 镜像管理 - 知道如何获取镜像,容器是从镜像启动的
掌握检查
- [ ] 能说出
docker run -d -p 3306:3306 -v /host:/container --name mysql mysql:8.0每个参数的含义 - [ ] 知道
-d和不带-d的区别:前者后台运行,后者前台运行(容器输出直接打印到终端) - [ ] 能用
docker exec -it 容器名 bash进入容器内部,检查进程、查看日志、修改配置 - [ ] 容器挂了后用
docker logs 容器名查看最近的日志来定位原因,而不是盲目重启 - [ ] 知道停止容器用
docker stop(优雅停止),强制停止用docker kill,以及为什么生产上优先用 stop
实践练习
基础题:启动一个 MySQL 容器,要求:(1) 后台运行;(2) 设置 root 密码;(3) 宿主机 3306 端口映射到容器 3306;(4) 数据挂载到宿主机目录(防止容器删除后数据丢失);(5) 设置 --restart unless-stopped。验证:用 docker exec 连入执行 SQL 查询。
进阶题:观察容器资源使用:同时启动 MySQL 和 Redis 两个容器,用 docker stats 实时监控两者的 CPU 和内存占用;然后停止 MySQL,再次查看 stats,理解如何判断容器是否消耗异常。
下一步
- 继续阅读:Dockerfile编写 - 学会构建自己的镜像
- 或者直接跳到实战:数据开发环境搭建 - 用 Docker 搭建常用数据服务