美文网首页
Dockerfile 指令 功能 三 (ENTRYPOINT)

Dockerfile 指令 功能 三 (ENTRYPOINT)

作者: 懒猫睡醒了 | 来源:发表于2021-08-16 10:41 被阅读0次

    ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式 和 shell 格式

    ENTRYPOINT 的目的和 CMD 一样,都是在指定的容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

    当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:

    <ENTRYPOINT> "<CMD>"

    场景一:让镜像变成像命令一样使用

    传参的用途

    使用一个公网IP的镜像来得知自己当前的公网IP,那么可以先用 CMD来实现:

    FROM ubuntu:18.04
    RUN apt-get update
    && apt-get install -y curl
    && rm -rf /var/lib/apt/lists/*
    CMD ["curl","-s","http://myip.ipip.net"]

    使用docker build 构建镜像

    [root@ip-10-1-0-142 ipip]# docker build -t myip:v1 .
    Sending build context to Docker daemon 2.048kB
    Step 1/3 : FROM ubuntu:18.04
    18.04: Pulling from library/ubuntu
    feac53061382: Pull complete
    Digest: sha256:7bd7a9ca99f868bf69c4b6212f64f2af8e243f97ba13abb3e641e03a7ceb59e8
    Status: Downloaded newer image for ubuntu:18.04
    ---> 39a8cfeef173
    Step 2/3 : RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
    ---> Running in 35433ebb43d4
    Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
    Get:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
    Get:3 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
    .
    .
    .
    Running hooks in /etc/ca-certificates/update.d...
    done.
    Removing intermediate container 35433ebb43d4
    ---> 4d4e2a6ea83b
    Step 3/3 : CMD [ "curl", "-s", "http://myip.ipip.net" ]
    ---> Running in 30a3a5f2f303
    Removing intermediate container 30a3a5f2f303
    ---> 2c191ad0c4c5
    Successfully built 2c191ad0c4c5
    Successfully tagged myip:v1

    运行myip

    [root@ip-10-1-0-142 ipip]# docker run myip
    当前 IP:52.215.213.34 来自于:爱尔兰 都柏林郡 都柏林 amazon.com

    嗯,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD 中可以看到实质的命令是 curl,那么如果我们希望显示 HTTP 头信息,就需要加上 -i 参数。那么我们可以直接加 -i 参数给 docker run myip 么?

    [root@ip-10-1-0-142 ipip]# docker run myip -i
    docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-i": executable file not found in $PATH: unknown.
    ERRO[0000] error waiting for container: context canceled

    我们可以看到可执行文件找不到的报错,executable file not found。之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i 替换了原来的 CMD,而不是添加在原来的 curl -s http://myip.ipip.net 后面。而 -i 根本不是命令,所以自然找不到。

    那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:

    [root@ip-10-1-0-142 ipip]# docker run myip curl -s http://myip.ipip.net -i
    HTTP/1.1 200 OK
    Date: Mon, 02 Aug 2021 11:00:28 GMT
    Content-Type: text/plain; charset=utf-8
    Content-Length: 84
    Connection: keep-alive
    CF-Cache-Status: DYNAMIC
    Report-To: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=RUCd8%2BCdlxsaLUf44f7INb92ZCnaIYiD4X2GYbLNyXJTiKg%2BOsAfEp3bPXOnfJrfRFnNDfyAP9p058HJ06wjUpA44ezop7eQEpLUBq37DiBP4GXI2YMaAt%2FkO%2Fz7Xx0%3D"}],"group":"cf-nel","max_age":604800}
    NEL: {"report_to":"cf-nel","max_age":604800}
    Server: cloudflare
    CF-RAY: 6786cd23feed1e89-AMS

    当前 IP:52.215.213.34 来自于:爱尔兰 都柏林郡 都柏林 amazon.com

    我们尝试使用 ENTRYPOINT 解决这个问题,使用 ENTRYPOINT 更新 Dockerfile 文件

    FROM ubuntu:18.04
    RUN apt-get update
    && apt-get install -y curl
    && rm -rf /var/lib/apt/lists/*
    ENTRYPOINT [ "curl", "-s", "http://myip.ipip.net" ]

    直接使用 docker run myipe 查看输出结果,

    [root@ip-10-1-0-142 ipip]# docker run myipe
    当前 IP:52.215.213.34 来自于:爱尔兰 都柏林郡 都柏林 amazon.com

    这次我们再来尝试直接使用 docker run myip -i:

    [root@ip-10-1-0-142 ipip]# docker run myipe -i
    HTTP/1.1 200 OK
    Date: Mon, 02 Aug 2021 11:04:59 GMT
    Content-Type: text/plain; charset=utf-8
    Content-Length: 84
    Connection: keep-alive
    CF-Cache-Status: DYNAMIC
    Report-To: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=K2An7ZP3qbdYTYdDYzojNsNZSi2jbEPs8N%2BQ7pwalGsr6kYLF9RE2ZSU2l%2FekmmBabeN9h%2FqBSwXZ2SuW%2F9RPbSx76YnYUtOAkSFGeC1CXEu6GyUWuRM7sB4Z%2BCyG4I%3D"}],"group":"cf-nel","max_age":604800}
    NEL: {"report_to":"cf-nel","max_age":604800}
    Server: cloudflare
    CF-RAY: 6786d416eaab53ec-LHR

    当前 IP:52.215.213.34 来自于:爱尔兰 都柏林郡 都柏林 amazon.com

    运行 docker run myipe -i 执行成功。是因为当 ENTRYPOINT 后,CMD 的内容被作为参数传给 ENTRYPOINT,而这里 -i 就是新的 CMD,因此会作为参数传给 curl,从而达到想要的结果,可以查看到HTTP 头的信息。

    场景二 应用运行前的准备工作

    启动容器就是启动主进程,有些时候需要在启动主进程前做一些准备工作。

    比如mysql的数据库,需要做数据库的配置、初始化等,这些动作需要在启动mysql 服务之前准备好。

    另外,避免使用root用户去启动服务,从提高安全性来讲,在启动前需要使用root做一些准备工作,然后在使用普通服务用户去启动服务。

    这些准备工作和容器 CMD 无关,无论 CMD 为什么指令,都需要预先做一个预处理的工作。
    使用脚本,然后利用 ENTRYPOINT 传参执行,脚本会接到参数作为命令,在脚本最后执行。
    官方镜像 redis 是这么做的:

    [root@ip-10-1-0-142 redis]# tree
    .
    ├── docker-entrypoint.sh
    └── redis-server

    0 directories, 2 files

    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 脚本。

    !/bin/sh

    # allow the container to be started with --user
    if [ "1" = 'redis-server' -a "(id -u)" = '0' ]; then
    find . ! -user redis -exec chown redis '{}' +
    exec gosu redis "0" "@"
    fi

    exec "$@"

    该脚本的内容就是根据 CMD 的内容来判断,如果是 redis-server ,则切换到 redis 用户身份启动服务器,否则依旧使用 root 身份执行。比如,
    $ docker run -it redis id
    uid=0(root) gid=0(root) groups=0(root)

    相关文章

      网友评论

          本文标题:Dockerfile 指令 功能 三 (ENTRYPOINT)

          本文链接:https://www.haomeiwen.com/subject/jcyjvltx.html