ENTRYPOINT

ENTRYPOINT有两种形式:

exec形式(我们优先选择的形式)

ENTRYPOINT ["executable", "param1", "param2"]

shell形式

ENTRYPOINT command param1 param2

ENTRYPOINT允许我们配置容器并作为可执行文件运行。

例如,以下代码以其默认内容启动nginx,监听端口80

$ docker run -i -t --rm -p 80:80 nginx

docker run的命令行参数将添加到exec形式的ENTRYPOINT的所有元素之后,并覆盖使用CMD指定的所有元素。这允许我们将参数传递给入口(entry point),即docker run -d-d参数传递给入口(entry point)。我们可以使用docker run --entrypoint覆盖ENTRYPOINT指令

Demon1:

main.go:

package main

import (
    "flag"
    "fmt"
)

type Usage struct {
    Name    string
    Age     string
    Address string
    Sex     string
}

const (
    name = `
The name flag is used to set a new name.
The default value is TonyYang.
`
    age = `
The age flag is used to set a new age.
The default value is 31.
`
    address = `
The address flag is used to set a new address.
The default value is ChangZhou.
`
    sex = `
The sex flag is used to set a new sex.
The default value is TonyYang.
`
)

var usage = Usage{
    Name:    name,
    Age:     age,
    Address: address,
    Sex:     sex,
}

func main() {

    var (
        fName    = flag.String("name", "TonyYang", usage.Name)
        fAge     = flag.String("age", "31", usage.Age)
        fAddress = flag.String("address", "ChangZhou", usage.Address)
        fSex     = flag.String("sex", "male", usage.Sex)
    )

    flag.Parse()

    infos := map[string]*string{
        "name":    fName,
        "age":     fAge,
        "address": fAddress,
        "sex":     fSex,
    }

    for k, v := range infos {
        fmt.Printf("The %s is %s\n", k, *v)
    }

}

Dockerfile:

上面定义了一个测试ENTRYPOINTDockerfile,通过go语言编写。

默认不为run指定运行的参数,输出结果如下所示:

输出的结果符合我们CMD中设置的参数默认值。

当为run指定参数以后,输出结果发生了改变,输出的值不再按照CMD中设定的那样。在这里name变成了CamelGem,而其余的值是我在程序中设置的默认值。由此可以看出,一旦为run指定了参数,CMD中的值就会被全部覆盖掉。

Shell形式可防止使用任何CMDrun命令行指定的参数,但具有以下缺点:ENTRYPOINT将作为/bin/sh -c的子命令启动,该子命令不传递信号。这意味着可执行文件进程将不是容器的PID 1,并且不会接收Unix信号,因此可执行文件将不会从docker stop 接收到SIGTERM

只有Dockerfile中的最后一条ENTRYPOINT指令才会生效。

我们可以使用ENTRYPOINTexec形式来设置相当稳定的默认命令和参数,然后使用CMD来设置更有可能被更改的其他的默认值。

当运行容器时,可以看到top是唯一的进程:

要进一步检查结果,可以使用docker exec:

我们可以使用docker stop test优雅地请求top关闭。

以下的示例,我们使用ENTRYPOINT来使用Apache服务器运行在前台:

如果我们需要为单个可执行文件编写启动脚本,则可以使用execgosu命令确保最终可执行程序能够接收到Unix信号:

最后,如果我们需要在关闭进程时进行一些额外的清理(或与其他容器通信),或正在协调多个可执行的容器,我们需要确保ENTRYPOINT脚本接收到Unix信号,传递它们,然后执行更多工作:

如果我们通过docker run -it --rm -p 80:80 --name test apache,我们可以通过docker execdocker top来查看容器的进程,然后让脚本停止Apache进程。

NOTE:

我们可以通过使用--entrypoint来覆盖ENTRYPOINT的设置,但是这只能设置二进制的可执行程序(不会使用sh -c)。

exec形式会被解析为JSON数组,这意味着我们必须使用双引号来包围单词,而不是通过单引号

shell形式不同,exec形式不会调用一个命令行shell。这意味着不会发生正常的shell处理。例如,ENTRYPOINT ["echo", "$HOME"]将不会进行变量替换。如果你希望发生shell处理,那么既可以使用shell形式也可以直接执行一个shell,例如:ENTRYPOINT ["sh", "-c", "echo $HOME"]。当使用exec形式并且直接执行一个shell,这种情况下,对环境变量进行扩展的是shell而不是docker

Last updated

Was this helpful?