· 容器内常用命令

容器内常用命令

3653 字
18 分钟
容器内常用命令
StarryLin/Geek · 摘要

本文介绍Docker容器内执行命令的方法及常用命令速查,比较Bash、exec与Dockerfile RUN的差异,说明镜像容器管理要点与安全边界。

一、Docker 核心原理:镜像、容器与分层#

1.1 Docker 是什么#

Docker 是一个开源容器平台,可以将应用程序连同其依赖一起打包成可移植的独立容器。核心价值是”一次构建,处处运行”:

  • 将应用与基础设施分离,实现快速软件交付;
  • 以管理应用程序的同样方式去管理基础设施;
  • 减少开发、测试、生产环境的用户态依赖差异。

1.2 镜像(Image)与容器(Container)#

概念类比说明
镜像 Image类 / 模板只读的打包产物,包含代码、运行时、系统工具、库与配置
容器 Container类的实例镜像运行时的实体,是轻量级可执行环境

一个镜像可以启动多个容器,互不影响。

1.3 镜像分层的原理(重点)#

Docker 镜像不是一个大文件,而是由多个只读层(Layer)叠加而成:

┌───────────────────────────────┐
│ 容器可写层(读写层,临时) │ ← 未挂载路径的文件修改写在此层
├───────────────────────────────┤
│ 配置: CMD/ENTRYPOINT(非层) │ ┐
├───────────────────────────────┤ │
│ Layer 2: RUN apt install │ │ 镜像只读层(由 Dockerfile
├───────────────────────────────┤ │ RUN/COPY/ADD 等产生文件层)
│ Layer 1: FROM ubuntu:latest │ ┘
└───────────────────────────────┘
镜像 (Image) + 可写层 = 容器

由此带来的三个结论:

  1. docker pull 为什么快:公共基础层在本地存在时会被复用,只下载增量层;
  2. 容器删除、重新运行:可写层销毁重建,但镜像保持不变;
  3. docker commit 为什么能产生新镜像:把容器的可写层”固化”为新的只读层。

补充理解:容器并不是虚拟机。Linux 容器共享运行它的 Linux 内核(Docker Desktop 通常由 Linux VM 提供),通过 Namespace(隔离进程、网络、文件系统等视图)与 Cgroup(限制 CPU、内存)实现隔离,因此比虚拟机少一层完整 OS,启动更快、占用更小。

1.4 核心操作流程(先建立整体观)#

镜像管理流程:pull/build → tag → push → rmi
容器生命周期:run → start/stop → restart → rm
开发调试流程:run → exec → logs → inspect

二、环境准备#

Terminal window
# 1. 验证 Docker 安装
docker --version
docker info
# 2. 拉取后续实验所需的基础镜像
docker pull ubuntu:latest
docker pull nginx:latest
# 3. 创建练习目录
mkdir docker-practice
cd docker-practice

三、核心命令详解与操作记录#

3.1 docker run —— 创建并运行容器#

原理:docker run 本质是 docker create(创建容器)+ docker start(启动容器)的组合。如果本地不存在指定镜像,会先自动 docker pull。

Terminal window
# 基本用法
docker run <image_name>
# 给容器命名(便于后续管理)
docker run --name <container_name> <image_name>
# 后台运行 + 端口映射(详见 3.8)
docker run -d -p <host_port>:<container_port> <image_name>

3.2 docker pull —— 拉取镜像#

从 Docker 官方注册表 Docker Hub(或配置的私有仓库)拉取镜像。默认拉取 latest 标签,也可以指定版本:

Terminal window
docker pull <image_name> # 默认最新版
docker pull ubuntu:22.04 # 指定版本
docker pull --all-tags nginx # 拉取所有标签

3.3 docker ps —— 查看容器状态#

默认只显示运行中的容器,常用标志:

标志作用
-a显示所有容器(含已停止)
-l只显示最新创建的容器
-q只输出容器 ID(常配合批量操作)
Terminal window
docker ps
docker ps -a
docker ps -q

3.4 docker stop / docker start —— 停止与启动#

容器状态变化不销毁数据,可反复启停,适合维护场景:

Terminal window
docker stop <container_ID> # 停止单个容器
docker stop c1 c2 c3 # 一次停止多个容器
docker start <container_ID> # 再次启动已停止的容器

3.5 docker restart —— 重启容器#

当容器运行出现异常、无法正常提供服务时使用:

Terminal window
docker restart <container_name_or_id>

3.6 docker rm / docker rmi —— 删除容器与镜像#

Terminal window
docker rm {options} <container_name_or_ID> # 删除容器
docker rmi <image_ID or image_name> # 删除镜像

删除操作的两个经典报错(教程重点提醒):

报错 1:删除运行中的容器

Error response from daemon: cannot remove container "/amazing_lichterman":
container is running: stop the container before removing or force remove

处理:先 docker stop,或用 -f 强制删除。

报错 2:删除仍在被容器使用的镜像

Error response from daemon: conflict: unable to delete 74cc54e27dc4 (must be forced)
- image is being used by stopped container 7fafcf043627

处理:必须先删除引用该镜像的容器(哪怕是已停止的),再删除镜像。

删除顺序口诀:先删容器(rm),再删镜像(rmi)。

3.7 docker images —— 查看镜像列表#

列出本机已拉取或构建的所有镜像(含仓库名、标签、镜像 ID、大小):

Terminal window
docker images
docker images -a # 含中间层镜像

3.8 端口映射 -p —— 让容器对外提供服务#

原理:容器有独立的网络命名空间,外部默认无法直接访问容器端口。-p 在宿主机与容器之间建立 NAT 映射,把宿主机的某端口”转发”到容器端口:

Terminal window
docker run -d -p <host_port>:<container_port> <image_name>
# 例:把宿主机 8080 映射到 nginx 容器的 80
docker run -d -p 8080:80 nginx

之后通过 http://localhost:8080 即可访问容器内的 nginx。

3.9 docker exec —— 在运行中的容器内执行命令#

Terminal window
docker exec {options} <container_ID> <command>
docker exec -it <container_ID> bash # 进入容器交互式 shell

常用标志:

标志作用
-i即使未附加终端也保持 STDIN 打开(交互输入)
-t分配伪终端(美化输出、支持交互)
-d在后台执行命令
-e设置环境变量,如 -e KEY=value

注意:exec 只在容器运行中有效;容器重启后不会自动恢复执行过的命令。

3.10 docker inspect —— 查看容器/镜像细节#

返回 JSON 格式的完整元数据(状态、网络配置、挂载卷、环境变量、入口命令等),是排查问题的利器:

Terminal window
docker inspect <container_name_or_id>
# 结合 jq 只提取关键字段
docker inspect <id> | jq '.[0].State'
docker inspect <id> | jq '.[0].NetworkSettings'

3.11 docker commit —— 从容器创建新镜像#

原理:将容器可写层的改动和相关配置保存为新镜像;挂载卷中的数据不包含在提交中,相当于把”可写层固化”为”只读层”:

Terminal window
docker commit <container_name_or_id> <new_image_name>:<tag>
docker commit -m "描述信息" -a "作者" <container_id> myapp:v1

适合快速保存现场;正式场景更推荐用 Dockerfile 构建(可复现、可审计)。

3.12 docker login / docker push —— 登录与推送镜像#

Terminal window
docker login --username <用户名> # 登录 Docker Hub;位置参数是仓库地址,不是用户名
docker push <image_name>:<tag> # 推送自建镜像到远程仓库

推送前通常先 docker tag 打上仓库地址前缀的标签。

3.13 docker build —— 根据 Dockerfile 构建镜像#

Terminal window
docker build -t image_name:tag .

参数含义:

  • -t image_name:tag:指定生成的镜像名与标签;
  • .(最后的点):指定构建上下文为当前目录。

原理:Docker 会读取 Dockerfile,按指令从上到下逐条执行,RUN、COPY、ADD 等产生文件系统层,CMD、ENV 等主要更新镜像配置,最终合成完整镜像。构建过程中可通过 [+] Building 步骤输出看到分步执行(如拉取基础镜像、执行 RUN 指令、naming to ... 等)。


四、容器内执行命令的三种方式#

在实际开发中,我们经常需要在容器内安装软件包、查看文件系统、调试应用。教程给出了三种主流方法:

方法 1:直接进入容器 Bash(交互式调试)#

Terminal window
docker run -it ubuntu bash
  • -i:保持标准输入打开,可键入命令;
  • -t:分配伪终端;
  • 进入后就是 Ubuntu 容器的 shell,可随意执行命令:
Terminal window
echo CloudStudio
apt-get update

适用场景:需要长时间交互式调试、手动安装工具时。

方法 2:docker exec 在运行容器中执行单条命令#

先获取容器 ID(两种方式均可):

Terminal window
docker container ls # 或 docker ps -a

确认容器在运行(若停止先启动):

Terminal window
docker start b877a547cb33

然后执行命令:

Terminal window
docker exec -it b877a547cb33 echo "CloudStudio"
docker exec -it <container_id> bash # 相当于临时开一个 shell

适用场景:对已运行的容器执行即时操作;安装包、重启进程等会改变运行状态,并非「零侵入」(查看日志、重启进程、安装调试工具等)。

方法 3:通过 Dockerfile 在构建时预定义命令#

适合大型应用:把”应该随镜像一起固化”的命令写进 Dockerfile,随镜像分发:

FROM ubuntu:latest
RUN echo "CloudStudio"
  • FROM ubuntu:latest:指定基础镜像,后续指令都基于它构建;
  • RUN echo "CloudStudio":在构建过程中执行,输出会出现在构建日志里。

构建:

Terminal window
docker build -t sample-image .

输出 [+] Building 0.2s (6/6) FINISHED 表示 6 个构建步骤全部完成,最终 naming to docker.io/library/sample-image。

三种方法对比#

方法适用场景优势限制
直接 Bash交互式调试开发完全交互体验需容器内存在 bash
docker exec运行中单次/组合命令灵活、支持各类命令容器必须处于运行状态
Dockerfile RUN构建时预定义自动化、可复现只能在构建时执行

多命令组合执行#

利用 sh -c 可以把多条命令串起来一次执行(需容器已运行):

Terminal window
docker exec -it <container_id> sh -c "apt-get update && apt-get install -y curl && echo 'Installation complete'"
# 管道组合
docker exec <container_id> sh -c "ps aux | grep nginx"

为什么要在容器内执行命令? 四个理由:

  • 隔离:命令在容器环境中执行,不受宿主机或其他容器影响;
  • 一致性:封装用户态依赖有助于减少差异,但内核、CPU 架构、挂载及外部服务仍会影响结果;
  • 可移植性:在兼容的内核、CPU 架构和运行配置下迁移,仍需验证外部依赖;
  • 安全性:与宿主机隔离,缩小漏洞影响面、降低安全风险。

五、RUN 与 CMD 的区别(原理)#

这是初学者最容易混淆的一对指令,两者一字之差、语义完全不同:

维度RUNCMD
执行时机构建镜像时执行定义容器启动时要运行的默认命令
是否创建层会为镜像新增一个层不创建层,仅记录默认命令
典型用途安装软件包/依赖、配置环境指定容器启动后运行的主程序/脚本
覆盖行为构建期执行,运行时不可覆盖可被 docker run 后追加的命令覆盖

记忆技巧:RUN 发生在”造镜像”阶段,CMD 发生在”跑容器”阶段。

FROM ubuntu:latest
# 构建时安装,产生新层
RUN apt-get update && apt-get install -y nginx
# 启动容器时执行主程序
CMD ["nginx", "-g", "daemon off;"]

六、Docker 用户管理与安全实践#

6.1 为什么要做用户管理(原理)#

默认情况下,容器内以 Root 用户运行。这在单机实验没问题,但大规模部署时存在严重安全隐患:

  • 容器逃逸风险:一旦攻击者通过应用漏洞进入容器,若以 Root 运行且内核有漏洞,可能获得宿主机 Root 权限;
  • 权限提升:恶意代码可利用 Root 身份读写容器内一切数据;
  • 最小权限原则:进程应只拥有完成任务所需的最小权限。

6.2 操作步骤:用 USER 指令切换用户#

原理:USER 指令会记录一个”用户上下文”,其后所有指令(RUN、CMD、ENTRYPOINT)以及容器启动后的进程,都会以该用户身份执行。

步骤 1:创建 Dockerfile

FROM ubuntu:latest
RUN apt-get -y update
RUN groupadd -r user && useradd -r -g user user
USER user
  • groupadd -r user:创建系统用户组 user;
  • useradd -r -g user user:创建系统用户 user 并归入该组;
  • USER user:切换后续执行的默认用户。

步骤 2:构建镜像

Terminal window
docker build -t user-demo .

步骤 3:运行容器

Terminal window
docker run -it user-demo bash

步骤 4:验证用户

Terminal window
id # 查看当前 UID/GID
whoami # 查看用户名

运行 id 应看到当前用户已从 root 变为 user(如 uid=999(user) gid=999(user))。

(图:USER 指令验证结果 —— 原图待补)

6.3 生产级最佳实践(教程进阶)#

更完善的 Dockerfile 模板:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y sudo
# 1. 创建专用用户组与用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 2. 创建应用目录并移交权限
RUN mkdir -p /app && chown -R appuser:appuser /app
# 3. 切换到非 Root 用户
USER appuser
WORKDIR /app
# 4. 设置启动命令
CMD ["bash"]

容器运行时的加固参数:

Terminal window
docker run -d \
--name secure-app \
--user 1001:1001 \ # 指定运行 UID/GID
--read-only \ # 根文件系统只读
--tmpfs /tmp \ # 仅 /tmp 可写(内存)
--cap-drop ALL \ # 丢弃全部 Linux 内核能力
--cap-add NET_BIND_SERVICE \
-p 8080:8080 \
myapp:latest

安全最佳实践清单:非 Root 运行、专用用户、权限最小化、定期安全审计。


七、命令分类速查表#

镜像命令#

命令功能示例
docker pull拉取镜像docker pull ubuntu:latest
docker images列出镜像docker images
docker build构建镜像docker build -t myapp:1.0 .
docker push推送镜像docker push myapp:1.0
docker tag标记镜像docker tag myapp:1.0 myapp:latest
docker rmi删除镜像docker rmi image_id
docker history查看镜像历史/分层docker history ubuntu
docker save / load镜像导出/导入docker save -o app.tar app:1.0

容器命令#

命令功能示例
docker run创建并运行容器docker run -d -p 80:8080 nginx
docker ps列出容器docker ps -a
docker start/stop/restart启动/停止/重启docker restart cid
docker rm删除容器docker rm -f cid
docker exec容器内执行命令docker exec -it cid bash
docker logs查看日志docker logs -f cid
docker inspect查看详细信息docker inspect cid
docker commit容器生成新镜像docker commit cid new:1.0

网络 / 卷 / 系统命令#

分类命令功能
网络docker network create/ls/inspect/connect/disconnect/rm创建、列出、查看、连接、断开、删除网络
数据卷docker volume create/ls/inspect/rm管理持久化数据卷
系统docker version / docker info版本/系统信息
系统docker system df查看磁盘占用
系统docker system prune清理未使用资源
系统docker stats实时资源监控

八、常见报错与排查技巧#

8.1 容器删不掉#

Terminal window
docker stop <cid> # 先停止
docker rm -f <cid> # 或直接强制删除

8.2 镜像删不掉(被容器占用)#

Terminal window
docker ps -a | grep <image_name> # 找出引用该镜像的容器
docker rm $(docker ps -aq --filter ancestor=<image_name>)
docker rmi <image_name>

8.3 批量操作(效率技巧)#

Terminal window
# 停止所有容器
docker stop $(docker ps -q)
# 删除所有已退出容器
docker rm $(docker ps -aq --filter status=exited)
# 清理所有悬空镜像
docker rmi $(docker images -q --filter dangling=true)
# 一键清理所有未使用资源
docker system prune -a --volumes

8.4 命令别名(日常提效)#

Terminal window
# 写入 ~/.zshrc 或 ~/.bashrc
alias dps='docker ps'
alias dpa='docker ps -a'
alias di='docker images'
alias dexec='docker exec -it'
alias dlogs='docker logs -f'

核对资料#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

容器内常用命令
https://mjzy.tech/posts/docker/05-容器内常用命令/
作者
JIA
发布于
2026-09-05
许可协议
CC BY-NC-SA 4.0

评论区

正在加载 GitHub 评论…

Tips · 随手记
仅自己可见 · 每篇文章单独保存

文章目录