Files
docker_practice/07_dockerfile/7.5_entrypoint.md
Baohua Yang 175aaae48a style(docs): standardize heading formats and numbering
- Enforce Level 1-3 structural numbering based on SUMMARY.md hierarchy
- Remove structural numbering from Level 4+ headings
- Eliminate single child headings by converting to bold text
- Auto-inject summary text for headings with multiple children missing intro text
- Exclude Appendix chapters from structural numbering
- Avoid modifying code block contents
- Add script to detect non-standard English usage in headers
2026-02-21 22:40:33 -08:00

352 lines
7.3 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 7.5 ENTRYPOINT 入口点
本节涵盖了相关内容与详细描述主要探讨以下几个方面
### 7.5.1 什么是 ENTRYPOINT
`ENTRYPOINT` 指定容器启动时运行的入口程序 CMD 不同ENTRYPOINT 定义的命令不会被 `docker run` 的参数覆盖而是 **接收这些参数**
> **核心作用**让镜像像一个可执行程序一样使用`docker run` 的参数作为这个程序的参数
---
### 7.5.2 语法格式
相关信息如下表
| 格式 | 语法 | 推荐程度 |
|------|------|---------|
| **exec 格式**| `ENTRYPOINT ["可执行文件", "参数1"]` | **推荐** |
| **shell 格式** | `ENTRYPOINT 命令 参数` | 不推荐 |
```docker
## exec 格式(推荐)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
## shell 格式(不推荐)
ENTRYPOINT nginx -g "daemon off;"
```
---
### 7.5.3 ENTRYPOINT vs CMD
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 核心区别
相关信息如下表
| 特性 | ENTRYPOINT | CMD |
|------|------------|-----|
| **定位** | 固定的入口程序 | 默认参数 |
| **docker run 参数** | 追加为参数 | 完全覆盖 |
| **覆盖方式** | `--entrypoint` | 直接指定命令 |
| **适用场景** | 把镜像当命令用 | 提供默认行为 |
#### 行为对比
如下代码块所示展示了相关示例
```docker
## 只用 CMD
CMD ["curl", "-s", "http://example.com"]
```
```bash
$ docker run myimage # curl -s http://example.com
$ docker run myimage -v # 执行 -v错误
$ docker run myimage curl -v ... # curl -v ...(完全替换)
```
```docker
## 只用 ENTRYPOINT
ENTRYPOINT ["curl", "-s"]
```
```bash
$ docker run myimage # curl -s缺参数
$ docker run myimage http://example.com # curl -s http://example.com ✓
```
```docker
## ENTRYPOINT + CMD 组合(推荐)
ENTRYPOINT ["curl", "-s"]
CMD ["http://example.com"]
```
```bash
$ docker run myimage # curl -s http://example.com默认
$ docker run myimage http://other.com # curl -s http://other.com ✓
$ docker run myimage -v http://other.com # curl -s -v http://other.com ✓
```
---
### 7.5.4 场景一让镜像像命令一样使用
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 需求 (启动前准备)
创建一个查询公网 IP 命令 镜像
#### 使用 CMD 的问题
如下代码块所示展示了相关示例
```docker
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
CMD ["curl", "-s", "http://myip.ipip.net"]
```
```bash
$ docker run myip # ✓ 正常工作
当前 IP61.148.226.66
$ docker run myip -i # ✗ 错误!
exec: "-i": executable file not found
## -i 替换了整个 CMD被当作可执行文件
...
```
#### 使用 ENTRYPOINT 解决
如下代码块所示展示了相关示例
```docker
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
```
```bash
$ docker run myip # ✓ 正常工作
当前 IP61.148.226.66
$ docker run myip -i # ✓ 添加 -i 参数
HTTP/1.1 200 OK
...
当前 IP61.148.226.66
```
#### 交互图示
如下代码块所示展示了相关示例
```bash
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
docker run myip -i
curl -s http://myip.ipip.net -i
└─────────────────────────────┘
ENTRYPOINT + docker run 参数
```
---
### 7.5.5 场景二启动前的准备工作
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 需求
在启动主服务前执行初始化脚本 (如数据库迁移权限设置)
#### 实现方式
如下代码块所示展示了相关示例
```docker
FROM redis:7-alpine
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["redis-server"]
```
**docker-entrypoint.sh**
```bash
#!/bin/sh
set -e
## 准备工作
echo "Initializing..."
## 如果第一个参数是 redis-server以 redis 用户运行
if [ "$1" = 'redis-server' ]; then
chown -R redis:redis /data
exec gosu redis "$@"
fi
## 其他命令直接执行
exec "$@"
```
#### 工作流程
如下代码块所示展示了相关示例
```bash
docker run redis docker run redis bash
│ │
▼ ▼
docker-entrypoint.sh redis-server docker-entrypoint.sh bash
│ │
├─ 初始化 ├─ 初始化
├─ chown -R redis:redis /data │
└─ exec gosu redis redis-server └─ exec bash
(以 redis 用户运行) (以 root 用户运行)
```
#### 关键点
1. **exec $@**用传入的参数替换当前进程确保信号正确传递
2. **条件判断**根据 CMD 不同执行不同逻辑
3. **用户切换**使用 `gosu` 切换用户 ( `su` 更适合容器)
---
### 7.5.6 场景三带参数的应用
如下代码块所示展示了相关示例
```docker
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
ENTRYPOINT ["python", "app.py"]
CMD ["--host", "0.0.0.0", "--port", "8080"]
```
```bash
## 使用默认参数
$ docker run myapp
## 执行: python app.py --host 0.0.0.0 --port 8080
## 覆盖参数
$ docker run myapp --host 0.0.0.0 --port 9000
## 执行: python app.py --host 0.0.0.0 --port 9000
## 完全不同的参数
$ docker run myapp --help
## 执行: python app.py --help
...
```
---
### 7.5.7 覆盖 ENTRYPOINT
使用 `--entrypoint` 参数覆盖
```bash
## 正常运行
$ docker run myimage
## 覆盖 ENTRYPOINT 进入 shell 调试
$ docker run --entrypoint /bin/sh myimage
## 覆盖 ENTRYPOINT 并传入参数
$ docker run --entrypoint /bin/cat myimage /etc/os-release
```
---
### 7.5.8 ENTRYPOINT CMD 组合表
相关信息如下表
| ENTRYPOINT | CMD | 最终执行命令 |
|------------|-----|-------------|
| | | (容器无法启动)|
| | `["cmd", "p1"]` | `cmd p1` |
| `["ep", "p1"]` | | `ep p1` |
| `["ep", "p1"]` | `["cmd", "p2"]` | `ep p1 cmd p2` |
| `ep p1` (shell)| `["cmd", "p2"]` | `/bin/sh -c "ep p1"` (CMD 被忽略)|
> **注意**shell 格式的 ENTRYPOINT 会忽略 CMD
---
### 7.5.9 最佳实践
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 1使用 exec 格式
如下代码块所示展示了相关示例
```docker
## ✅ 推荐
ENTRYPOINT ["python", "app.py"]
## ❌ 避免 shell 格式
ENTRYPOINT python app.py
```
#### 2提供有意义的默认参数
如下代码块所示展示了相关示例
```docker
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
```
#### 3入口脚本使用 exec
运行以下命令
```bash
#!/bin/sh
## 准备工作...
## 使用 exec 替换当前进程
exec "$@"
```
#### 4处理信号
确保 ENTRYPOINT 脚本能正确传递信号
```bash
#!/bin/bash
trap 'kill -TERM $PID' TERM INT
## 启动应用
app "$@" &
PID=$!
## 等待应用退出
wait $PID
```
---