news 2026/9/10 9:11:51

Docker命令全解析:镜像、容器与编排实操指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker命令全解析:镜像、容器与编排实操指南

1. 内容整体设计与思路拆解:为什么你的 Docker 命令总是记不住

1.1 核心痛点:命令数量爆炸,靠背诵永远不够用

我接触 Docker 这些年,被问得最多的一句话不是"Docker 怎么装",而是"这么多命令,到底怎么记才记得住"。说实话,如果一个一个命令去背,学完 Docker 的下一个月就忘掉大半了。这很正常,因为 Docker 的命令体系本身就不是设计出来让人背的,它是结构化、分层级的。

很多人第一次用 Docker,最直观的感受是docker psdocker rundocker imagesdocker pull这些高频命令看起来很简单,但一旦遇到"容器怎么进""日志怎么看""端口怎么映射""数据怎么持久化"这些问题,就卡住了,然后翻文档翻半天。这时候你就会意识到,Docker 命令是有内在逻辑的,不是平铺的一堆参数。

1.2 把命令拆成三大块,记忆负担直接减半

我习惯把 Docker 命令分成三层:镜像层、容器层、编排层

镜像层解决的是"从哪来、怎么管理"的问题,对应pullimagesrmitagbuildsaveload。容器层解决的是"怎么跑、怎么管"的问题,对应runpsstartstoprestartrmexeclogs。编排层解决的是"多个容器怎么协同"的问题,对应composenetworkvolumeswarm这些。

你只要抓住这条主线,命令就变成了"我镜像有了吗,我要不要让镜像个容器跑起来,跑起来之后我要进去看什么,多容器我要怎么编排"这样一条操作链,而不是一百条独立的记不住的黑命令。这篇指南我按这条主线来写,每一步都配合实际场景和参数解析,你可以直接拿过去用。

2. 环境准备:从安装 Docker 到第一个容器的完整闭环

2.1 不同系统的安装路径,以及 Docker Desktop 的坑

Docker 安装是老生常谈,但实际操作中坑特别多。Linux 上安装相对简单,以 Ubuntu 为例,先更新软件源,然后装apt-transport-httpsca-certificatescurl这些前置工具,再添加 Docker 官方 GPG 密钥,最后安装docker-cedocker-compose-plugin

sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl 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 sudo apt-get update sudo apt-get install -y docker-ce docker-compose-plugin

注意:安装完 Docker 后,默认需要sudo才能执行 Docker 命令。如果你不想每次敲命令都带sudo,把当前用户加入docker用户组即可,命令是sudo usermod -aG docker $USER。加入用户组后要重新登录一次终端才能生效,这一步很多人容易忽略,结果回头又来问"为什么我加了还要 sudo"。

Windows 和 macOS 上的方案是 Docker Desktop。下载安装包后一路下一步就行,但有两个高频问题你很可能遇到。一个是 Windows 安装时提示"virtualization support not detected"或者"Docker Desktop failed to start because virtualisation support wasn't detected",这类问题的根源是 Hyper-V 或 WSL2 没启用。解决方法是先到"启用或关闭 Windows 功能"里勾选"虚拟机平台"和"适用于 Linux 的 Windows 子系统",然后重启,再打开 PowerShell 执行wsl --set-default-version 2。如果还是不行,进 BIOS 确认虚拟化已经打开。

另一个常见问题是镜像拉取过程中出现 "not supported" 等奇怪的网络报错,这通常和 Docker Desktop 的代理设置有关,后面我会专门讲镜像源配置。

2.2 验证安装和 Docker 守护进程状态

装完之后,先跑两条命令确认环境正常。docker version会显示 Client 和 Server 两部分信息。正常情况下两条信息都要能显示出来,如果只有 Client 没有 Server,说明 Docker 守护进程没起来。Linux 上执行sudo systemctl start dockersudo systemctl enable docker让 Docker 开机自启。

docker info可以查看更详细的信息,包括容器数量、镜像数量、存储驱动、Cgroup 版本、网络配置等。我建议每次在新环境装完 Docker 都习惯性看一眼docker info,尤其要确认存储驱动是overlay2,因为老旧的aufs驱动在新内核上兼容性差,遇到奇怪问题先检查这里。

docker version docker info

接下来跑第一个容器验证环境是否可用。我的习惯是先拉一个hello-world镜像,虽然它几乎什么都没做,但能验证镜像拉取、容器创建、运行、退出这整条链路是否正常。

docker pull hello-world docker run --name hello-demo hello-world

如果看到 "Hello from Docker!" 的输出,说明整个 Docker 环境已经通了。这时候你也可以装一个自己真正会用到的镜像来进一步验证,比如 Nginx 或者 MySQL,我在后面第 4 章会详细拆解一个完整的 MySQL 8.0 部署实例。

3. 镜像管理命令:从拉取、查看到离线迁移

3.1 镜像拉取与版本标注

Docker 镜像管理的核心起点是docker pull。命令本身很简单:docker pull <镜像名>:<标签>。但有个细节很多人没搞清楚:标签的默认值是latest。如果你直接docker pull nginx,实际拉的是nginx:latest。而latest标签不等于"最新稳定版",它只是镜像维护者手动标记的一个标签,很多项目的latest实际上是开发版或者预发布版。生产环境部署时,我强烈建议指定具体版本标签,比如nginx:1.27-alpinemysql:8.0.37,这样后续可复现、可回滚。

镜像名还分单段和两段,比如nginxlibrary/nginx是同一个东西,因为官方镜像默认属于library这个顶层命名空间;而像mysql/mysql-server这样的两段式镜像名,前面是命名空间,后面是镜像名。从第三方仓库拉取时,还要在前面加仓库地址,比如registry.cn-hangzhou.aliyuncs.com/xxx/xxx

实操心得:我一般会在拉镜像前先用docker search看下镜像有哪些版本标签。虽然docker search查不到全部版本列表(它返回的是镜像概要信息),但能确认镜像是否存在、是否为官方镜像、星标数和描述是否匹配。想看全部版本列表,最可靠的办法是直接访问 Docker Hub 官方网站,或者用docker pull --help确认参数后拉取试探。

版本选择的另一个重要策略是尽量选择alpine变体。alpine是基于 Alpine Linux 的精简版本,体积比常规版本小好几倍,比如nginx:latest大概 190MB,nginx:alpine只有 45MB 左右。对于内存和磁盘敏感的场景,用 alpine 变体能显著降低资源占用。缺点是 Alpine 基于 musl libc,个别软件编译依赖会出问题,但绝大多数主流镜像官方都维护了 alpine 版本,踩坑率很低。

3.2 镜像查看、删除与离线迁移

docker images查看本地镜像列表,这个命令显示的字段包括REPOSITORYTAGIMAGE IDCREATEDSIZEIMAGE ID是镜像的唯一标识,但它是短 ID,完整的 ID 是 64 位。删除镜像用docker rmi,可以接IMAGE ID镜像名:标签。如果要强制删除,加-f参数,但这个参数要慎用,因为它会跳过"镜像正在被容器使用"的保护机制,可能导致正在运行的容器异常。

docker images docker rmi nginx:alpine docker image prune

docker image prune这个清理命令很实用,它会删除所有"悬挂镜像"(即没有标签且不被任何容器引用的中间镜像,也就是 dangling images)。做镜像构建频繁的时候,本机会积累很多<none>镜像,占用大量磁盘,跑一次docker image prune基本就清干净了。

镜像离线迁移是内网环境必备技能。docker save把镜像导出成 tar 文件,docker load把 tar 文件再导回镜像。这两个命令我习惯搭配使用,比如要把一台服务器上的镜像迁移到另一台离线服务器:

第一台机器上执行:

docker save -o nginx-alpine.tar nginx:alpine

把 tar 包拷贝到第二台机器后执行:

docker load -i nginx-alpine.tar

注意:docker savedocker export是完全不同的两个命令。docker save保存的是镜像,docker export导出的是容器的文件系统快照。前者可以完整保留镜像层和历史版本信息,适合镜像分发;后者不保留镜像元数据,导入后会丢失 CMD、ENTRYPOINT 等启动配置,适合做容器备份或迁移运行的容器状态。这两个场景不一样,千万别混用。

3.3 镜像标签和仓库上传

docker tag的作用是给镜像打标签,常用场景有两个:一个是给本地镜像重新命名以便推送,另一个是给镜像打特定版本标签。比如本地有个myapp:latest,要推送到自己的仓库:

docker tag myapp:latest registry.example.com/myteam/myapp:v1.0.0 docker push registry.example.com/myteam/myapp:v1.0.0

docker push之前必须先用docker login登录目标仓库。Docker Hub 的默认登录地址是index.docker.io/v1/,私有仓库则填具体地址。我建议用docker login时配合访问令牌(登录 Docker Hub 后在账号设置里生成),不要直接使用账号密码,因为访问令牌可以按需撤销,安全性高很多。

4. 容器生命周期命令:docker run 到 docker rm 的每一步都拆开讲

4.1 docker run 参数解析:一次运行一个容器的完整理解

docker run是整个 Docker 命令体系里最核心的命令,没有之一。它的语法可以拆成三部分:启动参数、镜像名和启动命令。启动参数决定容器的运行方式、资源限制和挂载情况;镜像名决定容器运行的模板;启动命令会覆盖镜像里定义的默认 CMD。

我举一个实际生产中用到的完整例子,启动一个带端口映射、数据卷、环境变量和自动重启策略的 MySQL 8.0 容器:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=MyPass@123 \ -e TZ=Asia/Shanghai \ -v /data/mysql:/var/lib/mysql \ --restart=always \ mysql:8.0.37

逐段解释一下:

  • -d:后台运行容器,容器启动后在后台运行,不占用终端。不加-d的话容器会以前台方式运行,日志直接输出到当前终端,用Ctrl+C会停止容器。调试阶段我会先用前台方式跑,确认日志没异常再改成后台方式。
  • --name mysql8:给容器指定名称,后续所有对容器的操作(logs、exec、stop、rm)都可以用这个名字定位。不指定的话 Docker 会生成一个随机名字,操作起来很麻烦。
  • -p 3306:3306:端口映射,格式是宿主机端口:容器端口。外部程序连接宿主机的 3306 端口就能访问到容器内的 MySQL。注意宿主机端口不能冲突,如果宿主机上已经有人在监听 3306,你就可以映射为-p 3307:3306
  • -e:环境变量,MySQL 镜像通过MYSQL_ROOT_PASSWORD来设置 root 密码。不同镜像支持的环境变量不同,使用前先看镜像文档。
  • -v /data/mysql:/var/lib/mysql:将宿主机的/data/mysql目录挂载到容器的 MySQL 数据目录。这样容器删了、重建了,数据还在宿主机上,这是实现数据持久化的核心手段。
  • --restart=always:容器退出或 Docker 重启后自动拉起。生产环境建议用alwaysunless-stopped,区别在于unless-stopped不会在你手动停止容器后自动拉起,而always在 Docker 重启时会启动一切标记为 always 的容器,即使你之前手动停过。

实操心得:-it这个组合参数是交互式进入容器的关键。-i表示保持标准输入打开,-t分配一个伪终端。在docker run里交互式创建容器时就把它加上,比如docker run -it ubuntu bash,会直接进入 Ubuntu 容器的 bash 终端。而docker exec -it是进入一个已经在运行的容器的标准姿势,我在下面的章节里专门说。

4.2 docker ps 和 docker logs:查看容器状态与日志

docker ps查看正在运行的容器,docker ps -a查看所有容器(包括已退出状态的)。输出的字段很多,最常用的是CONTAINER IDIMAGESTATUSPORTSNAMESSTATUS字段如果显示Up 3 hours说明容器正在运行,显示Exited (0)说明容器已正常退出,Exited (1)就是异常退出了。

docker logs查看容器日志,这个命令在排查容器启动失败时几乎是第一选择。常用参数是-f(实时跟随输出,类似 tail -f)、--tail(只显示最后 N 行)、--since(显示某个时间之后的日志)。

docker logs -f --tail 100 mysql8

这个命令会先打印最后 100 行日志,然后保持实时跟进。我调试容器时基本固定用这个组合。

4.3 docker exec -it:进入容器的正确姿势

当容器已经跑起来,你想进去执行命令,docker exec -it <容器名> /bin/bash是最常用的方式。比如进入 MySQL 容器执行 SQL:

docker exec -it mysql8 bash -c "mysql -uroot -p"

这里有个小知识点:很多精简镜像里没有bash,只有sh。比如alpine系列镜像默认只有sh,如果你执行docker exec -it alpine-container /bin/bash会报exec: "/bin/bash": stat /bin/bash: no such file or directory。遇到这种情况,把/bin/bash换成/bin/sh就行。还有一个思路是在镜像封装时把 bash 装进去,但为了一个 sh 能解决的问题去膨胀镜像体积不值得。

注意:docker exec -it <容器名> bash不加完整路径时,Docker 会按默认 PATH 查找命令,有时候因为 PATH 配置问题找不到。我建议无论 bash 还是 sh,都写完整路径,既稳定又快速。

4.4 stop、start、restart、kill、rm:容器生命周期管理

容器生命周期管理的命令其实挺直观,stop优雅停止(发送 SIGTERM,给进程一段时间处理收尾工作),kill强制停止(直接发 SIGKILL),start启动已存在的容器,restart重启容器,rm删除容器(只能删除已停止的容器,如果想删运行中的容器加-f)。

docker stop mysql8 docker rm mysql8 docker stop mysql8 && docker rm mysql8

比较实用的一个组合是从停止到删除一气呵成:docker stop xxx && docker rm xxx。因为我经常需要重建容器,用这个方式能防止忘记删掉旧容器导致重名冲突。

批量清理容器的需求也很常见,用docker ps -a -q获取所有容器的 ID 列表,然后配合docker rm批量删除:

docker rm $(docker ps -a -q)

这条命令把$()里的命令输出作为参数传给docker rm,所以能一次删掉所有已停止的容器。更稳妥的做法是加-f

docker rm -f $(docker ps -aq)

4.5 docker run 之后的资源限制

启动容器时还能限制 CPU 和内存,这对生产环境尤其重要。不限制的话,容器可以吃满宿主机的所有资源,一旦某个容器内存泄漏,整台机器都会被拖垮。

docker run -d --name app_demo --memory="512m" --cpus="1.5" nginx:alpine

--memory限制最大内存,超限容器会被 OOM Killer 杀掉,--cpus限制 CPU 核数,1.5 表示最多用 1.5 个核。如果只想限制内存但不想让它被杀死,加--memory-swap--oom-kill-disable,但后者要谨慎,因为无限交换 / 无限内存意味着可能拖垮宿主机。

5. 数据卷与容器网络:理解 Docker 的"持久化"与"通信"

5.1 数据卷管理:数据不随容器消失而消失

容器的隔离性让数据持久化成为一个矛盾点。容器本身是临时的,删除容器后里面写的文件就没了。要保住数据,必须使用数据卷或者 bind mount。

数据卷的推荐做法是命名卷(named volume),创建和管理都是docker volume系列命令:

docker volume create mysql-data docker volume ls docker volume inspect mysql-data

挂载命名卷:

docker run -d --name mysql8 -v mysql-data:/var/lib/mysql mysql:8.0.37

关键点在于,这里-v参数左边mysql-data是卷名,不是宿主机路径。当你只写了一个名字而没写路径分隔符的时候,Docker 会把mysql-data当作命名卷来处理,自动在宿主机/var/lib/docker/volumes/mysql-data/_data下创建目录。

还有一种方式是我前面章节提到的 bind mount,将宿主机绝对路径直接挂载进容器:

docker run -d --name nginx-web -v /home/user/nginx/html:/usr/share/nginx/html:ro nginx:alpine

bind mount 的好处是你直接能看到文件、直接编辑,适合开发调试。我在开发环境 Nginx 静态文件就是用 bind mount,改代码不用重新构建镜像;生产环境则优先用命名卷,因为 Docker 管理更规范,备份恢复也更方便。

实操心得:-v挂载目录如果宿主机上不存在,Docker 会自动帮你创建这个目录。听起来很方便,但坑点在于它创建目录的所有者是 root,权限往往是 755,这时候容器内非 root 用户往挂载目录写文件就会权限不足。遇到"明明挂载了却写不进去"的报错,先检查宿主机目录的属主和权限,再用-v挂载时配合:Z(SELinux 环境)或者在镜像里调整用户权限。

5.2 容器网络:bridge、host、none 与自定义网络

Docker 默认网络模式是 bridge,容器通过虚拟网桥docker0通信,和宿主机之间也有 NAT 转换。docker network ls能看到当前有哪些网络,默认有bridgehostnone三个。

实际业务里最常用的是自定义 bridge 网络。自定义网络相比默认 bridge 的优势在于内置 DNS 解析,容器之间可以直接用容器名互相访问。比如搭建 Redis 主从时,主从容器通过网络用同一套内部网络,从节点连接主节点时地址写主节点容器名就行,不需要知道具体 IP。

docker network create app-net docker run -d --name redis-master --network app-net redis:6.2-alpine docker run -d --name redis-slave --network app-net redis:6.2-alpine

HOST 模式直接把容器进程绑到宿主机网络栈,性能更好但隔离性差,一般用于对网络性能要求极高的场景,比如一些高性能代理。none 模式容器没有网络,做网络隔离测试时才会用到。

查看容器网络详情用docker inspect。这个命令输出的是 JSON 格式的巨量信息,包括容器的网络配置、挂载情况、环境变量、启动命令等。查看某个字段时加--format参数更高效,比如:

docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql8

这条命令只输出容器的 IP 地址。docker inspect配合--format是排查容器问题的利器,我建议花点时间熟悉 Go template 的基本语法,很多信息用一条 inspect 就能精准捞出来。

5.3 清理磁盘:docker system 系列命令

容器和镜像用久了,磁盘会莫名其妙小下去。罪魁祸首往往是镜像、无用的容器、悬空数据卷和构建缓存。docker system df可以一次性看磁盘占用情况:

docker system df

输出会列出IMAGESCONTAINERSLOCAL VOLUMESBUILD CACHE四类资源,以及 RECLAIMABLE 列,这一列显示可回收的空间。清理命令我用得最多的是docker system prune

docker system prune -a

这个命令会删除所有未使用的镜像(包括历史镜像)、停止的容器、未被容器使用的网络和构建缓存。加-a会连未被任何容器引用的镜像一起删,而且会提示你确认,不放心的话可以加--volumes把未使用的数据卷也清理掉。我在 CI 构建机上定期跑一次,能回收大量空间。

6. 构建命令与 Compose 编排:从单容器到多服务的进阶实战

6.1 docker build:用 Dockerfile 打包应用镜像

有了基础镜像之后,真正属于你自己的镜像是通过docker build构建出来的。Dockerfile 里最关键的有几个指令:FROM指定基础镜像,WORKDIR切换工作目录,COPY复制文件,RUN执行构建期命令,EXPOSE声明容器监听端口,CMDENTRYPOINT设置容器启动时的默认命令。

一个典型的 Node.js 应用 Dockerfile:

FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install --registry=https://registry.npmmirror.com COPY . . EXPOSE 3000 CMD ["npm", "start"]

构建命令:

docker build -t myapp:1.0.0 .

尾部那个.是构建上下文,Dockerfile 里的COPY . .就是从上下文中复制文件。构建上下文越大,构建越慢,所以.dockerignore文件里要排除node_modulesdist.git等不需要的文件。

6.2 多容器编排:docker compose up 一行启全套

单容器可以用docker run硬扛,一旦服务多了,比如 Nginx + 后端 + Redis + MySQL 四个服务,你还用一条条docker run去启动,管理命令会变得非常痛苦。这时候就需要 Docker Compose。

Compose 的核心是docker-compose.yml。我以一个最小可跑的 Nginx + Redis 服务为例:

version: "3.8" services: web: image: nginx:alpine ports: - "8080:80" volumes: - ./html:/usr/share/nginx/html depends_on: - cache cache: image: redis:6.2-alpine

然后在同目录执行:

docker compose up -d

-d后台运行。查看日志用docker compose logs -f,停止并删除服务用docker compose down,重新构建并启动用docker compose up -d --build。如果你改了 compose 文件,docker compose up -d会自动检测配置变更并重建受影响的服务。

实操心得:比较docker-composedocker compose要注意,老版本的 Compose 是 Python 写的docker-compose命令,新版 Docker 已经把 Compose 集成到 Docker CLI 里了,命令是docker compose。如果执行docker compose报 "unknown command",说明你装的是老版本 Docker,需要单独安装docker-compose-plugin。现在主流 Linux 发行版默认都给的是新命令,但很多旧教程还在用旧命令,看教程时注意区分。

在 Compose 配置里,我会给每个服务单独设置restart: unless-stopped,这样节点重启后服务能自动恢复,这是生产部署的一个基本素养。资源限制也可以直接写在 compose 文件里,比如:

web: image: nginx:alpine deploy: resources: limits: memory: 256M

6.3 一个完整的 Redis 主从编排示例

Redis 主从是面试和实操都经常遇到的需求。用 Compose 编排两个 Redis 容器,实现主从复制:

version: "3.8" services: redis-master: image: redis:6.2-alpine container_name: redis-master command: redis-server --requirepass 123456 ports: - "6379:6379" networks: - redis-net redis-slave: image: redis:6.2-alpine container_name: redis-slave command: redis-server --slaveof redis-master 6379 --masterauth 123456 ports: - "6380:6379" depends_on: - redis-master networks: - redis-net networks: redis-net:

启动:

docker compose up -d docker exec -it redis-slave redis-cli -a 123456 info replication

你能看到role:slave输出,master_link_status:up说明主从已经通了。这个示例的核心在于两个容器都在同一个自定义网络redis-net里,从容器通过redis-master这个容器名就能解析到主容器地址,这就是自定义网络内置 DNS 的威力。

7. 常见问题与排查技巧实录

7.1 Windows Docker Desktop 启动失败

Windows 上最常见的报错就是Docker Desktop failed to start because virtualisation support wasn't detected,其次是 "incompatible version of Windows"。

先看第一个。虚拟化支持没被检测到,按这个顺序排查:先进 BIOS 确认Intel VT-xAMD-V已经开启;然后打开"启用或关闭 Windows 功能",勾选"虚拟机平台"和"适用于 Linux 的 Windows 子系统";接着用管理员 PowerShell 执行wsl --set-default-version 2;最后重启,再启动 Docker Desktop。如果系统提示需要安装 WSL2 内核,按提示下载安装即可。

第二个报错是 Windows 版本过旧。Docker Desktop 对 Windows 10 的版本有要求,必须 2004 以上版本并确保系统更新补丁打全。老版本系统直接升级,或者干脆装 Docker Toolbox 这种遗留方案,但不建议,维护成本很高。

7.2 镜像拉取慢、失败,以及重启后镜像源丢失

镜像拉取慢是国内 Docker 用户最头疼的问题之一。常规思路配置镜像加速器,Docker Desktop 在 Settings -> Docker Engine 里加一段配置:

{ "registry-mirrors": [ "https://docker.m.daocloud.io" ] }

保存后 Docker Engine 会自动重启,然后重新docker pull试试。加速器地址选择要谨慎,优先选公共可信度高的镜像站,同时注意配置到多个地址轮流用,不要吊死在一棵树上。如果拉取还是失败,可以用docker pull时指定直连官方仓库的代理规避方式,不过这块限于篇幅不展开,核心思路是让 Docker 进程的网络走可用通道。

注意:配置完镜像加速器后,老 Docker Desktop 版本可能存在重启后配置丢失的情况。解决办法是确认保存成功后再重启 Docker Desktop,或者在启动脚本里动态写入配置。我自己踩过几次"昨天还能拉,今天又不行了"的坑,排查到最后发现是配置被覆盖了。

7.3 容器启动后秒退

docker ps看到容器状态是Exited (0)或者Exited (1),大概率原因有几种:

第一种,前台进程不存在。容器的主进程是一个前台进程,它一旦退出,容器就结束。比如你docker run nginx没加-d,nginx 正常前台运行;但如果你跑一个docker run ubuntu bash,bash 执行完就退出,容器自然就 Exited 了。解决办法是给容器一个常驻前台命令,比如docker run -d ubuntu tail -f /dev/null

第二种,应用启动失败了,比如 MySQL 密码参数没传、端口被占用、数据目录权限不对。这种就要看日志,docker logs <容器名>基本能找到线索。我开发时看到容器退出,第一反应永远是这几条命令轮番上:

docker ps -a docker logs --tail 50 <容器名> docker inspect <容器名>

第三种,资源不足。物理机内存不够,容器内的 Java 或 Node 进程直接被 OOM 掉。docker inspect <容器名>OOMKilled字段是true就能确认,解决办法是调整--memory限制或换大内存机器。

7.4 exec 进不去容器、权限和交互问题

docker exec进不去容器,最常见的问题是镜像里没有 bash,前面已经说过换/bin/sh。另一个问题是容器主进程状态异常,导致 exec 无法连接,这种先docker restart再 exec。

交互式操作时记住两点:-i不分配终端也能保持输入流,但光标、颜色、回车表现会不正常,所以基本都配-t组合成-it;环境变量不完整时,某些命令会报错,比如mysql命令找不到MYSQL_HOME,可以先env看看当前容器环境变量,再决定是直接补全命令还是进容器里 export。

实操心得:怎么判断容器里有没有 bash?最简单是docker exec <容器名> which bash,有输出就是有 bash,没有则执行docker exec <容器名> which sh兜底。这个技巧我在排障时几乎天天用,比盲猜快得多。

7.5 容器内文件拷贝与备份

在容器和宿主机之间拷贝文件用docker cp。方向有两种,宿主机到容器,容器到宿主机:

docker cp /host/file.txt mysql8:/tmp/ docker cp mysql8:/var/lib/mysql/mysql.sock /host/mysql.sock

注意docker cp的命令格式是docker cp <src> <container>:<dest>或反着来,容器名和路径之间是冒号。拷贝目录时记得加-r参数递归复制。这个命令在调试时很实用,比如要临时把宿主机上的配置文件覆盖进容器测试,但又不修改镜像。

备份场景下,如果要备份整个 MySQL 数据库,更好的方案是走 mysqldump,因为docker cp直接拷贝数据文件可能因为版本不一致或者表锁问题导致数据不一致。

8. 我的几个经验总结与学习建议

8.1 把命令当工具链,而不是当考试题

我见过太多人花大量时间背命令,最后收效甚微。Docker 命令的掌握方式应该是"用一个学一个",用到哪个命令就去查它的--help,理解了它在整个操作链里的位置,再用几次就记住了。别急着把所有命令都背下来,先记住runpslogsexecstoprm这一条最核心的生命周期管线,再逐步扩展。

Docker 官方文档的参考页写得不错,每次看到不熟悉的命令,我的习惯是docker <command> --help先看参数列表,再对照官方文档确认细节。命令行里直接输出帮助信息,比翻浏览器快得多。

8.2 用 alias 和脚本简化高频操作

高频命令可以做成 alias,比如我经常用dps代替docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}",把输出格式精简成只关心名字、状态和端口。这个--format技巧也很实用,能让你一屏看到更多容器,而不是被长 ID 和 Image 占满。

更复杂的场景我会写一个部署脚本,比如在服务器上发布新版应用:

#!/bin/bash docker build -t myapp:$1 . docker stop myapp || true docker rm myapp || true docker run -d --name myapp -p 8080:8080 myapp:$1

脚本第一行接收版本号参数,构建对应版本的镜像,然后停掉旧容器、删掉旧容器,最后用新镜像跑新容器。|| true的意思是即使前一个命令失败也不中断脚本,防止因为容器本来就不存在导致脚本卡住。

8.3 最后补一句关于命令安全的小提醒

Docker 的很多命令有强制参数,-f--force-v在删卷时是危险操作。docker rm -f会直接杀掉正在运行的容器,docker volume rm -f会删数据卷,删完之后数据无法恢复。我在生产环境执行删除操作前,习惯先docker ps -adocker volume ls看清楚对象,再执行删除。这不算胆小,是做运维的基本素养。

以上就是我这些年用 Docker 命令的一点积累。命令本身只是工具,真正值钱的是你清楚每一步操作背后的逻辑和可能产生的影响。把这些命令用熟悉,你会发现容器化部署并不神秘,无非是"拿着镜像跑容器,再把容器管明白"这回事。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 9:10:55

单片机智能鱼缸监控系统:实时本地闭环控制设计

简介&#xff1a;本资源是一套基于51单片机实现的智能鱼缸监控系统完整开发包&#xff0c;面向电子信息、自动化、计算机等专业的本科生课程设计、期末大作业及毕业设计实践。系统可实时监测水温、控制水泵与LED补光&#xff0c;并通过LCD1602显示状态&#xff0c;涵盖传感器驱…

作者头像 李华
网站建设 2026/9/10 9:10:09

PR Review Context

PR Review Context 【免费下载链接】oh-my-claudecode Teams-first Multi-agent orchestration for Claude Code 项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-claudecode You are reviewing PR #{{PR_NUMBER}}: {{PR_TITLE}} PR Details Author: {{PR_AU…

作者头像 李华
网站建设 2026/9/10 9:08:26

编码器阻尼力检测原理与高精度测量关键技术

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 9:08:23

主从博弈在综合能源系统调度优化中的应用与Matlab实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 9:06:44

国内主流Agent产品怎么选?平台、框架、垂直产品对照与踩坑实录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华