mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-10 11:54:37 +00:00
297 lines
7.4 KiB
Go
297 lines
7.4 KiB
Go
## 进入容器
|
||
|
||
### 为什么需要进入容器
|
||
|
||
使用 `-d` 参数启动容器后,容器在后台运行。以下场景需要进入容器内部操作:
|
||
|
||
| 场景 | 示例 |
|
||
|------|------|
|
||
| **调试问题** | 查看日志、检查配置、排查错误 |
|
||
| **临时操作** | 执行数据库迁移、清理缓存 |
|
||
| **检查状态** | 查看进程、网络连接、文件系统 |
|
||
| **开发测试** | 交互式测试命令、验证环境 |
|
||
|
||
### 两种进入方式
|
||
|
||
Docker 提供两种进入容器的命令:
|
||
|
||
| 命令 | 推荐程度 | 特点 |
|
||
|------|---------|------|
|
||
| `docker exec` | ✅ **推荐** | 启动新进程,退出不影响容器 |
|
||
| `docker attach` | ⚠️ 谨慎使用 | 附加到主进程,退出可能停止容器 |
|
||
|
||
---
|
||
|
||
### docker exec(推荐)
|
||
|
||
#### 基本用法
|
||
|
||
运行以下命令:
|
||
|
||
```bash
|
||
## 进入容器并启动交互式 shell
|
||
|
||
$ docker exec -it 容器名 /bin/bash
|
||
|
||
## 或使用 sh(适用于 Alpine 等精简镜像)
|
||
|
||
$ docker exec -it 容器名 /bin/sh
|
||
```
|
||
|
||
#### 参数说明
|
||
|
||
| 参数 | 作用 |
|
||
|------|------|
|
||
| `-i` | 保持标准输入打开(interactive) |
|
||
| `-t` | 分配伪终端(TTY) |
|
||
| `-it` | 两者组合,获得完整交互体验 |
|
||
| `-u` | 指定用户(如 `-u root`) |
|
||
| `-w` | 指定工作目录 |
|
||
| `-e` | 设置环境变量 |
|
||
|
||
#### 示例
|
||
|
||
运行以下命令:
|
||
|
||
```bash
|
||
## 启动一个后台容器
|
||
|
||
$ docker run -dit --name myubuntu ubuntu
|
||
69d137adef7a...
|
||
|
||
## 进入容器(交互式 shell)
|
||
|
||
$ docker exec -it myubuntu bash
|
||
root@69d137adef7a:/# ls
|
||
bin boot dev etc home lib ...
|
||
root@69d137adef7a:/# exit
|
||
|
||
## 容器仍在运行!
|
||
|
||
$ 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
|
||
...
|
||
|
||
## 用 -it:有完整的终端体验
|
||
|
||
$ docker exec -it myubuntu bash
|
||
root@69d137adef7a:/# # 有提示符
|
||
```
|
||
|
||
> 💡 通常使用 `-it` 组合。只有在脚本中需要通过管道传入命令时才只用 `-i`。
|
||
|
||
---
|
||
|
||
### 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 容器名`(慎用) |
|
||
|
||
### 延伸阅读
|
||
|
||
- [后台运行](5.2_daemon.md):理解容器主进程
|
||
- [查看容器](ls.md):列出和过滤容器
|
||
- [容器日志](logs.md):查看容器输出
|