如果你按照下面的方式运行了一个ubuntu容器,你将会发现一段时间后,容器退出了,为什么会发生这种情况?
这是因为,不像virtual machine,containers无意于托管os operation system,containers意图于运行指定的任务或进程,如托管一个web server或其应用的实例等,或简单的执行一些计算和分析任务,一旦任务完成,容器将会退出,容器仅存活在其内部应用在活动状态,若容器内的应用退出或崩溃,则容器将会退出。
那么问题是,谁定义了容器内该要运行着什么?
如果你查看了Dockfile定义,如下的nginx dockefile,你将会看到一条cmd指令
最后的cmd ["nginx"],表示该应用在容器启动后,将会在容器内运行。对应nginx 镜像而言,它是nginx命令,对于mysql 镜像而言,它是mysql命令:
前面我们仅仅在容器内运行了一个ubuntu操作系统。
下面我们看下该ubuntu镜像的Dockerfile定义:
能够看到它使用bash作为默认命令,而bash并不是像web server或database server那样,是一个真正的进程,它是一个shell,监听来自终端的输入,在找不到终端时,它将会退出。
这就导致,当我们执行docker run ubuntu命令,运行一个容器时,默认docker并没有attach一个终端到容器内,因此bash 程序没有找到终端,然后就退出了。
因此如何指定一个不同的命令来启动容器?其中一个选项是,附加命令到docker run ,这样它将覆盖容器内定义的command,如docker run unbuntu sleep 5,此时在容器启动后,它将sleep 5s后退出
但是如何持久化该修改呢?即声明你想要该镜像所创建的容器启动后,总是执行sleep命令
此时你可以基于ubuntu镜像创建自己的镜像,并指定一条新的命令。有多种指定命令的方式,要么简单地以shell形式,或json数组形式;需要注意的是,如果以json数组形式指定命令,数组的第一个元素必须是能够执行的命令,请不要像下面这种形式指定命令,而是应该将命令和它的参数隔离开来
如果我们想要实现,启动后随眠10s,可以在启动容器的时候,传入参数:
但是多数时候,我们可能直接使用entrypoint,它接收命令行参数做append操作,也可以配置默认值,
当启动容器时候,没有指定任何的参数,cmd命令,会append到entrypoint命令后面,如
此时,若在启动容器时,指定了参数,则会替换掉dockerfile中的cmd命令
当然,如果你想要覆盖dockerfile中定义的entrypoint,则可以使用--entrypoint选项参数,如
另外我们比较关心的是,dockerfile中定义的command和entrypoint,映射到kubernetes资源定义文件中会是什么样的?
在启动容器时,命令行参数等价于在POD定义文件中这样来书写
我们可以在POD定义文件中,使用Args字段参数来覆盖dockerfile中的command指令;而使用command字段来覆盖dockerfile中的entrypoint指令