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)查看容器输出