2016-11-26 02:02:43 +08:00
# # # ENTRYPOINT 入 口 点
` ENTRYPOINT ` 的 格 式 和 ` RUN ` 指 令 格 式 一 样 , 分 为 ` exec ` 格 式 和 ` shell ` 格 式 。
` ENTRYPOINT ` 的 目 的 和 ` CMD ` 一 样 , 都 是 在 指 定 容 器 启 动 程 序 及 参 数 。 ` ENTRYPOINT ` 在 运 行 时 也 可 以 替 代 , 不 过 比 ` CMD ` 要 略 显 繁 琐 , 需 要 通 过 ` docker run ` 的 参 数 ` --entrypoint ` 来 指 定 。
当 指 定 了 ` ENTRYPOINT ` 后 , ` CMD ` 的 含 义 就 发 生 了 改 变 , 不 再 是 直 接 的 运 行 其 命 令 , 而 是 将 ` CMD ` 的 内 容 作 为 参 数 传 给 ` ENTRYPOINT ` 指 令 , 换 句 话 说 实 际 执 行 时 , 将 变 为 :
` ` ` bash
< ENTRYPOINT > "<CMD>"
` ` `
那 么 有 了 ` CMD ` 后 , 为 什 么 还 要 有 ` ENTRYPOINT ` 呢 ? 这 种 ` <ENTRYPOINT> "<CMD>" ` 有 什 么 好 处 么 ? 让 我 们 来 看 几 个 场 景 。
# # # # 场 景 一 : 让 镜 像 变 成 像 命 令 一 样 使 用
假 设 我 们 需 要 一 个 得 知 自 己 当 前 公 网 IP 的 镜 像 , 那 么 可 以 先 用 ` CMD ` 来 实 现 :
2019-10-29 14:31:45 +08:00
` ` ` docker
2018-12-08 21:47:05 +08:00
FROM ubuntu : 18.04
2016-11-26 02:02:43 +08:00
RUN apt - get update \
&& apt - get install - y curl \
&& rm - rf / var / lib / apt / lists / *
2018-12-10 18:20:10 +08:00
CMD [ "curl" , "-s" , "https://ip.cn" ]
2016-11-26 02:02:43 +08:00
` ` `
假 如 我 们 使 用 ` docker build -t myip . ` 来 构 建 镜 像 的 话 , 如 果 我 们 需 要 查 询 当 前 公 网 IP , 只 需 要 执 行 :
` ` ` bash
$ docker run myip
当 前 IP : 61.148 .226 .66 来 自 : 北 京 市 联 通
` ` `
嗯 , 这 么 看 起 来 好 像 可 以 直 接 把 镜 像 当 做 命 令 使 用 了 , 不 过 命 令 总 有 参 数 , 如 果 我 们 希 望 加 参 数 呢 ? 比 如 从 上 面 的 ` CMD ` 中 可 以 看 到 实 质 的 命 令 是 ` curl ` , 那 么 如 果 我 们 希 望 显 示 HTTP 头 信 息 , 就 需 要 加 上 ` -i ` 参 数 。 那 么 我 们 可 以 直 接 加 ` -i ` 参 数 给 ` docker run myip ` 么 ?
` ` ` bash
$ docker run myip - i
docker : Error response from daemon : invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"exec: \\\"-i\\\": executable file not found in $PATH\"\n" .
` ` `
2018-12-10 18:20:10 +08:00
我 们 可 以 看 到 可 执 行 文 件 找 不 到 的 报 错 , ` executable file not found ` 。 之 前 我 们 说 过 , 跟 在 镜 像 名 后 面 的 是 ` command ` , 运 行 时 会 替 换 ` CMD ` 的 默 认 值 。 因 此 这 里 的 ` -i ` 替 换 了 原 来 的 ` CMD ` , 而 不 是 添 加 在 原 来 的 ` curl -s https://ip.cn ` 后 面 。 而 ` -i ` 根 本 不 是 命 令 , 所 以 自 然 找 不 到 。
2016-11-26 02:02:43 +08:00
那 么 如 果 我 们 希 望 加 入 ` -i ` 这 参 数 , 我 们 就 必 须 重 新 完 整 的 输 入 这 个 命 令 :
` ` ` bash
2018-12-10 18:20:10 +08:00
$ docker run myip curl - s https : //ip.cn -i
2016-11-26 02:02:43 +08:00
` ` `
这 显 然 不 是 很 好 的 解 决 方 案 , 而 使 用 ` ENTRYPOINT ` 就 可 以 解 决 这 个 问 题 。 现 在 我 们 重 新 用 ` ENTRYPOINT ` 来 实 现 这 个 镜 像 :
2019-10-29 14:31:45 +08:00
` ` ` docker
2018-12-08 21:47:05 +08:00
FROM ubuntu : 18.04
2016-11-26 02:02:43 +08:00
RUN apt - get update \
&& apt - get install - y curl \
&& rm - rf / var / lib / apt / lists / *
2018-12-10 18:20:10 +08:00
ENTRYPOINT [ "curl" , "-s" , "https://ip.cn" ]
2016-11-26 02:02:43 +08:00
` ` `
这 次 我 们 再 来 尝 试 直 接 使 用 ` docker run myip -i ` :
` ` ` bash
$ docker run myip
当 前 IP : 61.148 .226 .66 来 自 : 北 京 市 联 通
$ docker run myip - i
HTTP / 1.1 200 OK
Server : nginx / 1.8 .0
Date : Tue , 22 Nov 2016 05 : 12 : 40 GMT
Content - Type : text / html ; charset = UTF - 8
Vary : Accept - Encoding
X - Powered - By : PHP / 5.6 .24 - 1 ~ dotdeb + 7.1
X - Cache : MISS from cache - 2
X - Cache - Lookup : MISS from cache - 2 : 80
X - Cache : MISS from proxy - 2_6
Transfer - Encoding : chunked
Via : 1.1 cache - 2 : 80 , 1.1 proxy - 2_6 : 8006
Connection : keep - alive
当 前 IP : 61.148 .226 .66 来 自 : 北 京 市 联 通
` ` `
可 以 看 到 , 这 次 成 功 了 。 这 是 因 为 当 存 在 ` ENTRYPOINT ` 后 , ` CMD ` 的 内 容 将 会 作 为 参 数 传 给 ` ENTRYPOINT ` , 而 这 里 ` -i ` 就 是 新 的 ` CMD ` , 因 此 会 作 为 参 数 传 给 ` curl ` , 从 而 达 到 了 我 们 预 期 的 效 果 。
# # # # 场 景 二 : 应 用 运 行 前 的 准 备 工 作
启 动 容 器 就 是 启 动 主 进 程 , 但 有 些 时 候 , 启 动 主 进 程 前 , 需 要 一 些 准 备 工 作 。
比 如 ` mysql ` 类 的 数 据 库 , 可 能 需 要 一 些 数 据 库 配 置 、 初 始 化 的 工 作 , 这 些 工 作 要 在 最 终 的 mysql 服 务 器 运 行 之 前 解 决 。
此 外 , 可 能 希 望 避 免 使 用 ` root ` 用 户 去 启 动 服 务 , 从 而 提 高 安 全 性 , 而 在 启 动 服 务 前 还 需 要 以 ` root ` 身 份 执 行 一 些 必 要 的 准 备 工 作 , 最 后 切 换 到 服 务 用 户 身 份 启 动 服 务 。 或 者 除 了 服 务 外 , 其 它 命 令 依 旧 可 以 使 用 ` root ` 身 份 执 行 , 方 便 调 试 等 。
这 些 准 备 工 作 是 和 容 器 ` CMD ` 无 关 的 , 无 论 ` CMD ` 为 什 么 , 都 需 要 事 先 进 行 一 个 预 处 理 的 工 作 。 这 种 情 况 下 , 可 以 写 一 个 脚 本 , 然 后 放 入 ` ENTRYPOINT ` 中 去 执 行 , 而 这 个 脚 本 会 将 接 到 的 参 数 ( 也 就 是 ` <CMD> ` ) 作 为 命 令 , 在 脚 本 最 后 执 行 。 比 如 官 方 镜 像 ` redis ` 中 就 是 这 么 做 的 :
2019-10-29 14:31:45 +08:00
` ` ` docker
2016-11-26 02:02:43 +08:00
FROM alpine : 3.4
...
RUN addgroup - S redis && adduser - S - G redis redis
...
ENTRYPOINT [ "docker-entrypoint.sh" ]
EXPOSE 6379
CMD [ "redis-server" ]
` ` `
可 以 看 到 其 中 为 了 redis 服 务 创 建 了 redis 用 户 , 并 在 最 后 指 定 了 ` ENTRYPOINT ` 为 ` docker-entrypoint.sh ` 脚 本 。
` ` ` bash
# ! / bin / sh
...
# allow the container to be started with ` --user `
if [ "$1" = ' redis - server ' - a "$(id -u)" = '0' ] ; then
chown - R redis .
exec su - exec redis "$0" "$@"
fi
exec "$@"
` ` `
该 脚 本 的 内 容 就 是 根 据 ` CMD ` 的 内 容 来 判 断 , 如 果 是 ` redis-server ` 的 话 , 则 切 换 到 ` redis ` 用 户 身 份 启 动 服 务 器 , 否 则 依 旧 使 用 ` root ` 身 份 执 行 。 比 如 :
` ` ` bash
$ docker run - it redis id
uid = 0 ( root ) gid = 0 ( root ) groups = 0 ( root )
` ` `