内容摘要
- dockerfile 常用指令
- RUN/CMD/ENTRYPOINT区别
Dockerfile 常用指令
前面初步讲解了Dockerfile,这节详细介绍Dockerfile用到的指令和语法。
下面来看一个较为完整的Dockerfile,内容如下:
# dockerfile haha FROM centos MAINTAINER [email protected] WORKDIR /mydir RUN touch mytext COPY test . ADD busybox-1_29_0.tar.gz . ENV VERSION "1.0.2" CMD echo "I am cmd" CMD echo $VERSION ENTRYPOINT sleep 1000000
先不解释上面命令的意义,运行该文件构建镜像。
在构建镜像前,先在根目录下创建 test 文件夹,在其下面创建Dockerfile,以及准备构建使用的test文件,使用Xftp将busybox的压缩包上传到test目录下。
具体操作见下面操作截图:
说明:busybox文件的压缩包自行在github上下载。
构建镜像,命令为:
docker build -t centos-with-busybox .
从上面 Step 信息可以看出,构建步骤是按照我们在Dockerfile中的命令先后顺序执行的,最后生成的镜像 SIZE 比基础镜像要多 9M。
运行容器,检查构建是否成功, 命令为:
docker run -d --name centos-with-busybox1 centos-with-busybox
进入容器可以看到当前目录为 mydir,而且里面包含 创建的文件以及拷贝进去的文件,busybox压缩包已经被解压。
使用docker history 指令查看刚才构建的镜像:
从红框中可以看到 dockerfile 文件中执行的操作步骤。
下面详细解释下 dockerfile 文件用到的命令:
FROM:表示基于什么基础镜像进行构建
MAINTAINER:构建者信息,说明是谁构建的
WORKDIR:指定后续执行步骤的工作目录,比如拷贝文件,创建文件操作在哪个目录下执行
RUN:在容器运行命令,比如创建文件 touch xxx.txt
COPY:拷贝数据,即将主机上的文件拷贝到容器中去
ADD:也是拷贝数据,不同的是,如果被拷贝文件是压缩文件,那么拷贝到容器后会自动解压缩
ENV:指定环境变量,该环境变量可以在Dockerfile文件中使用,同时在容器中也生效
CMD:容器启动时运行的命令
ENTRYPOINT:同CMD相似,但也有区别
RUN/CMD/ENTRYPOINT 区别
从上面可以看出 RUN/CMD/ENTRYPOINT 都可以运行命令,那它们的区别是什么呢?
RUN 和 CMD/ENTRYPOINT的区别比较清楚:RUN主要用于在容器安装软件,操作文件和文件夹等,CMD/ENTRYPOINT主要用于启动容器,但是有很大的差别。
下面通过实验逐步分析二者之不同:
修改 Dockerfile 文件,内容如下:
# dockerfile haha FROM centos MAINTAINER [email protected] WORKDIR /mydir RUN touch mytext COPY test . ADD busybox-1_29_0.tar.gz . ENV VERSION "1.0.2" CMD echo "I am cmd" CMD echo $VERSION
按照上面步骤重新构建镜像并运行,命令为:
docker run -it --name centos-with-busybox centos-with-busybox
镜像构建就不展示截图,镜像名为:centos-with-busybox,创建的容器也使用这个名字。
可以看到容器运行结果为环境变量VERSION的版本信息,但是倒数第二行的CMD命令没有输出,说明只有最后一个CMD命令生效。
下面换个方式运行容器,在 docker run 后面指定运行参数:
命令为:
docker run -it --name centos-with-busybox centos-with-busybox /bin/bash
指定 /bin/bash 作为启动参数,发现没有输出环境变量VERSION的版本信息,说明CMD命令被 /bin/bash 取代了。
那么ENTRYPOINT会如何表现呢?
修改Dockerfile,内容如下:
# dockerfile haha FROM centos MAINTAINER [email protected] WORKDIR /mydir RUN touch mytext COPY test . ADD busybox-1_29_0.tar.gz . ENV VERSION "1.0.2" CMD echo "I am cmd" CMD echo $VERSION ENTRYPOINT echo "I am entrypoint"
先不加参数运行容器,命令为:
docker run -it --name centos-with-busybox centos-with-busybox
可见打印信息和Dockerfile中规定的字符串一致。
带上参数运行:
docker run -it --name centos-with-busybox centos-with-busybox /bin/bash
和上面一致,仍旧打印出一样的字符串。
对于ENTRYPOINT而言,无论 docker run 是否带有执行命令,都会执行,而CMD则相反。
问题:如果先后出现两个ENTRYPOINT命令,那么先出现的会执行吗?
修改Dockerfile,内容如下:
# dockerfile haha FROM centos MAINTAINER [email protected] WORKDIR /mydir RUN touch mytext COPY test . ADD busybox-1_29_0.tar.gz . ENV VERSION "1.0.2" CMD echo "I am cmd" CMD echo $VERSION ENTRYPOINT echo "I am entrypoint 1" ENTRYPOINT echo "I am entrypoint 2"
构建镜像,并启动容器,命令为:
docker run -it --name centos-with-busybox centos-with-busybox
只运行了第二个ENTRYPOINT指令,第一个被忽略。
在这点上,ENTRYPOINT和CMD一样,即如果有多条该命令,只会执行最后一条。
CMD和ENTRYPOINT的区别决定了二者使用上不同:
1、由于CMD命令可以被docker run的命令替换,因此它可以用来设置默认启动命令,如果用户不想使用默认命令,就可以在docker run指令中指定自己的容器启动命令;
2、ENTRYPOINT 是必须执行的命令,所以往往用来启动应用程序或者服务,设置容器启动命令最好使用ENTRYPOINT,不要使用CMD。
3、ENTRYPOINT可以和CMD结合起来使用,充分结合二者的优点,可以使容器启动更加方便。
下面显示下如何结合使用ENTRYPOINT和CMD两个命令:
修改Dockerfile,内容如下:
FROM centos MAINTAINER [email protected] WORKDIR /mydir RUN touch mytext COPY test . ADD busybox-1_29_0.tar.gz . ENV VERSION "1.0.2" ENTRYPOINT ["echo","I am"] CMD ["entrypoint1"]
构建镜像并运行,命令为:
docker run -it centos-with-busybox
输出内容为: I am entrypoint1
带命令执行docker run,命令为:
docker run -it centos-with-busybox entrypoint2
输出内容为: I am entrypoint2
容器启动携带的参数entrypoint2,覆盖了entrypoint1。
对比两种运行方式,可以看到二者输出不同。
ENTRYPOINT命令是静态的,CMD命令可以动态变更,上面将二者结合起来了。
因此在启动容器时:不变部分使用ENTRYPOINT执行命令,可变部分使用CMD,用户在运行容器时给出参数取代CMD命令。从而做到动静结合,容器运行更加灵活,更容易控制。
实验
使用dockerfile命令构建一个镜像