Docker常见命令总结

0 阅读5分钟

Docker 里最容易混的 5 组命令

容器的状态其实只有三个:up(运行中)、exited(已停止)、deleted(已删除)。

下面这 5 组命令名字很像、作用很接近,但用错了一个就是 Conflict,或者一个找不回来的容器。

总览

组容易混的一句话区别
一run / startrun 是造一台新的,start 是把旧的发动起来
二stop / kill / pausestop 优雅停、kill 强制杀、pause 只冻结不结束
三exec / attachexec 新开一个终端,attach 接管容器主进程
四rm / rm -f运行中的容器删不掉,要么先 stop,要么加 -f
五save/load / export/import前者搬镜像,后者搬容器快照

一、docker run vs docker start

一句话区别:docker run = 创建 + 启动一个新容器;docker start = 启动一个已经存在的、处于停止状态的容器。

run 的本质:首次运行时,它会检测本地是否有镜像 —— 有的话直接 start,没有的话先 pull,再 start。

docker run   = 创建 + 启动一个新容器
               如果 --name 已存在,报:
               Conflict. The container name "/xxx" is already in use

docker start = 启动一个已经存在的、处于停止状态的容器

一句话:run 是"造一台新的",start 是"把旧的发动起来"。

坑:第二次启动用 run 就会撞上 Conflict. The container name "/xxx" is already in use。这不是 Docker 出问题了,是你在让 Docker 造一个重名的容器。

run 的常用参数:

参数含义
--name给运行的容器命名
-d后台运行(detach)
-it交互式运行(常常配合 bash 进容器)
-p小写 p,指定端口映射(宿主机端口:容器端口)
-P大写 P,随机分配宿主机端口
-e设置环境变量
-v挂载数据卷(宿主机目录:容器目录)

一个把参数都用上的例子(跑 MySQL):

docker run -d \
  --name mysql-db \
  -e MYSQL_ROOT_PASSWORD="Qianshan@123" \
  -e MYSQL_DATABASE="appdb" \
  -p 3306:3306 \
  mysql:8.0.44

它起来之后怎么确认"真的能用",见文末的实操一节。

顺带记住启停四件套:

docker stop 容器名/容器ID        # 优雅停止(默认发 SIGTERM,10 秒超时后 SIGKILL)
docker start 容器名/容器ID       # 第二次启动就用 start,不要再用 run(会报 Conflict)
docker restart 容器名/容器ID     # = stop + start
docker kill 容器名/容器ID        # 直接 SIGKILL(强制,不优雅)

二、docker stop vs docker kill vs docker pause

三条都跟"让它停下来"有关,但停的方式完全不同。

命令干了什么容器状态变成怎么恢复
stop发 SIGTERM,10 秒没退再发 SIGKILLExitedstart 重新启动
kill直接发 SIGKILL,不给反应时间Exitedstart 重新启动
pause用 cgroup freezer 冻结进程(不释放资源)Pausedunpause 继续跑
docker pause 容器名/ID        # 暂停(进程被冻结,还在内存里)
docker unpause 容器名/ID      # 恢复

怎么选:

  • 正常维护 → stop(给进程机会把手上的事做完)
  • 进程卡死不听话 → kill
  • 只是临时不想让它占 CPU → pause

面试会问:「怎么临时冻结一个容器」——答案是 pause,不是 stop。两者的区别在于要不要释放资源:pause 是冻结,内存还占着;stop 是结束进程,容器变 Exited。


三、docker exec vs docker attach

docker execdocker attach
是否新进程是(在容器里新开一个进程)否(连到主进程的 stdin/stdout)
退出方式exit 只退出这个进程,容器继续运行按 Ctrl+C 会把信号发给主进程,容器可能直接退出
推荐度推荐,排障首选少用,容易误杀容器
docker exec -it 容器ID bash      # 新起一个进程(新终端),不会影响容器主进程
docker attach 容器ID             # 直接接到容器主进程的终端上
                                 # 不启动新的终端,如果按 ctrl+c,容器会自动退出

一句话记忆:要进容器就用 docker exec -it,别用 attach —— attach 按 Ctrl+C 会把容器弄停。


四、docker rm vs docker rm -f

docker rm 容器名/ID            # 删除已停止的容器
docker rm -f 容器名/ID         # 强制删除(不管它有没有在运行)

坑:正在运行的容器直接 docker rm 会报错:

Error response from daemon: You cannot remove a running container ...
Stop the container before attempting removal or force remove

要么先 docker stop,要么加 -f。

顺带一个批量清理的写法:

docker rm -f $(docker ps -qa)      # 强制删除所有容器

(-qa = 只输出所有容器的 ID,脚本里批量操作用)


五、docker save/load vs docker export/import

这一组最容易搞混,因为一个搬镜像,一个搬容器。

# 导出(在能上网的机器上)
docker save -o nginx.tar nginx:1.24
ls -lh nginx.tar                # 检验:生成一个 tar 文件

# 导入(在内网机器上)
docker load -i nginx.tar
docker images | grep nginx      # 检验:能看到 nginx:1.24
# 新写法(等价)
docker image save -o nginx.tar nginx:1.24
docker image load -i nginx.tar

坑(关键区别): docker save 保存的是镜像(含 tag 和所有层),docker load 之后 tag 还在; 而 docker export 导出的是容器的文件系统快照,docker import 回来会丢掉 tag 和历史层。

别混。

怎么选:内网没有外网要搬镜像 → save / load;想把一个容器的当前文件系统带走 → export / import(但要接受 tag 和层历史丢失)。


附:从跑起一个 MySQL,到"真的能用"

容器起来了不等于服务能用。以第一节那个 MySQL 为例,完整验证是 5 步:

docker ps                                  # 1) 容器在运行
docker logs mysql-db                       # 2) 看启动日志(找 "ready for connections")
docker port mysql-db                       # 3) 看端口映射(0.0.0.0:3306 -> 3306/tcp)
ss -lntp | grep 3306                       # 4) 宿主机确实在监听 3306
mysql -uroot -p'Qianshan@123' -h 127.0.0.1 -P 3306 -e "show databases;"
                                           # 5) 真正连进去(能看到 appdb 才算成功)

第 5 步是"闭环"的关键:光看到容器 Up 不算成功,能连上业务端口才算。

这也是面试时"你怎么确认服务真的起来了"的标准答法。