前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >node 镜像 ENTRYPOINT 脚本解析

node 镜像 ENTRYPOINT 脚本解析

作者头像
山月
发布2022-11-02 16:41:10
9630
发布2022-11-02 16:41:10
举报
文章被收录于专栏:服务器运维笔记

本篇文章来自 Linux 训练营中的作业,欢迎咨询训练营。

node:18 为例,node 官方镜像的 ENTRYPOINT 入口脚本为以下内容:

代码语言:javascript
复制
#!/bin/sh
set -e

# Run command with node if the first argument contains a "-" or is not a system command. The last
# part inside the "{}" is a workaround for the following bug in ash/dash:
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then
  set -- node "$@"
fi

exec "$@"

源码详见 docker-entrypoint.sh1

1. shebang

#! 组成了 shebang,指定脚本执行的解释器的绝对路径。

代码语言:javascript
复制
# 使用 sh 执行脚本
#!/bin/sh

# 使用 python 执行脚本
#!/usr/bin/python

2. set -e

set -e,当命令发生异常时立即退出。

Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command (see SHELL GRAMMAR above), exits with a non-zero status.

新建文件 hello.sh,脚本示例如下,使用 bash hello.sh 执行。

代码语言:javascript
复制
# 当有该行时,直接报错退出
# 当无该行时,最终会输出 done
set -e

cat notexistfile

echo done

3. if

接下来是 if 语句,过长,需要拆开来看。

代码语言:javascript
复制
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then
  set -- node "$@"
fi

在这之前,首先需要了解一下语法,可参考 Linux 技能实战2

  • [ ]:布尔判断
  • $1$2$@$1 代表命令行第一个参数,$@ 代表命令行所有参数。可参考 linux 中的函数3

4. ${1#-}

这种属于不较常见的 Parameter Expansion 了,常见的也就 ${NODE_ENV:=development} 这种,见文档 Shell Parameter Expansion4。

${var#word} 具体的含义呢?

可以理解为:如果变量 var 以 word 开头,则 {var#word} 的值为 var 删掉 word,否则为 var。简单点来说,就是 「Remove prefix」。

有点绕口,看看示例:

代码语言:javascript
复制
$ var=helloworld

$ echo ${var#hello}
world

$ echo ${var#world}
helloworld

$ echo ${var#ok}
helloworld

所以 "

其实用以下两种写法更为直观点:

代码语言:javascript
复制
$ var=--version

$ [[ ${var:0:1} == "-" ]] && echo ok
ok

$ [[ $var =~ ^- ]] && echo ok
ok

5. command -v

command -v <command> 输出某个命令的真实绝对路径,which 也可以干这件事情。

二者最重要的一个不同点是,当某个命令不存在时,command -v 不会输出任何字符,用此常来判断某个命令是否存在。

可参考 $PATH5

代码语言:javascript
复制
$ command -v node
/usr/local/bin/node

$ which hello
/usr/bin/which: no hello in (/home/train/.autojump/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/train/bin)

# 无任何输出
$ command -v hello command -v 

[[ -z STRING]],判断 STRING 是否为空字符串。

因此下一条,则是判断 1 该命令是否存在,或者说「判断 1 是否是一个全局可执行的命令」。

6. {[ -f "${1}" ] && ! [ -x "${1}"];}

而这一条,前边是判断 1 是否是一个文件,而后边是判断 1 是否是一个可执行的文件。因此该条件就是说判断 「

可参考 linux 中的括号6

其目的是在 Dockerfile 中可直接写 CMD ["index.js"],如以下示例

代码语言:javascript
复制
FROM node:14-alpine

ADD server.js /

CMD ["server.js"]

哦对,注意两点

  1. 该命令使用 {} 包裹
  2. 该命令最后有一个分号

7. set --

set 用以重置命令行 1 2

至于它有什么作用,看了以下示例就明白了了。

代码语言:javascript
复制
$ set -- a b c d

$ echo $1 $2 $3 $4
a b c d

$ echo "$@"
a b c d

$ set -- node "$@"

$ echo "$@"
node a b c d

所以 set -- node "$@" 的意思也很明白了:「最前边添加一个 node 参数」

8. exec

exec,执行某条命令,但会退出当前 shell。

If command is specified, it replaces the shell.

代码语言:javascript
复制
$ exec echo hello
hello

9. 总结

docker-entrypoint.sh 代码添加注释

代码语言:javascript
复制
#!/bin/sh
set -e

# 如果 $1 以 - 开头
if [ "${1#-}" != "${1}" ] ||
  # 或者不是一个可执行命令
  [ -z "$(command -v "${1}")" ] ||
  # 或者是当前目录的一个文件,但不可执行
  { [ -f "${1}" ] && ! [ -x "${1}" ]; };
then
  # 则在前边附一个 node 
  set -- node "$@"
fi

# 执行执行代码
exec "$@"
  1. 如果 - 开头,则作为 node 的参数执行
  2. 如果判断 $1 是文件且不可执行,则使用 node 运行该文件
  3. 如果判断 $1 是系统命令,则直接执行该命令

参考资料

[1]

docker-entrypoint.sh:https://github.com/nodejs/docker-node/blob/main/18/bullseye/docker-entrypoint.sh

[2]

Linux 技能实战:https://q.shanyue.tech/command/

[3]

linux 中的函数:https://umiinn9jie.feishu.cn/wiki/wikcnA6zD21wdJtihB1y4fSpqgb

[4]

Shell Parameter Expansion:https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion

[5]

$PATH:https://q.shanyue.tech/command/path.html

[6]

linux 中的括号:https://q.shanyue.tech/command/quote.html

[7]

how to nest conditional script operators -a -o in an if statement in bash:https://unix.stackexchange.com/questions/670519/how-to-nest-conditional-script-operators-a-o-in-an-if-statement-in-bash

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. shebang
  • 2. set -e
  • 3. if
  • 4. ${1#-}
  • 5. command -v
  • 6. {[ -f "${1}" ] && ! [ -x "${1}"];}
  • 7. set --
  • 8. exec
  • 9. 总结
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档