【云原生|Docker】07-Entrypoin与Cmd的区别

【云原生|Docker】07-Entrypoin与Cmd的区别

文章目录

  • 【云原生|Docker】07-Entrypoin与Cmd的区别
    • 前言
    • Entrypoint
      • Entrypoint概述
      • Entrypoint使用
      • 总结
    • CMD
      • CMD概述
      • CMD的使用
        • 方法1:
        • 方法2
        • 方法3
        • 总结
    • CMD和Entrypoint组合使用
      • 场景一:让镜像变成像命令一样使用
      • 场景2:应用运行前的准备工作

前言

	这一章节我们将再次复习CMD和ENTRYPOINT的用法,将详细介绍CMD和ENTRYPOINT的使用区别,同时也通过实用场景来介绍CMD与ENTRYPOINT的结合使用。

Entrypoint

Entrypoint概述

​ entrypoint(入口)才是真正用于定义容器启动以后的执行体的,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint来指定。

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

 ""

Entrypoint使用

格式:
    方法1:ENTRYPOINT ["executable","param1","param2"]
    方法2:ENTRYPOINT command param1 param2 (shell中执行)
 
示例:
    ENTRYPOINT ["ls", "/usr/local"]
    CMD ["/usr/local/tomcat"]
  • 当镜像中只有Entrypoint的时候,Entrypoint会被当作容器启动后的指令执行,在docker ps -a中看到的cmmd参数则为镜像中Entrypoint。 示例:

    FROM    centos:7
    LABEL   name=xiaohaizhou [email protected]
    RUN     yum install  openssh-server -y
    ADD     ./keys/ssh_host_ecdsa_key /etc/ssh/
    ADD     ./keys/ssh_host_ed25519_key /etc/ssh/
    ADD     ./keys/ssh_host_rsa_key /etc/ssh/
    RUN     chown root:root /etc/ssh/ssh_host_* && chmod 0600 /etc/ssh/ssh_host_* \
            && useradd -s /bin/bash -m -d /home/xhz xhz && \
            echo 'xhz123'|passwd xhz --stdin
    EXPOSE  22 80
    ENTRYPOINT     [ "/usr/sbin/sshd","-D" ]
    

在这里插入图片描述

  • 当镜像中有Entrypoint和CMD的时候,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给 ENTRYPOINT 指令。示例:
FROM    centos:7
LABEL   name=xiaohaizhou [email protected]
RUN     yum install  openssh-server -y
ADD     ./keys/ssh_host_ecdsa_key /etc/ssh/
ADD     ./keys/ssh_host_ed25519_key /etc/ssh/
ADD     ./keys/ssh_host_rsa_key /etc/ssh/
RUN     chown root:root /etc/ssh/ssh_host_* && chmod 0600 /etc/ssh/ssh_host_* \
        && useradd -s /bin/bash -m -d /home/xhz xhz && \
        echo 'xhz123'|passwd xhz --stdin
EXPOSE  22 80
ENTRYPOINT     [ "/usr/sbin/sshd" ]
CMD [ "-C" ]

在这里插入图片描述

  • 当镜像中有Entrypoint和CMD的时候(或者通过run直接传参),传入的参数会覆盖cmd,同时该参数会是entrypoint的参数,以上述dockerfie为例:

在这里插入图片描述

总结

  • 镜像中ENTRYPOINT只能有一个,如果存在多个,只有最后一条会被执行。
  • 镜像中只有Entrypoint的时候,Entrypoint会被当作容器启动后的指令执行。
  • 镜像中有Entrypoint和CMD的时候,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给 ENTRYPOINT 指令。

CMD

CMD概述

Docker不是虚拟机,事实上容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

在运行时可以指定新的命令来替代镜像设置中的这个默认命令。重点是**“默认”**,那就意味着,如果docker run没有指定任何可执行的命令,或者在镜像中也没有entrypoint,那么就会使用CMD指定的默认命令执行,比如:

比如ubuntu镜像默认的CMD是 /bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入bash。我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。

CMD的使用

格式:
    方法1:CMD ["executable","param1","param2"]    #使用exec执行,推荐的方式
    方法2:CMD command param1 param2   #在/bin/sh中执行,提供给需要交互的应用
    方法3:CMD ["param1","param2"]    #提供给ENTRYPOINT的默认参数
 
示例:
    CMD ["/usr/sbin/sshd","-D"]

方法1:

​ 命令在没有任何shell终端环境下,如果我们执行shell,必须把shell加入到括号的参数中,

FROM  centos:7
CMD	  ["/bin/bash","-c","echo $HOME"]

需要注意的是,采用括号的形式,那么第一个参数必须是命令的全路径才行。

方法2

​ 如果使用/bin/sh方式执行的话(cmd默认是在/bin/sh -c下执行),实际的命令会被包装为 sh -c 的参数的形式进行执行。比如

FROM  centos:7
CMD   echo $HOME

在实际执行中,会变更为:

CMD [ "sh", "-c", "echo $HOME" ]

方法3

​ 当镜像中存在entrypoint的时候,镜像中的CMD会被当作提供给ENTRYPOINT的默认参数,比如:

FROM  centos:7
ENTRYPOINT  ["/usr/bin/sshd"]
CMD  ["-D"]

在实际执行中,会变更为:

"/usr/bin/sshd  -D"

总结

  • 当镜像总ENTRYPOINT和CMD同时存在的时候,此时镜像中的CMD会被当作提供给ENTRYPOINT的默认参数;
  • 当经常总只有cmd的时候,CMD有方法1和方法2两种书写格式,需要注意的是,采用括号的形式(方法1),那么第一个参数必须是命令的全路径才行。
  • 镜像中CMD只能有一个,如果存在多个,只有最后一条会被执行。
  • 当执行docker run 后面接参数的时候,该参数会替换镜像中默认的CMD

CMD和Entrypoint组合使用

建议:
	组合使用ENTRYPOINT和CMD命令式, 确保你一定用的是Exec表示法. 如果用其中一个用的是Shell表示法, 或者一个是Shell表示法, 另一个是Exec表示法, 你永远得不到你预期的效果。

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

假设我们需要一个ssh的命令,来进行远程客户机,我们通过cmd来实现,

FROM    centos:7
LABEL   name=xiaohaizhou [email protected]
RUN     yum install  openssh-clients -y

EXPOSE  22

# 192.168.194.128为本机ip
CMD [ "/usr/bin/ssh", "192.168.194.128" ]

我们使用 docker build -tssh_client . 来构建镜像的话,如果我们需要ssh本地,只需要执行:

[root@clinet ubuntu]# docker run -it ip:v1.2

在这里插入图片描述

这么看起来好像可以直接把镜像当做命令使用了,但是我们希望不要写死远程ip,而是可以根据自己传入的ip进行远程连接。那我们就可以这样去写:

FROM    centos:7
LABEL   name=xiaohaizhou [email protected]
RUN     yum install  openssh-clients -y

EXPOSE  22
ENTRYPOINT [ "/usr/bin/ssh" ]
CMD [ "127.0.0.1" ]

【云原生|Docker】07-Entrypoin与Cmd的区别_第1张图片

这样就是实现,然而这个实验并不完善且没有实际意义。通过这个场景我们再次证实了当存在 ENTRYPOINT 后,CMD 的内容将会作为参数传给 ENTRYPOINT,这里的127.0.0.1就是默认参数,192.168.194.128/129就是我们手动传入的参数。

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

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

比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的 mysql 服务器运行之前解决。

此外,可能希望避免使用 root 用户去启动服务,从而提高安全性,而在启动服务前还需要以 root 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 root 身份执行,方便调试等。

这些准备工作是和容器CMD无关的,无论CMD是什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入ENTRYPOINT中去执行,而这个脚本会将接到的参数(也就是 )作为命令,在脚本最后执行。比如官方镜像 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脚本:

# 该脚本的内容就是根据CMD的内容来判断,如果是 redis-server 的话,则切换到 redis 用户身份启动服务器,否则依旧使用 root 身份执行

#!/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 "$@"

你可能感兴趣的:(Docker,运维,云原生,docker)