容器的构建方式
1. 通过容器构建镜像
通过容器构建是将部署好的容器,使用docker commit
命令将该容器打包成一个镜像
docker commit 容器名 镜像名:版本
#版本不填默认为latest
优点:
1. 交互性好
缺点:
1. 每次做更改都需要再次commit来构建
2. 无法查看容器的构建历史:做过哪些更改
2. Dockerfile构建镜像
Dockerfile 是一个文件,里面记录了镜像构建的步骤,它有自己的语法规则。
编写Dockerfile
一个Dockerfile的示例如下所示:
#基于centos镜像
FROM centos
#维护人的信息
MAINTAINER The CentOS Project <303323496@qq.com>
#安装httpd软件包
RUN yum -y update
RUN yum -y install httpd
#开启80端口
EXPOSE 80
#复制网站首页文件至镜像中web站点下
ADD index.html /var/www/html/index.html
#复制该脚本至镜像中,并修改其权限
ADD run.sh /run.sh
RUN chmod 775 /run.sh
#当启动容器时执行的脚本文件
CMD ["/run.sh"]
由上可知,Dockerfile结构大致分为四个部分:
(1)基础镜像信息
(2)维护者信息
(3)镜像操作指令
(4)容器启动时执行指令。
Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。下面会对上面使用到的一些常用指令做一些介绍。
构建
有了Dockerfile 我们就可以构建镜像了
docker build -t 镜像名:版本号 .
# .表示当前目录(docker会自动查找该目录下的Dockerfile文件
3. 命令解释
FROM: 表示基于什么基础镜像进行构建
MAINTAINER:构建者信息,说明是谁构建的
WORKDIR:指定后续执行步骤的工作目录,比如拷贝文件,创建文件操作在哪个目录下执行
RUN:构建镜像时运行的Shell命令,比如创建文件 touch xxx.txt
COPY:拷贝数据,即将主机上的文件拷贝到容器中去
ADD:也是拷贝数据,不同的是如果拷贝文件是压缩文件,那么拷贝到容器中会自动解压
ENV:指定环境变量,该变量可以在Dockerfile文件中使用,同时也能在容器中生效
CMD:启动容器时执行的Shell命令
ENTRPRINT:同CMD相似,稍有区别
更多详情可参考:你必须知道的Dockerfile
RUN, CMD,ENTRYPOINT的区别
RUN
指令是在构建镜像时执行的指令。通常会用来安装软件,操作文件夹等。CDM
和ENTRPRINT
是在启动容器时执行的指令。CMD
和ENTRPRINT
的相同点是:都是执行shell指令,但当出现多条CMD
或ENTRPRINT
指令时,仅有最后一个会生效。CMD
和ENTRPRINT
的不同点是:CMD
指令或被容器启动时run
后面指定的参数替代,而ENTRPRINT
不会被替代
CMD
和ENTRYPOINT
的区别决定了二者使用上的不同:
4. 由于CMD
命令会被docker run
的命令替换,因此它可用来设置默认启动命令,如果用户不想使用默认命令,就可以在docker run指令中指定自己的容器的启动命令
5. ENTRYPOINT
是必须执行的命令,所以往往用来启动应用程序或者服务,设置容器启动命令的最好方式是使用ENTRYPOINT
命令,不要使用CMD
。
4. CMD和ENTRPRINT命令格式
CMD命令的3种格式:
- Exec格式
格式: CMD [“命令”,“参数1”,“参数2”,…]
CMD ["echo","hello","world"]
- Shell格式
格式: CMD 命令 参数1 参数2 …
CMD echo "hello" "world"
- 为ENTRPRINT提供参数
ENTRPRINT ["echo","I","am"]
CMD ["entrprint1"]
# I am entrprint1
ENTRPRINT同样支持第一和第二种格式。除此之外,RUN同样适用这两种格式
Exec和Shell两种格式的区别:
主要区别在于:Shell 格式底层会调用/bin/sh -c
,而Exec不会。
比如:
ENV VERSION "1.0.2"
ENTRPRINT echo "hello,$VERSION"
# hello,1.0.2
ENV VERSION "1.0.2"
ENTRPRINT ["/bin/echo", "hello,$VERSION"]
# hello,$VERSION
可见Exec格式下的变量并没有被替换,需要改成
ENV VERSION "1.0.2"
ENTRPRINT ["/bin/sh","-c","echo hello,$VERSION"]
# hello,1.0.2
可见Exec底层不会调用/bin/sh -c
,需要自己补齐。
对于两种格式,推荐使用exec格式,因为可读性好,容易理解。