CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Docker 容器入门/课时/Docker CLI 基础
RawBlame
课时目录12 节

Docker 容器入门

  1. 01容器是什么
  2. 02安装与环境
  3. 03Docker CLI 基础
  4. 04镜像与分层
  5. 05编写 Dockerfile
  6. 06构建与优化
  7. 07镜像仓库
  8. 08数据卷与挂载
  9. 09网络
  10. 10Docker Compose
  11. 11容器安全基础
  12. 12综合练习与 K8s 方向

Docker CLI 基础

run、ps、logs、exec、stop、rm。

35 分钟

Docker CLI 基础

这一课你将能做到

  1. 用 docker run 独立起一个 Redis / Nginx 容器,并让本地 Spring Boot 应用连上容器里的 Redis
  2. 用 ps、logs、exec、inspect 四个命令完成日常排查:看状态、看日志、进容器、查配置
  3. 完整走一遍容器生命周期:创建 → 运行 → 停止 → 删除,并说清每一步数据在哪

为什么要学

CLI 是 Docker 的日常操作面。以后你排查「服务挂了」的第一反应应该是:docker ps 看它还在不在 → docker logs 看它死前说了什么 → docker exec 进去看现场。这三个动作比任何面板都快。

本课场景完全贴合 Java 开发日常:本地开发不想装 Redis,用一条命令拉起一个;Spring Boot 的 application.yml 直接连容器。学完本课,容器就从一个「概念」变成你手里的工具。

先建立图像

容器生命周期状态机(记这张图,ps -a 里的每个状态都能对上):

docker run ──→ created ──→ running ──→ exited ──→ removed
                ↑              │            │
                │              │ pause      │ stop/kill
                └── start ─────┘            ▼
                                          (可 start 复活)

本课高频命令地图:

docker run     创建并启动        docker ps       看运行中容器
docker logs    看日志            docker exec     进容器执行命令
docker stop    优雅停止          docker start    启动已停止容器
docker rm      删除容器          docker inspect  查看全部元数据

跟着做

步骤 1:起第一个容器(后台运行 + 命名)

docker run -d --name dev-redis redis:7

参数拆解:

  • -d(detach):后台运行,命令立刻返回,不占住终端。
  • --name dev-redis:给容器起名。不起名 Docker 会随机生成 hungry_turing 这类名字,引用起来很痛苦。
  • redis:7:镜像名:标签,不写标签默认拉 latest。

步骤 2:确认状态

docker ps         # 只显示运行中的容器
docker ps -a      # 显示所有容器(含已退出的),排查必备

ps -a 输出里重点看两列:STATUS(Up 2 minutes 在运行;Exited (0) 正常退出;Exited (1) 异常)和 NAMES。

步骤 3:看日志

docker logs dev-redis            # 全量日志
docker logs --tail 50 dev-redis  # 最后 50 行
docker logs -f dev-redis         # 跟踪输出(Ctrl+C 退出,不影响容器)

Java 容器里 System.out / logback 控制台输出都会进到这里。容器一启动就退出的故障,第一反应永远是 。

docker logs 容器名

步骤 4:映射端口,跑一个 Nginx

docker run -d --name dev-web -p 8080:80 nginx:1.27-alpine

-p 宿主机端口:容器端口:把容器的 80 端口转发到宿主机的 8080。浏览器打开 http://localhost:8080,看到 Nginx 欢迎页。

步骤 5:进容器执行命令

docker exec -it dev-redis redis-cli

进去后实际操作一下:

127.0.0.1:6379> set hello docker
OK
127.0.0.1:6379> get hello
"docker"
127.0.0.1:6379> exit

-it 是 -i(保持标准输入打开)+ -t(分配伪终端)的合写,交互式 shell 必加。进去执行的是 redis-cli,也可以换成 bash 通用排查:docker exec -it dev-redis bash。

步骤 6:让本地 Spring Boot 连上这个 Redis

application.yml 无需改任何代码,容器默认监听 6379 且已通过 -p 暴露(重新起一个带端口映射的):

docker rm -f dev-redis
docker run -d --name dev-redis -p 6379:6379 redis:7 --requirepass "dev123"

注意 --requirepass 直接跟在镜像名后面,是传给 redis-server 的参数。Spring Boot 配置:

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: dev123

启动 Spring Boot,写一段 redisTemplate.opsForValue().set("k","v") 验证连通。

步骤 7:停止、启动、删除

docker stop dev-redis      # 优雅停止:先发 SIGTERM,10 秒后 SIGKILL
docker ps -a               # 状态变为 Exited (0),容器还在
docker start dev-redis     # 复活,之前 exec 写入的数据(在可写层内)还在
docker rm dev-redis        # 彻底删除;运行中的要加 -f

步骤 8:inspect 查元数据,stats 看资源

docker inspect dev-redis                 # 全量 JSON:IP、挂载、环境变量、启动参数
docker inspect --format '{{.NetworkSettings.IPAddress}}' dev-redis
docker stats                             # 实时 CPU/内存,排查内存泄漏利器

讲清楚要点

  1. 容器随主进程生,随主进程死:容器里 PID 1 是启动命令本身(如 redis-server)。它一退出,容器就 Exited——这是「我的容器为什么秒退」的万能解释。
  2. stop 与 kill 的区别:stop 发 SIGTERM 给 PID 1 并等 10 秒(可用 -t 调整),Java 应用借此做优雅停机;kill 直接 SIGKILL,数据可能写一半。
  3. exec 与 attach 的区别:exec 是在容器里新开一个进程(退出不影响容器);attach 是接管 PID 1 的标准输入输出(一退出容器可能跟着死),日常一律用 exec。
  4. ps -a 是排查第一现场:Exited (0) 是正常结束;Exited (1)/(137) 要看 logs 与启动参数——137 = 128+9,通常是 OOM 被 kill 或 rm -f。
  5. --name 是你的管理锚点:后续课程的卷挂载、网络互通、compose 全部依赖容器名/服务名,从现在起养成起名习惯。

你可能会懵的地方

  • docker run ubuntu 为什么立刻退出了? ubuntu 镜像默认命令是 bash,后台模式没有输入可读,主进程直接结束。要让它活着:docker run -d ubuntu sleep 3600,或交互式 docker run -it ubuntu bash。不是 Docker 坏了,是主进程没事干。

  • 容器停止后,我 exec 时改的东西还在吗? 在可写层里,stop/start 不丢;但 rm 之后彻底消失。要让数据跨容器存活,用第 8 课的数据卷。

  • -p 6379:6379 忘了写,容器里的 Redis 还能用吗? 宿主机直连不了,但同一网络里的其他容器照样能连(第 9 课)。开发调试必须加 -p,生产上数据库类容器反而刻意不加,避免暴露。

  • 命令参数太多记不住怎么办? docker run --help 随时查;也可以反过来用工具反推:给现有容器用 docker inspect 看 Config.Cmd 与 HostConfig,就知道它是怎么起的。

  • docker ps 里 STATUS 一会 Up 一会 Restarting 是什么情况? 容器配了重启策略(如 --restart always),主进程崩溃后 Docker 反复拉起又反复崩溃。先 docker logs 找崩溃根因,别只盯着重启。

错法对照

错法问题正解
docker run redis 忘加 -d终端被占住,Ctrl+C 直接停容器后台服务加 -d
容器起了就退,反复重 run不会排查根因docker ps -a + docker logs 容器名
用 attach 调试交互容器退出导致容器停止用 exec -it
容器名随手不命名只能用随机名或 ID 操作--name 规范命名
rm 运行中容器不加 -f 报错不知道容器状态限制先 stop 再 rm,或明确用 rm -f
stop 等了 10 秒被强杀Java 优雅停机没跑完排查是否 shell 格式吞了信号(第 5 课)

卡点急救

  1. 端口被占用:docker run -p 6379:6379 报 port is already allocated。Windows 用 netstat -ano | findstr 6379 找到进程(多半是本地装的 Redis),换 -p 6380:6379 或停掉本地服务。
  2. 容器名冲突:The container name "/dev-redis" is already in use。docker rm -f dev-redis 删旧的再起。
  3. logs 没有任何输出:应用日志写文件而非控制台。要么改 logback 输出 console,要么用第 8 课的卷把日志目录挂出来。
  4. 误删了运行中的容器:如果镜像还在,重新 run 即可;容器可写层数据无法找回——这就是第 8 课要解决的问题。
  5. exec 报 container not running:先 docker ps -a 看状态,docker start 容器名 拉起来再 exec。

面试常问

  • 描述容器的生命周期? run 创建并启动,经历 created → running;stop/kill 后进入 exited,数据仍在可写层;rm 彻底删除。主进程(PID 1)退出即容器退出,重启策略可控制 exited 后的行为。

  • docker stop 的原理?如何让 Spring Boot 优雅停机? stop 先向 PID 1 发 SIGTERM,默认等 10 秒再 SIGKILL。Java 侧要保证:Dockerfile 用 exec 格式让 java 收到信号;Spring Boot 开启 graceful shutdown(server.shutdown: graceful),并把 stop 宽限期调到大于最长请求时间。

  • 如何排查一个「启动就挂」的容器? 固定三板斧:docker ps -a 看退出码 → docker logs --tail 100 容器名 看报错 → docker inspect 核对环境变量/挂载/启动命令是否符合预期。

  • exec 和 attach 的区别? exec 在容器内新建进程,退出不影响容器,是标准排查手段;attach 绑定的是主进程的 IO,退出会连带影响容器运行,基本只在看持续输出时用。

自测三问

  1. -d、-it、-p、--name 分别是什么意思?写出一条完整命令把 Redis 7 用密码 dev123 跑在 6379 端口。
  2. 容器 Exited (137) 最可能的原因是什么?如何确认?
  3. stop 后再 start,容器里之前写入 /tmp 的文件还在吗?rm 后再 run 呢?

小结一句话

CLI 六件套 run / ps / logs / exec / stop / rm 覆盖容器全生命周期——主进程决定容器生死,ps -a 与 logs 是一切排障的起点。

延伸

  • docker run 官方参考
  • 下一课预告:镜像与分层——搞懂 pull 时那一层层输出到底是什么,以及为什么镜像能被复用。
加载本节练习…
← 上一课安装与环境下一课 →镜像与分层