写在前面

本文一起看下Dockerfile中经常用到的几个类似命令,RUN,CMD,ENTRYPOINT。

1:容器是怎么来的?

想要有容器我们就必须先创建镜像,而想要有镜像,我们则必须写一个用来描述想要创建的镜像的文件,这个文件我们一般叫做Dockerfile(非强制),则容器怎么来的就如下图:

docker-entrypoint.sh docker-entrypoint.sh怎么生成的_Docker

经过上图的过程1我们就有了镜像,经过过程2我们就有了容器了,知道了这个过程,我们就可以来正式开始分析RUN,CMD,ENTRYPOINT命令了。

2:RUN

docker-entrypoint.sh docker-entrypoint.sh怎么生成的_Docker

RUN命令是在上图过程1中执行的,如下的Dockerfile:

FROM busybox
WORKDIR /var
RUN pwd

则执行docker build时就会输出pwd的结果:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t test-push-dockerhub:0.1 -f howPwd.txt helloworld-app/
Sending build context to Docker daemon  8.738kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : WORKDIR /var
    /var # 这里就是pwd的输出,其实输出的就是工作目录,不过输出的到底是什么此时不重要,我们主要是验证pwd在docker build时执行了
Step 3/3 : RUN pwd
 ---> Using cache
 ---> 7975c01019bd
Successfully built 7975c01019bd

3:CMD

在容器启动时执行的命令,一般用来启动应用等,如下Dockerfile:

dongyunqi@dongyunqi-virtual-machine:~/test$ cat testEntrypoint.txt 
FROM busybox
CMD echo "hello world"

构建:

dongyunqi@dongyunqi-virtual-machine:~/test$ docker build -t test-entrypoint:v0.1 -f testEntrypoint.txt .
...

运行容器:

dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test-entrypoint:v0.1
hello world

可以看到正常输出了。另外如果是有多个CMD只会保留最后一个,如下:

FROM busybox
CMD echo "hello world"
CMD echo "hello world1111"

测试:

dongyunqi@dongyunqi-virtual-machine:~/test$ docker build -t test_entrypoint:v0.1 -f testEntrypoint.txt .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : CMD echo "hello world"
 ---> Using cache
 ---> c596d2e7bfb5
Step 3/3 : CMD echo "hello world1111"
 ---> Running in 9369670af208
Removing intermediate container 9369670af208
 ---> d7d08688d050
Successfully built d7d08688d050
Successfully tagged test_entrypoint:v0.1
dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test_entrypoint:v0.1
hello world1111
dongyunqi@dongyunqi-virtual-machine:~/test$

可以看到只输出了hello world1111。以上的是shell格式,我们也可以用Exec 格式,如下:

dongyunqi@dongyunqi-virtual-machine:~/test$ cat testEntrypoint.txt 
FROM busybox
CMD ["/bin/echo", "Hello world222"]

测试:

dongyunqi@dongyunqi-virtual-machine:~/test$ docker build -t test_entrypoint:v0.1 -f testEntrypoint.txt .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM busybox
 ---> 827365c7baf1
Step 2/2 : CMD ["/bin/echo", "Hello world222"]
 ---> Running in d69c8fdbb1a4
Removing intermediate container d69c8fdbb1a4
 ---> 5e0920f3e988
Successfully built 5e0920f3e988
Successfully tagged test_entrypoint:v0.1
dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test_entrypoint:v0.1
Hello world222

可以看到正常输出了Hello world222。但是如果是在docker run时指定了启动命令,则会覆盖CMD,如下:

dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test_entrypoint:v0.1 /bin/echo "hey man!"
hey man!

4:ENTRYPOINT

ENTRYPOINT在Dockerfile中的表现和CMD是一样的,但是ENTRYPOINT不会被docker run中指定的命令覆盖,但是也分为两种情况,如果是使用shell格式的话则docker run中指定的命令将会被忽略,如下:

dongyunqi@dongyunqi-virtual-machine:~/test$ cat testEntrypoint.txt 
FROM busybox
ENTRYPOINT echo "Hello world44444"  
dongyunqi@dongyunqi-virtual-machine:~/test$ docker build -t test_entrypoint:v0.1 -f testEntrypoint.txt .
Sending build context to Docker daemon  2.048kB
...
dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test_entrypoint:v0.1 11111111111/bin/echo "hey man!"
Hello world44444

如果是Exec格式的话则会被当做参数追加到后面,如下:

dongyunqi@dongyunqi-virtual-machine:~/test$ cat testEntrypoint.txt 
FROM busybox
ENTRYPOINT ["echo", "Hello world555"]  
dongyunqi@dongyunqi-virtual-machine:~/test$ docker build -t test_entrypoint:v0.1 -f testEntrypoint.txt .
Sending build context to Docker daemon  2.048kB
...
dongyunqi@dongyunqi-virtual-machine:~/test$ docker run --rm test_entrypoint:v0.1 11111111111/bin/echo "hey man!"
Hello world555 11111111111/bin/echo hey man!

相当于是在Dockerfile中写的是ENTRYPOINT ["echo", "Hello world555", "11111111111/bin/echo", "hey man!"]

4:比较

RUN:在docker build生成镜像时执行。
CMD:在docker run时执行,但其会被docker run中指定的命令覆盖
ENTRYPOINT:在docker run时执行,但不会被docker run中指定的命令覆盖,如果是ENTRYPOINT使用shell格式则会忽略,使用Exec格式则会作为参数追加后执行

所以RUN比较独立,CMD和ENTRYPOINT几乎一样,只是在docker run指定指定命令时的表现不同。

写在后面

参考文章列表:

docker精简入门(五)run&cmd&enterpoint区别