一、Dockerfile 概念
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。
Dockfile最多不超过128层,也就是一个docker最多128行
1.1. Dockerfile的体系结构
先来看一下我们最常用的centos的Dockerfile
在hub.docker.com中所有centos
FROM scratch MAINTAINER The CentOS Project <cloud-ops@centos.org> ADD c68-docker.tar.xz / LABEL name="CentOS Base Image" \ vendor=CentOS \ license=GPLv2 \ build-date=2016-06-02 # Default command CMD [/bin/bash"]
含义:
FROM scratch 这里引用了一个父镜像. 我们通常在使用tomcat或者jdk的时候,他的父类镜像是centos. 而centos的父类镜像是scratch,scratch是所有镜像的基础镜像 MAINTAINER The CentOS Project <cloud-ops@centos.org> MAINTAINER是备注的意思,这是哪个团队,哪个人写的 ADD c68-docker.tar.xz / 这个参数后面讲解 LABEL name= LABEL顾名思义,就是描述的含义 # Default command CMD [] 表示运行/bin/bash. 我们通常在运行docker run -it lxl/centos的时候,有时候加/bin/bash,有时候不加. 那么什么时候加,什么时候不加呢? 其实加和不加都是可以的....因为这里已经给我们自动加了/bin/bash,如果不加就是用默认的,如果加了,就相当于有两个/bin/bash,他只会执行一个
1.2. dockerfile的编写规则
1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2. 指令按照顺序,从上到下,一条指令就是一层
3. #表示注释
4. 每条指令都会创建一个新的镜像层,并对镜像进行提交
1.3 docker执行dockerfile的流程
1. docker从基础镜像运行一个容器
2. 执行一条指令并对容器修改
3. 执行类似docker commit的操作提交一个新的镜像层
4. docker在基于刚提交的镜像运行一个新容器
5. 执行dockerfile中的下一条指令直到所指令都执行完成
1.4 dockerfile的保留字指令
-
FROM:
基础镜像,当前镜像是基于哪一个镜像
-
MAINTAINER:
镜像维护者的姓名,邮箱地址
-
RUN:
容器构建时需要运行的命令
-
EXPOSE:
当前容器对外暴露的端口号
-
WORKDIR:
指定在创建容器后,终端默认登录进来的工作目录,一个落脚点
没有指定,进入到容器的根目录 -
ENV:
用来在构建镜像的过程中设置环境变量
这个环境你变量可以在后续的任务Run指令中使用,这就如同在命令前面指定了环境变量前缀一样,也可以在其他指令中直接使用这些环境变量.
举个例子:
ENV MY_PATH /usr/home
WORKDIR $MY_PATH
这就是说,进入到容器以后,直接进入的工作目录不是根目录,而是/usr/home -
ADD & COPY
ADD 和 COPY一起说 他俩都有将宿主机指定目录下的文件拷贝到到镜像中的含义. ADD比COPY更强大. ADD有拷贝并解压的含义
例如:ADD c68-docker.tar.xz /
这个含义就是,拷贝到根目录,并进行解压
-
VOLUME:
容器数据卷,用于数据保存和持久化
-
CMD:
指定一个容器启动时需要运行的命令,Dockerfile中可以有多个CMD命令,但只有最后一个生效,CMD会被docker run之后的参数替代
-
ENTRYPOINT:
和CMD有相同之处 指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在绑定容器启动程序及参数. 不同之处是,ENTRYPOINT 不会被docker run后面的参数代替,而是追加
-
ONBUILD:
子镜像继承自父类镜像以后,父镜像的onbuild就会被触发,这就相当于一个触发器,满足一定条件的时候触发
二. Dockerfile案例
2.1 Base镜像
Docker hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的.
最基础的base镜像是scratch,这是所有镜像的祖先
2.2 案例1
目标: 练习使用WORKDIR,FROM,EVN,RUN,CMD命令
以centos镜像为例. 我们看
1. 目标: 下面我们要处理的就是以上两个问题:
1) 设置进入容器的目录不是根目录
2) 为centos安装vim和ifconfig命令
2. 编写dockerfile
FROM scratch MAINTAINER LXL<23413@11.com ENV MYPATH /usr/local WORKDIR $MYPATH RUN yum -y install vim RUN yum -y install net-tools EXPOSE 80 CMD echo success CMD /bin/bash
下面来详细看看其含义
基础镜像 FROM scratch 指定镜像维护的作者和邮箱 MAINTAINER LXL<.com 设置环境变量mypath ENV MYPATH /usr/local 设置进入容器的默认目录是/usr/local WORKDIR $MYPATH 安装vim和net-tools工具 RUN yum -tools 设置端口号是80 EXPOSE 运行命令,打印success CMD echo bash CMD /bin/bash
3. 构建dockerfile,生成镜像
docker build -f Dockerfile2 -t mycentos:1.3 .
4. 运行构建好的镜像
docker run -it mycentos:1.3 /bin/bash
5. 查看dockerfile的构建历史
docker history 镜像ID
这个命令可以查询镜像构建的各个层
2.3 案例2--CMD命令 和 EntryPoint的区别
1. CMD命令
CMD: dockerfile中可以有多个CMD指令,但是只有最后一个生效. CMD会被docker run中最后的参数替换
查看tomcat的dockerfile.
..... 最后几行 RUN set -e \ && nativeLines=$(catalina.sh configtest 2>&1) \ && nativeLines=$(echo "$nativeLines | grep 'Apache Tomcat Native') | sort -u) \ && if ! echo $nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \ echo >&2 ; \ exit 1; \ fi EXPOSE 8080 CMD ["catalina.sh","run"]
最后一行是启动tomcat的命令. 所以,我们运行tomcat镜像的时候,会启动tomcat
下面,我们在命令行中使用其他CMD命令. 按照规则,docker run中最后的参数将替换dockerfile中的参数
docker run -it -p 8080:8080 docker.io/tomcat ls -l
运行结果:
没有启动tomcat,而是进入了查看当前目录的文件.
2. ENTRYPOINT命令
ENTRYPOINT: 执行命名,和CMD类似,不同的是,ENTRYPOINT命令不会被docker run中的命令替换,而是被追加
我们来看一个案例,curl http://ip.cn 是查询当前网络信息
第一步: 编写一个dockerfile
FROM docker.io/centos MAINTAINER lxl < 23242@qq.com RUN yum install -y curl CMD [curl",-shttps://www.ip.cn"]
第二步: 构建dockerfile
docker build -f Dockerfile3 -t myip .
第三步: 运行容器
docker run -it myip
运行结果
您现在的 IP:**.**.**
所在地理位置:北京市 联通
GeoIP: Beijing,China
第四步: 我们还想查看header. 于是追加一个参数-i即可
如果使用CMD就会以docker run中的命令替换dockerfile,这时我们应该使用ENTRYPOINT.
FROM docker.io/y curl ENTRYPOINT ["]
重新build,然后在docker run启动的时候增加 -i命令
docker run -it myip2 -i
1. 新建文件,创建一个DockerFile
文件名叫Dockerfile. 固定叫法
From ubuntu MAINTAINER lxl CMD echo hello docker'
2. 构建Dockerfile
docker build -t demo-docker .
domo-docker: 是生成的新的docker镜像的名字.
构建的时候,首先会判断基础镜像是否存在,如果不存在,则下载
3. 查看构建好的镜像
docker image demo-docker
我们看到生产了一个64.2M的镜像. 版本定义了一个最新版本
4. 运行镜像
docker run demo-docker
运行镜像,打印输出hello docker
以上我们就自己定义了一个dockerfile,并运行起来了.
2.4 案例3--ONBUILD命令
第一步: 构建一个父类镜像
FROM docker.io/centos MAINTAINER LXL<234@QQ.COM CMD [] 增加了触发器 ONBUILD RUN echo onbuild starting ...... 886"
第二步: 编译父类镜像
docker build -f dockerfile4 -t centos03 .
第三步: 构建一个子类镜像
这引用的父类镜像是centos03
FROM centos03 MAINTAINER LXL<"]
第四步: 编译子类镜像
docker build -f dockerfile5 -t child-centos04 .
2.5 案例4
练习COPY ADD命令
按照如下操作执行
1. 创建一个/docker/tomcat9文件夹,里面放三个文件
touch c.txt
apache-tomcat-9.0.8.tar.gz
jdk.tar.gz
其中后两个文件是tomcat和jdk的压缩包,我们提前下载好,放到文件夹里即可. 如下图所示:
下载tomcat sudo curl -OL https://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.35/bin/apache-tomcat-9.0.35.tar.gz 下载jdk sudo curl -OL https:www.oracle.com/webapps/redirect/signon?nexturl=https://download.oracle.com/otn/java/jdk/8u251-b08/3d5a2bb8f8d4428bbe94aed7ec7ae784/jdk-8u251-linux-x64.tar.gz
2. 在/docker/tomcat9文件夹下创建一个dockerfile文件
FROM docker.io/centos # 设置dockerfile的作者和邮箱 MAINTAINER lxl < @qq.com # 拷贝文件到指定目录并解压 ADD apache-tomcat-9.0.35.tar.gz /usr/local ADD jdk-8u251-linux-x64.tar.gz /usr/local # 定义环境变量 ENV WORKPATH /usr/# 设定工作目录 WORKDIR $WORKPATH # 设置jdk和tomcat的环境变量 ENV JAVA_HOME /usr/local/jdk1.8.0_251 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-35 ENV CATALINA_BASE /usr/local/apache-tomcat- ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_BASE/bin # 设定端口号 EXPOSE 8080 # 启动并运行tomcat CMD $WORKPATH/apache-tomcat-35/bin/startup.sh && tail -F $WORKPATH/apache-tomcat-35/logs/catalina.out
3. 构建dockerfile
4. docker run 运行镜像
docker run -it tomcat9
5. 验证tomcat启动结果
在本地输入localhost:8080. 看到tomcat启动页