zoukankan      html  css  js  c++  java
  • 6 Dockerfile指令详解 && ENTRYPOINT 指令

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

    ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。

    ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过docker run 的参数 --entrypoint 来指定。

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

    <ENTRYPOINT> "<CMD>"

    那么有了 CMD 后,为什么还要有 ENTRYPOINT 呢?这种

    <ENTRYPOINT> "<CMD>"

    有什么好处么?让我们来看几个场景。

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

    假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD 来实现:

    FROM ubuntu:16.04
    RUN apt-get update 
        && apt-get install -y curl 
        && rm -rf /var/lib/apt/lists/*
    CMD [ "curl", "-s", "http://ip.cn" ]

    假如我们使用 docker build -t myip . 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:

    $ docker run myip
    当前 IP:61.148.226.66 来自:北京市 联通

    嗯,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?

    比如从上面的 CMD 中可以看到实质的命令是 curl ,那么如果我们希望显示 HTTP 头信息,就需要加上 -i 参数。那么我们可以直接加 -i 

    参数给 docker run myip 么?

    $ docker run myip -i
    docker: Error response from daemon: invalid header field value "
    oci runtime error: container_linux.go:247: starting container pr
    ocess caused "exec: \"-i\": executable file not found in $P
    ATH"
    ".

    我们可以看到可执行文件找不到的报错, executable file not found 。之前我们说过,跟在镜像名后面的是 command ,运行时会替换 CMD 的默认值。因此

    这里的 -i 替换了原来的 CMD ,而不是添加在原来的 curl -s http://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。
    那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:

    $ docker run myip curl -s http://ip.cn -i

    这显然不是很好的解决方案,而使用 ENTRYPOINT 就可以解决这个问题。现在我们重新用 ENTRYPOINT 来实现这个镜像:

    FROM ubuntu:16.04
    RUN apt-get update 
        && apt-get install -y curl 
        && rm -rf /var/lib/apt/lists/*
    ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

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

    $ 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 中就是这么做的:

    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
        chown -R redis .
        exec su-exec redis "$0" "$@"
    fi
    exec "$@"

    该脚本的内容就是根据 CMD 的内容来判断,如果是 redis-server 的话,则切

    换到 redis 用户身份启动服务器,否则依旧使用 root 身份执行。比如:

    $ docker run -it redis id
    uid=0(root) gid=0(root) groups=0(root)

     

  • 相关阅读:
    【力扣】767. 重构字符串
    【力扣】976. 三角形的最大周长
    【力扣】164. 最大间距
    【力扣】454. 四数相加 II
    JS中,输出1-10之间的随机整数
    web移动端浮层滚动阻止window窗体滚动JS/CSS处理
    禁止网站F12和查看源码
    苹果浏览器移动端click事件延迟300ms的原因以及解决办法
    jQuery下锚点的平滑跳转
    js实现placehoider效果
  • 原文地址:https://www.cnblogs.com/reachos/p/8609025.html
Copyright © 2011-2022 走看看