容器内常用命令
本文介绍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) + 可写层 = 容器由此带来的三个结论:
docker pull为什么快:公共基础层在本地存在时会被复用,只下载增量层;- 容器删除、重新运行:可写层销毁重建,但镜像保持不变;
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二、环境准备
# 1. 验证 Docker 安装docker --versiondocker info
# 2. 拉取后续实验所需的基础镜像docker pull ubuntu:latestdocker pull nginx:latest
# 3. 创建练习目录mkdir docker-practicecd docker-practice三、核心命令详解与操作记录
3.1 docker run —— 创建并运行容器
原理:docker run 本质是 docker create(创建容器)+ docker start(启动容器)的组合。如果本地不存在指定镜像,会先自动 docker pull。
# 基本用法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 标签,也可以指定版本:
docker pull <image_name> # 默认最新版docker pull ubuntu:22.04 # 指定版本docker pull --all-tags nginx # 拉取所有标签3.3 docker ps —— 查看容器状态
默认只显示运行中的容器,常用标志:
| 标志 | 作用 |
|---|---|
-a | 显示所有容器(含已停止) |
-l | 只显示最新创建的容器 |
-q | 只输出容器 ID(常配合批量操作) |
docker psdocker ps -adocker ps -q3.4 docker stop / docker start —— 停止与启动
容器状态变化不销毁数据,可反复启停,适合维护场景:
docker stop <container_ID> # 停止单个容器docker stop c1 c2 c3 # 一次停止多个容器docker start <container_ID> # 再次启动已停止的容器3.5 docker restart —— 重启容器
当容器运行出现异常、无法正常提供服务时使用:
docker restart <container_name_or_id>3.6 docker rm / docker rmi —— 删除容器与镜像
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、大小):
docker imagesdocker images -a # 含中间层镜像3.8 端口映射 -p —— 让容器对外提供服务
原理:容器有独立的网络命名空间,外部默认无法直接访问容器端口。-p 在宿主机与容器之间建立 NAT 映射,把宿主机的某端口”转发”到容器端口:
docker run -d -p <host_port>:<container_port> <image_name># 例:把宿主机 8080 映射到 nginx 容器的 80docker run -d -p 8080:80 nginx之后通过 http://localhost:8080 即可访问容器内的 nginx。
3.9 docker exec —— 在运行中的容器内执行命令
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 格式的完整元数据(状态、网络配置、挂载卷、环境变量、入口命令等),是排查问题的利器:
docker inspect <container_name_or_id># 结合 jq 只提取关键字段docker inspect <id> | jq '.[0].State'docker inspect <id> | jq '.[0].NetworkSettings'3.11 docker commit —— 从容器创建新镜像
原理:将容器可写层的改动和相关配置保存为新镜像;挂载卷中的数据不包含在提交中,相当于把”可写层固化”为”只读层”:
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 —— 登录与推送镜像
docker login --username <用户名> # 登录 Docker Hub;位置参数是仓库地址,不是用户名docker push <image_name>:<tag> # 推送自建镜像到远程仓库推送前通常先 docker tag 打上仓库地址前缀的标签。
3.13 docker build —— 根据 Dockerfile 构建镜像
docker build -t image_name:tag .参数含义:
-t image_name:tag:指定生成的镜像名与标签;.(最后的点):指定构建上下文为当前目录。
原理:Docker 会读取 Dockerfile,按指令从上到下逐条执行,
RUN、COPY、ADD等产生文件系统层,CMD、ENV等主要更新镜像配置,最终合成完整镜像。构建过程中可通过[+] Building步骤输出看到分步执行(如拉取基础镜像、执行 RUN 指令、naming to ...等)。
四、容器内执行命令的三种方式
在实际开发中,我们经常需要在容器内安装软件包、查看文件系统、调试应用。教程给出了三种主流方法:
方法 1:直接进入容器 Bash(交互式调试)
docker run -it ubuntu bash-i:保持标准输入打开,可键入命令;-t:分配伪终端;- 进入后就是 Ubuntu 容器的 shell,可随意执行命令:
echo CloudStudioapt-get update适用场景:需要长时间交互式调试、手动安装工具时。
方法 2:docker exec 在运行容器中执行单条命令
先获取容器 ID(两种方式均可):
docker container ls # 或 docker ps -a确认容器在运行(若停止先启动):
docker start b877a547cb33然后执行命令:
docker exec -it b877a547cb33 echo "CloudStudio"docker exec -it <container_id> bash # 相当于临时开一个 shell适用场景:对已运行的容器执行即时操作;安装包、重启进程等会改变运行状态,并非「零侵入」(查看日志、重启进程、安装调试工具等)。
方法 3:通过 Dockerfile 在构建时预定义命令
适合大型应用:把”应该随镜像一起固化”的命令写进 Dockerfile,随镜像分发:
FROM ubuntu:latestRUN echo "CloudStudio"FROM ubuntu:latest:指定基础镜像,后续指令都基于它构建;RUN echo "CloudStudio":在构建过程中执行,输出会出现在构建日志里。
构建:
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 可以把多条命令串起来一次执行(需容器已运行):
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 的区别(原理)
这是初学者最容易混淆的一对指令,两者一字之差、语义完全不同:
| 维度 | RUN | CMD |
|---|---|---|
| 执行时机 | 构建镜像时执行 | 定义容器启动时要运行的默认命令 |
| 是否创建层 | 会为镜像新增一个层 | 不创建层,仅记录默认命令 |
| 典型用途 | 安装软件包/依赖、配置环境 | 指定容器启动后运行的主程序/脚本 |
| 覆盖行为 | 构建期执行,运行时不可覆盖 | 可被 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:latestRUN apt-get -y updateRUN groupadd -r user && useradd -r -g user userUSER usergroupadd -r user:创建系统用户组user;useradd -r -g user user:创建系统用户user并归入该组;USER user:切换后续执行的默认用户。
步骤 2:构建镜像
docker build -t user-demo .步骤 3:运行容器
docker run -it user-demo bash步骤 4:验证用户
id # 查看当前 UID/GIDwhoami # 查看用户名运行 id 应看到当前用户已从 root 变为 user(如 uid=999(user) gid=999(user))。
(图:USER 指令验证结果 —— 原图待补)
6.3 生产级最佳实践(教程进阶)
更完善的 Dockerfile 模板:
FROM ubuntu:latestRUN 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 appuserWORKDIR /app
# 4. 设置启动命令CMD ["bash"]容器运行时的加固参数:
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 容器删不掉
docker stop <cid> # 先停止docker rm -f <cid> # 或直接强制删除8.2 镜像删不掉(被容器占用)
docker ps -a | grep <image_name> # 找出引用该镜像的容器docker rm $(docker ps -aq --filter ancestor=<image_name>)docker rmi <image_name>8.3 批量操作(效率技巧)
# 停止所有容器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 --volumes8.4 命令别名(日常提效)
# 写入 ~/.zshrc 或 ~/.bashrcalias dps='docker ps'alias dpa='docker ps -a'alias di='docker images'alias dexec='docker exec -it'alias dlogs='docker logs -f'核对资料
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
评论区
正在加载 GitHub 评论…