Add more content

This commit is contained in:
Baohua Yang
2026-01-30 16:48:39 -08:00
parent c58f61dbed
commit fec2e506d9
39 changed files with 8202 additions and 1063 deletions

View File

@@ -1,56 +1,264 @@
# 进入容器
在使用 `-d` 参数时容器启动后会进入后台
## 为什么需要进入容器
某些时候需要进入容器进行操作包括使用 `docker attach` 命令或 `docker exec` 命令推荐大家使用 `docker exec` 命令原因会在下面说明
使用 `-d` 参数启动容器后容器在后台运行以下场景需要进入容器内部操作
## `attach` 命令
| 场景 | 示例 |
|------|------|
| **调试问题** | 查看日志检查配置排查错误 |
| **临时操作** | 执行数据库迁移清理缓存 |
| **检查状态** | 查看进程网络连接文件系统 |
| **开发测试** | 交互式测试命令验证环境 |
下面示例如何使用 `docker attach` 命令
## 两种进入方式
Docker 提供两种进入容器的命令
| 命令 | 推荐程度 | 特点 |
|------|---------|------|
| `docker exec` | **推荐** | 启动新进程退出不影响容器 |
| `docker attach` | 谨慎使用 | 附加到主进程退出可能停止容器 |
---
## docker exec推荐
### 基本用法
```bash
$ docker run -dit ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
# 进入容器并启动交互式 shell
$ docker exec -it 容器名 /bin/bash
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia
$ docker attach 243c
root@243c32535da7:/#
# 或使用 sh适用于 Alpine 等精简镜像)
$ docker exec -it 容器名 /bin/sh
```
*注意* 如果从这个 stdin exit会导致容器的停止
### 参数说明
## `exec` 命令
| 参数 | 作用 |
|------|------|
| `-i` | 保持标准输入打开interactive |
| `-t` | 分配伪终端TTY |
| `-it` | 两者组合获得完整交互体验 |
| `-u` | 指定用户 `-u root` |
| `-w` | 指定工作目录 |
| `-e` | 设置环境变量 |
### `-i` `-t` 参数
`docker exec` 后边可以跟多个参数这里主要说明 `-i` `-t` 参数
只用 `-i` 参数时由于没有分配伪终端界面没有我们熟悉的 Linux 命令提示符但命令执行结果仍然可以返回
`-i` `-t` 参数一起使用时则可以看到我们熟悉的 Linux 命令提示符
### 示例
```bash
$ docker run -dit ubuntu
69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6
# 启动一个后台容器
$ docker run -dit --name myubuntu ubuntu
69d137adef7a...
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69d137adef7a ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles
# 进入容器(交互式 shell
$ docker exec -it myubuntu bash
root@69d137adef7a:/# ls
bin boot dev etc home lib ...
root@69d137adef7a:/# exit
$ docker exec -i 69d1 bash
ls
bin
# 容器仍在运行!
$ docker ps
CONTAINER ID IMAGE STATUS NAMES
69d137adef7a ubuntu Up 2 minutes myubuntu
```
### 执行单条命令
不进入交互模式直接执行命令
```bash
# 查看容器内进程
$ docker exec myubuntu ps aux
# 查看配置文件
$ docker exec myubuntu cat /etc/nginx/nginx.conf
# 以 root 用户执行
$ docker exec -u root myubuntu apt update
```
### 只用 -i 不用 -t 的区别
```bash
# 只用 -i可以执行命令但没有提示符
$ docker exec -i myubuntu bash
ls # 输入命令
bin # 输出结果
boot
dev
...
$ docker exec -it 69d1 bash
root@69d137adef7a:/#
# 用 -it有完整的终端体验
$ docker exec -it myubuntu bash
root@69d137adef7a:/# # 有提示符
```
如果从这个 stdin exit不会导致容器的停止这就是为什么推荐大家使用 `docker exec` 的原因
> 💡 通常使用 `-it` 组合只有在脚本中需要通过管道传入命令时才只用 `-i`
更多参数说明请使用 `docker exec --help` 查看
---
## docker attach谨慎使用
### 基本用法
```bash
$ docker attach 容器名
```
### 工作原理
`attach` 会附加到容器的**主进程**PID 1的标准输入输出
```
┌─────────────────────────────────────────┐
│ 容器 │
│ ┌─────────────────────────────────┐ │
│ │ PID 1: /bin/bash (主进程) │◄───┼─── docker attach 附加到这里
│ │ └─ 你的输入直接发送到主进程 │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
```
### 示例
```bash
# 启动容器
$ docker run -dit --name myubuntu ubuntu
243c32535da7...
# 附加到容器
$ docker attach myubuntu
root@243c32535da7:/#
```
### 重要警告
** attach 会话中输入 `exit` 或按 `Ctrl+D` 会导致容器停止**
```bash
$ docker attach myubuntu
root@243c32535da7:/# exit # 这会停止容器!
$ docker ps
CONTAINER ID IMAGE STATUS NAMES
243c32535da7 ubuntu Exited (0) 2 seconds ago myubuntu
```
**原因**attach 附加到主进程退出主进程就等于退出容器
### 安全退出 attach
使用 `Ctrl+P` 然后 `Ctrl+Q` 可以从 attach 会话中**分离**而不停止容器
```bash
$ docker attach myubuntu
root@243c32535da7:/#
# 按 Ctrl+P 然后 Ctrl+Q
read escape sequence
$ docker ps # 容器仍在运行
CONTAINER ID IMAGE STATUS NAMES
243c32535da7 ubuntu Up 5 minutes myubuntu
```
---
## exec vs attach 对比
| 特性 | docker exec | docker attach |
|------|-------------|---------------|
| **工作方式** | 在容器内启动新进程 | 附加到主进程 |
| **退出影响** | 不影响容器 | 可能停止容器 |
| **多终端** | 可以开多个 | 共享同一个会话 |
| **适用场景** | 调试临时操作 | 查看主进程输出 |
| **推荐程度** | 推荐 | 特殊场景使用 |
```
docker exec docker attach
┌─────────────────────┐ ┌─────────────────────┐
│ 容器 │ │ 容器 │
│ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ PID 1: nginx │ │ │ │ PID 1: bash │◄─┼── 附加到主进程
│ ├───────────────┤ │ │ └───────────────┘ │
│ │ PID 50: bash │◄─┼── 新进程 │ │
│ └───────────────┘ │ │ │
└─────────────────────┘ └─────────────────────┘
退出 bash 不影响 nginx 退出 bash 容器停止
```
---
## 最佳实践
### 1. 首选 docker exec
```bash
# 进入容器调试
$ docker exec -it myapp bash
# 查看日志
$ docker exec myapp tail -f /var/log/app.log
# 执行数据库迁移
$ docker exec myapp python manage.py migrate
```
### 2. 生产环境避免进入容器
笔者建议生产环境应尽量避免进入容器直接操作而是通过
- 日志系统查看日志 `docker logs` 或集中式日志
- 监控系统查看状态
- 重新部署而非手动修改
### 3. shell 镜像的处理
某些精简镜像如基于 `scratch` `distroless`没有 shell
```bash
# 这会失败
$ docker exec -it myapp bash
OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found
# 解决方案使用调试容器Docker Desktop 或 Kubernetes debug
$ docker debug myapp
```
---
## 常见问题
### Q: exec 进入后看不到其他终端的操作
这是正常的exec 启动的是独立进程多个 exec 会话互不影响
### Q: 容器没有 bash
尝试使用 sh
```bash
$ docker exec -it myapp /bin/sh
```
### Q: 需要 root 权限
```bash
$ docker exec -u root -it myapp bash
```
---
## 本章小结
| 需求 | 推荐命令 |
|------|---------|
| 进入容器调试 | `docker exec -it 容器名 bash` |
| 执行单条命令 | `docker exec 容器名 命令` |
| 查看主进程输出 | `docker attach 容器名`慎用 |
## 延伸阅读
- [后台运行](daemon.md)理解容器主进程
- [查看容器](ls.md)列出和过滤容器
- [容器日志](logs.md)查看容器输出

View File

@@ -1,10 +1,19 @@
# 后台运行
更多的时候需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下此时可以通过添加 `-d` 参数来实现
在生产环境中我们通常需要容器持续运行不受终端关闭的影响本节将深入讲解如何让容器在后台运行以及理解容器生命周期的核心概念
下面举两个例子来说明一下
## 核心概念前台 vs 后台
如果不使用 `-d` 参数运行容器
当你在终端运行一个程序时有两种模式
- **前台运行**程序占用当前终端输出直接显示关闭终端程序就停止
- **后台运行**程序在后台执行不占用终端终端关闭也不影响程序
Docker 容器默认是**前台运行**使用 `-d`detach参数可以让容器在后台运行
## 基本使用
### 前台运行默认
```bash
$ docker run ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
@@ -14,33 +23,196 @@ hello world
hello world
```
容器会把输出的结果 (STDOUT) 打印到宿主机上面
容器会把输出的结果STDOUT打印到宿主机上面此时
- 终端被占用无法执行其他命令
- `Ctrl+C` 会终止容器
- 关闭终端窗口容器也会停止
如果使用 `-d` 参数运行容器
### 后台运行使用 -d 参数
```bash
$ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
```
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 `docker logs` 查看)
使用 `-d` 参数后
- 容器在后台运行
- 返回容器的完整 ID
- 终端立即释放可以继续执行其他命令
- 输出不会直接显示需要用 `docker logs` 查看
**** 容器是否会长久运行是和 `docker run` 指定的命令有关 `-d` 参数无关
## 深入理解容器为什么会"立即退出"
使用 `-d` 参数启动后会返回一个唯一的 id也可以通过 `docker container ls` 命令来查看容器信息
> **这是初学者最常遇到的困惑** 理解这个问题你就理解了 Docker 的核心设计理念
很多人尝试这样启动容器
```bash
$ docker run -d ubuntu:24.04
```
然后用 `docker ps` 查看发现容器根本不在运行这是为什么
### 核心原理容器的生命周期与主进程绑定
```
┌─────────────────────────────────────────────────────────────────────┐
│ Docker 容器的生命周期 = 容器内 PID 1 进程的生命周期 │
│ │
│ 主进程启动 → 容器运行 │
│ 主进程退出 → 容器停止 │
└─────────────────────────────────────────────────────────────────────┘
```
当你运行 `docker run -d ubuntu:24.04`
1. 容器启动
2. 没有指定命令默认执行 `/bin/bash`
3. 但没有交互式终端没有 `-it` 参数bash 发现没有输入源
4. bash 立即退出
5. 主进程退出容器停止
**关键理解**
- `-d` 参数**不是**让容器"一直运行"
- `-d` 参数是让容器"在后台运行"能运行多久取决于主进程
### 常见的"立即退出"场景
| 场景 | 原因 | 解决方案 |
|------|------|---------|
| `docker run -d ubuntu` | 默认 bash 无输入立即退出 | 指定长期运行的命令 |
| `docker run -d nginx` 后改了配置 | 配置错误导致 nginx 启动失败 | 查看 `docker logs` |
| 自定义镜像容器启动即退 | Dockerfile CMD 执行完毕 | 确保 CMD 是前台进程 |
## 查看后台容器
### 查看运行中的容器
```bash
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b2dc01fe0f ubuntu:24.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
```
要获取容器的输出信息可以通过 `docker container logs` 命令
### 查看容器输出日志
```bash
$ docker container logs [container ID or NAMES]
$ docker container logs 77b2dc01fe0f
hello world
hello world
hello world
. . .
...
```
**实时查看日志**类似 `tail -f`
```bash
$ docker container logs -f 77b2dc01fe0f
```
### 查看已停止的容器
```bash
$ docker container ls -a
```
加上 `-a` 参数可以看到所有容器包括已停止的这对于调试"容器启动即退出"的问题非常有用
## 最佳实践
### 1. 长期运行的服务使用 -d
```bash
# Web 服务器
$ docker run -d -p 80:80 nginx
# 数据库
$ docker run -d -p 3306:3306 mysql:8
# 缓存服务
$ docker run -d -p 6379:6379 redis
```
### 2. 调试时先用前台模式
当容器启动有问题时**去掉 `-d` 参数**可以直接看到输出和错误
```bash
# 有问题的容器,先前台运行看看发生了什么
$ docker run myimage:latest
```
### 3. 使用 --rm 自动清理
对于一次性任务使用 `--rm` 参数让容器退出后自动删除
```bash
$ docker run --rm ubuntu:24.04 echo "Hello, World!"
Hello, World!
# 容器执行完后自动删除
```
### 4. 配合日志查看
```bash
# 后台启动
$ docker run -d --name myapp myimage:latest
# 查看最近 100 行日志
$ docker logs --tail 100 myapp
# 实时跟踪日志
$ docker logs -f myapp
# 查看带时间戳的日志
$ docker logs -t myapp
```
## 常见问题排查
### Q: 容器启动后立即退出
1. **查看退出状态码**
```bash
$ docker ps -a --filter "name=mycontainer"
# 查看 STATUS 列,如 "Exited (1)" 表示异常退出
```
2. **查看容器日志**
```bash
$ docker logs mycontainer
```
3. **以交互模式调试**
```bash
$ docker run -it myimage:latest /bin/sh
# 进入容器手动执行命令,查找问题
```
### Q: 容器在后台运行但无法访问服务
1. **检查端口映射**
```bash
$ docker port mycontainer
```
2. **检查容器内服务状态**
```bash
$ docker exec mycontainer ps aux
```
### Q: 如何让已经在后台运行的容器回到前台
使用 `docker attach`
```bash
$ docker attach mycontainer
```
> **注意**`attach` 会连接到容器的主进程如果主进程不是交互式的你可能只能看到输出使用 `Ctrl+P` `Ctrl+Q` 可以安全退出而不停止容器
## 延伸阅读
- [进入容器](attach_exec.md)如何进入正在运行的容器执行命令
- [容器日志](../appendix/best_practices.md)生产环境的日志管理最佳实践
- [HEALTHCHECK 健康检查](../image/dockerfile/healthcheck.md)自动检测容器内服务是否正常
- [Docker Compose](../compose/README.md)管理多个后台容器的更好方式

View File

@@ -1,18 +1,238 @@
# 删除容器
可以使用 `docker container rm` 来删除一个处于终止状态的容器例如
## 基本用法
使用 `docker rm` 删除已停止的容器
```bash
$ docker container rm trusting_newton
trusting_newton
$ docker rm 容器名或ID
```
如果要删除一个运行中的容器可以添加 `-f` 参数Docker 会发送 `SIGKILL` 信号给容器
> 💡 `docker rm` `docker container rm` 的简写两者等效
# 清理所有处于终止状态的容器
---
`docker container ls -a` 命令可以查看所有已经创建的包括终止状态的容器如果数量太多要一个个删除可能会很麻烦用下面的命令可以清理掉所有处于终止状态的容器
## 删除选项
| 选项 | 说明 | 示例 |
|------|------|------|
| 无参数 | 删除已停止的容器 | `docker rm mycontainer` |
| `-f` | 强制删除运行中的容器 | `docker rm -f mycontainer` |
| `-v` | 同时删除关联的匿名卷 | `docker rm -v mycontainer` |
### 删除已停止的容器
```bash
$ docker rm mycontainer
mycontainer
```
### 强制删除运行中的容器
```bash
# 不加 -f 会报错
$ docker rm running_container
Error: cannot remove running container
# 加 -f 强制删除
$ docker rm -f running_container
running_container
```
> 强制删除会向容器发送 SIGKILL 信号可能导致数据丢失建议先 `docker stop` 优雅停止
### 删除容器及其数据卷
```bash
# 删除容器时同时删除其匿名卷
$ docker rm -v mycontainer
```
> 注意只删除匿名卷命名卷不会被删除
---
## 批量删除
### 删除所有已停止的容器
```bash
# 方式一:使用 prune 命令(推荐)
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
abc123...
def456...
Total reclaimed space: 150MB
# 方式二:不提示确认
$ docker container prune -f
```
### 删除所有容器包括运行中的
```bash
# 先停止所有容器,再删除
$ docker stop $(docker ps -q)
$ docker rm $(docker ps -aq)
# 或者直接强制删除
$ docker rm -f $(docker ps -aq)
```
### 按条件删除
```bash
# 删除所有已退出的容器
$ docker rm $(docker ps -aq -f status=exited)
# 删除名称包含 "test" 的容器
$ docker rm $(docker ps -aq -f name=test)
# 删除 24 小时前创建的容器
$ docker container prune --filter "until=24h"
```
---
## 常用过滤条件
`docker ps` 的过滤条件可以配合 `rm` 使用
| 过滤条件 | 说明 | 示例 |
|---------|------|------|
| `status=exited` | 已退出的容器 | `-f status=exited` |
| `status=created` | 已创建未启动 | `-f status=created` |
| `name=xxx` | 名称匹配 | `-f name=myapp` |
| `ancestor=xxx` | 基于某镜像创建 | `-f ancestor=nginx` |
| `before=xxx` | 在某容器之前创建 | `-f before=mycontainer` |
| `since=xxx` | 在某容器之后创建 | `-f since=mycontainer` |
### 示例
```bash
# 删除所有基于 nginx 镜像的容器
$ docker rm $(docker ps -aq -f ancestor=nginx)
# 删除所有创建后未启动的容器
$ docker rm $(docker ps -aq -f status=created)
```
---
## 容器与镜像的依赖关系
> 有容器依赖的镜像无法删除
```bash
# 尝试删除有容器依赖的镜像
$ docker image rm nginx
Error: image is being used by stopped container abc123
# 需要先删除依赖该镜像的容器
$ docker rm abc123
$ docker image rm nginx
```
---
## 清理策略建议
### 开发环境
```bash
# 定期清理已停止的容器
$ docker container prune -f
# 一键清理所有未使用资源
$ docker system prune -f
```
### 生产环境
```bash
# 使用 --rm 参数运行临时容器
$ docker run --rm ubuntu echo "Hello"
# 容器退出后自动删除
# 定期清理(设置保留时间)
$ docker container prune --filter "until=168h" # 保留 7 天内的
```
### 完整清理脚本
```bash
#!/bin/bash
# cleanup.sh - Docker 资源清理脚本
echo "清理已停止的容器..."
docker container prune -f
echo "清理未使用的镜像..."
docker image prune -f
echo "清理未使用的数据卷..."
docker volume prune -f
echo "清理未使用的网络..."
docker network prune -f
echo "清理完成!"
docker system df
```
---
## 常见问题
### Q: 容器无法删除
```bash
Error: container is running
```
解决先停止容器或使用 `-f` 强制删除
```bash
$ docker stop mycontainer
$ docker rm mycontainer
# 或
$ docker rm -f mycontainer
```
### Q: 删除后磁盘空间没释放
可能原因
1. 容器的数据卷未删除使用 `-v` 参数
2. 镜像未删除
3. 构建缓存未清理
解决
```bash
# 查看空间占用
$ docker system df
# 完整清理
$ docker system prune -a --volumes
```
---
## 本章小结
| 操作 | 命令 |
|------|------|
| 删除已停止容器 | `docker rm 容器名` |
| 强制删除运行中容器 | `docker rm -f 容器名` |
| 删除容器及匿名卷 | `docker rm -v 容器名` |
| 清理所有已停止容器 | `docker container prune` |
| 删除所有容器 | `docker rm -f $(docker ps -aq)` |
## 延伸阅读
- [终止容器](stop.md)优雅停止容器
- [删除镜像](../image/rm.md)清理镜像
- [数据卷](../data_management/volume.md)数据卷管理

View File

@@ -1,55 +1,166 @@
# 启动容器
启动容器有两种方式一种是基于镜像新建一个容器并启动另外一个是将在终止状态`exited`的容器重新启动
## 启动方式概述
因为 Docker 的容器实在太轻量级了很多时候用户都是随时删除和新创建容器
启动容器有两种方式
- **新建并启动**基于镜像创建新容器
- **重新启动**将已终止的容器重新运行
由于 Docker 容器非常轻量实际使用中常常是随时删除和新建容器而不是反复重启同一个容器
## 新建并启动
所需要的命令主要为 `docker run`
### 基本语法
例如下面的命令输出一个 Hello World之后终止容器
```bash
docker run [选项] 镜像 [命令] [参数...]
```
### 最简单的例子
输出 "Hello World" 后容器自动终止
```bash
$ docker run ubuntu:24.04 /bin/echo 'Hello world'
Hello world
```
跟在本地直接执行 `/bin/echo 'hello world'` 几乎感觉不出任何区别
直接执行 `/bin/echo 'Hello world'` 几乎没有区别但实际上已经启动了一个完整的 Ubuntu 容器来执行这条命令
下面的命令则启动一个 bash 终端允许用户进行交互
### 交互式容器
启动一个可以交互的 bash 终端
```bash
$ docker run -t -i ubuntu:24.04 /bin/bash
$ docker run -it ubuntu:24.04 /bin/bash
root@af8bae53bdd3:/#
```
其中`-t` 选项让Docker分配一个伪终端pseudo-tty并绑定到容器的标准输入上 `-i` 则让容器的标准输入保持打开
**参数说明**
在交互模式下用户可以通过所创建的终端来输入命令例如
| 参数 | 作用 |
|------|------|
| `-i` | 保持标准输入stdin打开允许输入 |
| `-t` | 分配伪终端pseudo-TTY提供终端界面 |
| `-it` | 两者组合使用获得交互式终端 |
在交互模式下可以执行命令
```bash
root@af8bae53bdd3:/# pwd
/
root@af8bae53bdd3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@af8bae53bdd3:/# exit # 退出容器
```
当利用 `docker run` 来创建容器时Docker 在后台运行的标准操作包括
## docker run 的完整流程
* 检查本地是否存在指定的镜像不存在就从 [registry](../repository/README.md) 下载
* 利用镜像创建并启动一个容器
* 分配一个文件系统并在只读的镜像层外面挂载一层可读写层
* 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
* 从地址池配置一个 ip 地址给容器
* 执行用户指定的应用程序
* 执行完毕后容器被终止
执行 `docker run` Docker 在后台完成以下操作
```
┌─────────────────────────────────────────────────────────────────────┐
│ docker run ubuntu:24.04 /bin/echo "Hello" │
└───────────────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 1. 检查本地是否有 ubuntu:24.04 镜像 │
│ ├── 有 → 使用本地镜像 │
│ └── 无 → 从 Registry 下载 │
├─────────────────────────────────────────────────────────────────────┤
│ 2. 创建容器 │
│ • 基于镜像的只读层 │
│ • 添加一层可读写层(容器存储层) │
├─────────────────────────────────────────────────────────────────────┤
│ 3. 配置网络 │
│ • 创建虚拟网卡 │
│ • 分配 IP 地址 │
│ • 连接到 Docker 网桥 │
├─────────────────────────────────────────────────────────────────────┤
│ 4. 启动容器,执行指定命令 │
├─────────────────────────────────────────────────────────────────────┤
│ 5. 命令执行完毕,容器停止 │
└─────────────────────────────────────────────────────────────────────┘
```
## 常用启动选项
### 基础选项
| 选项 | 说明 | 示例 |
|------|------|------|
| `-d` | 后台运行detach | `docker run -d nginx` |
| `-it` | 交互式终端 | `docker run -it ubuntu bash` |
| `--name` | 指定容器名称 | `docker run --name myapp nginx` |
| `--rm` | 退出后自动删除容器 | `docker run --rm ubuntu echo hi` |
### 端口映射
```bash
# 将容器的 80 端口映射到宿主机的 8080 端口
$ docker run -d -p 8080:80 nginx
# 随机映射端口
$ docker run -d -P nginx
# 只绑定到 localhost
$ docker run -d -p 127.0.0.1:8080:80 nginx
```
### 数据卷挂载
```bash
# 挂载命名卷
$ docker run -v mydata:/data nginx
# 挂载宿主机目录
$ docker run -v /host/path:/container/path nginx
# 只读挂载
$ docker run -v /host/path:/container/path:ro nginx
```
### 环境变量
```bash
# 设置单个环境变量
$ docker run -e MYSQL_ROOT_PASSWORD=secret mysql
# 从文件加载环境变量
$ docker run --env-file .env myapp
```
### 资源限制
```bash
# 限制内存
$ docker run -m 512m nginx
# 限制 CPU
$ docker run --cpus=1.5 nginx
```
## 启动已终止容器
可以利 `docker container start` 命令直接将一个已经终止`exited`的容器启动运行
使 `docker start` 重新启动已停止的容器
容器的核心为所执行的应用程序所需要的资源都是应用程序运行所必需的除此之外并没有其它的资源可以在伪终端中利用 `ps` `top` 来查看进程信息
```bash
# 查看所有容器(包括已停止的)
$ docker ps -a
CONTAINER ID IMAGE STATUS NAMES
af8bae53bdd3 ubuntu Exited (0) 2 minutes ago myubuntu
# 重新启动
$ docker start myubuntu
# 启动并附加终端
$ docker start -ai myubuntu
```
## 容器内进程的特点
容器内只运行指定的应用程序及其必需资源
```bash
root@ba267838cc1b:/# ps
@@ -58,4 +169,61 @@ root@ba267838cc1b:/# ps
11 ? 00:00:00 ps
```
可见容器中仅运行了指定的 bash 应用这种特点使得 Docker 对资源的利用率极高是货真价实的轻量级虚拟化
可见容器中仅运行了 `bash` 进程这种特点使得 Docker 对资源的利用率极高
> 💡 笔者提示容器内的 PID 1 进程很重要它是容器的主进程该进程退出则容器停止详见[后台运行](daemon.md)章节
## 常见问题
### Q: 容器启动后立即退出
**原因**主进程执行完毕或无法保持运行
```bash
# 这个容器会立即退出echo 执行完就结束了)
$ docker run ubuntu echo "hello"
# 解决:使用能持续运行的命令
$ docker run -d nginx # nginx 是持续运行的服务
```
详细解释见[后台运行](daemon.md)
### Q: 无法连接容器内的服务
**原因**未正确映射端口
```bash
# 错误:没有 -p 参数,外部无法访问
$ docker run -d nginx
# 正确:映射端口
$ docker run -d -p 80:80 nginx
```
### Q: 容器内修改的文件丢失
**原因**未使用数据卷数据保存在容器存储层
```bash
# 使用数据卷持久化
$ docker run -v mydata:/app/data myapp
```
详见[数据管理](../data_management/README.md)
## 本章小结
| 操作 | 命令 | 说明 |
|------|------|------|
| 新建并运行 | `docker run` | 最常用的启动方式 |
| 交互式启动 | `docker run -it` | 用于调试或临时操作 |
| 后台运行 | `docker run -d` | 用于服务类应用 |
| 启动已停止的容器 | `docker start` | 重用已有容器 |
## 延伸阅读
- [后台运行](daemon.md)理解 `-d` 参数和容器生命周期
- [进入容器](attach_exec.md)操作运行中的容器
- [网络配置](../network/README.md)理解端口映射的原理
- [数据管理](../data_management/README.md)数据持久化方案

View File

@@ -1,19 +1,256 @@
# 终止容器
可以使用 `docker container stop` 终止一个运行中的容器
## 终止方式概述
此外 Docker 容器中指定的应用终结时容器也自动终止
终止容器有三种方式
例如对于上一章节中只启动了一个终端的容器用户通过 `exit` 命令 `Ctrl+d` 来退出终端时所创建的容器立刻终止
| 方式 | 命令 | 说明 |
|------|------|------|
| **优雅停止** | `docker stop` | 先发 SIGTERM超时后发 SIGKILL |
| **强制停止** | `docker kill` | 直接发 SIGKILL |
| **自动终止** | - | 容器主进程退出时自动停止 |
终止状态的容器可以用 `docker container ls -a` 命令看到例如
---
## docker stop推荐
### 基本用法
```bash
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba267838cc1b ubuntu:24.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton
$ docker stop 容器名或ID
```
处于终止状态的容器可以通过 `docker container start` 命令来重新启动
### 工作原理
此外`docker container restart` 命令会将一个运行态的容器终止然后再重新启动它
```
docker stop mycontainer
┌─────────────────────────────────────────────────────────────────┐
│ 1. 发送 SIGTERM 信号给容器主进程PID 1
│ ↓ │
│ 2. 等待容器优雅退出(默认 10 秒) │
│ ↓ │
│ 3. 如果超时仍未退出,发送 SIGKILL 强制终止 │
└─────────────────────────────────────────────────────────────────┘
```
### 自定义超时时间
```bash
# 等待 30 秒后强制终止
$ docker stop -t 30 mycontainer
# 立即发送 SIGKILL相当于 docker kill
$ docker stop -t 0 mycontainer
```
### 停止多个容器
```bash
# 停止多个指定容器
$ docker stop container1 container2 container3
# 停止所有运行中的容器
$ docker stop $(docker ps -q)
```
---
## docker kill
### 基本用法
```bash
$ docker kill 容器名或ID
```
### stop 的区别
| 命令 | 信号 | 使用场景 |
|------|------|---------|
| `docker stop` | SIGTERM SIGKILL | 正常停止让应用优雅退出 |
| `docker kill` | SIGKILL | 应用无响应强制终止 |
### 发送自定义信号
```bash
# 发送 SIGHUP让进程重新加载配置
$ docker kill -s HUP mycontainer
# 发送 SIGTERM
$ docker kill -s TERM mycontainer
```
---
## 容器自动终止
容器的生命周期与主进程绑定主进程退出时容器自动停止
```bash
# 主进程是交互式 bash
$ docker run -it ubuntu bash
root@abc123:/# exit # 退出 bash → 容器停止
# 主进程执行完毕
$ docker run ubuntu echo "Hello" # echo 执行完 → 容器停止
```
---
## 查看已停止的容器
```bash
$ docker ps -a
CONTAINER ID IMAGE COMMAND STATUS NAMES
ba267838cc1b ubuntu "/bin/bash" Exited (0) 2 minutes ago myubuntu
c5d3a5e8f7b2 nginx "nginx" Up 5 minutes mynginx
```
**STATUS 字段说明**
| 状态 | 说明 |
|------|------|
| `Up X minutes` | 运行中 |
| `Exited (0)` | 正常退出退出码 0 |
| `Exited (1)` | 异常退出非零退出码 |
| `Exited (137)` | SIGKILL 终止128 + 9 |
| `Exited (143)` | SIGTERM 终止128 + 15 |
---
## 重新启动容器
### 启动已停止的容器
```bash
$ docker start 容器名或ID
# 启动并附加终端
$ docker start -ai 容器名
```
### 重启运行中的容器
```bash
# 先停止再启动
$ docker restart 容器名
# 自定义停止超时
$ docker restart -t 30 容器名
```
---
## 生命周期状态图
```
docker create
┌──────────┐
┌────────│ Created │────────┐
│ └──────────┘ │
│ │ │
│ │ docker start│
│ ▼ │
│ ┌──────────┐ │
│ ┌────│ Running │────┐ │
│ │ └──────────┘ │ │
│ │ │ │ │
│ │ docker │ docker │ │
│ │ pause │ stop │ │
│ ▼ │ │ │
│ ┌──────┐ │ │ │
│ │Paused│ │ │ │
│ └──────┘ │ │ │
│ │ │ │ │
│ │ docker │ │ │
│ │ unpause │ │ │
│ ▼ ▼ │ │
│ └──────►┌──────────┐◄┘ │
│ │ Stopped │ │
│ └──────────┘ │
│ │ │
│ │ docker rm │
│ ▼ │
│ ┌──────────┐ │
└──────────►│ Deleted │◄────┘
└──────────┘
```
---
## 批量操作
### 停止所有容器
```bash
$ docker stop $(docker ps -q)
```
### 删除所有已停止的容器
```bash
$ docker container prune
```
### 停止并删除所有容器
```bash
$ docker stop $(docker ps -q) && docker container prune -f
```
---
## 常见问题
### Q: 容器停止很慢
原因应用没有正确处理 SIGTERM 信号需要等待超时后强制终止
解决方案
1. 在应用中正确处理 SIGTERM
2. 使用 `docker stop -t 0` 立即终止
3. 检查 Dockerfile 中的 `STOPSIGNAL` 配置
### Q: 如何让容器优雅退出
确保容器主进程正确处理信号
```dockerfile
# Dockerfile 示例
FROM node:18
...
# 使用 exec 形式确保信号能传递给 node 进程
CMD ["node", "server.js"]
```
### Q: 容器无法停止
```bash
# 强制终止
$ docker kill 容器名
# 如果仍无法停止,检查系统资源
$ docker inspect 容器名
```
---
## 本章小结
| 操作 | 命令 | 说明 |
|------|------|------|
| 优雅停止 | `docker stop` | SIGTERM超时后 SIGKILL |
| 强制停止 | `docker kill` | 直接 SIGKILL |
| 重新启动 | `docker start` | 启动已停止的容器 |
| 重启 | `docker restart` | 停止后立即启动 |
| 停止全部 | `docker stop $(docker ps -q)` | 停止所有运行中容器 |
## 延伸阅读
- [启动容器](run.md)容器启动详解
- [删除容器](rm.md)清理容器
- [容器日志](logs.md)排查停止原因