01_DOCKERFILE语法简述和示例

一: DOCKFILE语法:

常用指令:
FROM: 申明DOCKERFILE的基础镜像
MAINTAINER:申明DOCKERFILE的描述信息, 通常在这个地方会申明作者信息
WORKDIR: 申明镜像的工作空间,一旦申明后,此关键字下的层级的RUN,CMD会在这么目录下进行,并且申明后,在docker run && docker exec 进入镜像后,默认的pwd是此处申明的位置
RUN:执行命令的关键字,也就是在build镜像时,在基础镜像的基础上执行哪些命令。更具镜像的分层概念,如果需要执行多个命令,需使用&&符号连接起来
ADD: 拷贝宿主机文件进镜像中,如果源文件是zip.tar,gz等这种压缩包,会在目标地址上自动解压。并且,ADD命令拷贝远程的资源,但是docker官方强烈不建议这么做
COPY: 拷贝宿主机文件进镜像中,但是不会自动解压。如果没有自动解压的需求,建议拷贝文件使用COPY指令
USER: 申明用户,此关键字申明后,下面层级的RUN,CMD,ENV等会用此用户执行。这里需要注意的是,如果我们在镜像中,不声明USER,那么进程使用root启动的,反应到宿主机上,也会是一个root进程,这样是不符合安全规范的
ENV: 申明环境变量,类似Linux的export。
CMD: 启动镜像时执行的命令

非常用指令
EXPOSE : 申明暴露的端口,但是个人理解在使用k8s编排后,此指令不需要使用,端口的暴露可通过k8s来完成
ENTRYPOINT: 此指令也是运行镜像时执行的命令,如果有多个ENTRYPOINT,则只会执行最后一个。该指令的功能,可以通过CMD来完成。目前没有发现必须使用此指令的场景
ARG: 申明只在build镜像过程中生效的环境变量,在后续的生产环境使用Jenkins构建镜像时可能会用到这个关键字
VOLUME: 数据卷,在使用k8s编排后,此指令实现的功能会在k8s中实现

二:DOCKFILE示例:

构建含有JDK的基础镜像:

FROM centos:7 as basis                                      #申明基础镜像,根据现在生产环境的现状,这里使用的是centos 7作为基础镜像
MAINTAINER o2o "[email protected]"                    #申明dockerfile的作者信息
RUN useradd appsvr && \                                     #根据现在生产环境的现状,从useradd命令开始到chown appsvr:appsvr /home/appsvr/apps -R 这条命令为止,进行初始化的工作
    mkdir /home/appsvr/logs -p && \
    mkdir /var/log/tomcat -p && \
    mkdir /home/appsvr/apps -p && \
    chown appsvr:appsvr /var/log/tomcat -R && \
    chown appsvr:appsvr /home/appsvr/logs -R && \
    chown appsvr:appsvr /home/appsvr/apps -R && \
    localedef -i zh_CN -c -f UTF-8 zh_CN.UTF-8 && \        #修改镜像的字符集
    echo "export LC_ALL=zh_CN.UTF-8" >> /etc/profile       #修改镜像的字符集
ADD jdk-8u171-linux-x64.tar.gz /home/appsvr                #将jdk的压缩包拷贝进镜像中,由于jdk的压缩包需要解压,所以这里使用ADD指令
COPY localtime /etc/localtime                              #修改镜像的时区
ENV LANG zh_CN.UTF-8                                       #为了修改镜像的字符集而申明的环境变量
ENV LC_CTYPE zh_CN.UTF-8                                   #为了修改镜像的字符集而申明的环境变量

以test-gateway为例,构建一个包含应用的镜像

FROM o2o-jdk-centos:v1                                                        #申明基础镜像,此处的o2o-jdk-centos:v1为根据上文中的dockerfile 构建出来的镜像
MAINTAINER o2o "[email protected]"                                      #申明dockerfile的作者信息
WORKDIR /home/appsvr/                                                         #申明工作目录
COPY --chown=appsvr:appsvr test-gateway.jar /home/appsvr/app/               #拷贝jar包到镜像中,这里加入了--chown=appsvr:appsvr 是为了修改目标镜像中jar的权限,appsvr在上面构建出来的镜像中,已经创建
USER appsvr                                                                   #申明用户信息,这里申明后,下面的EVN和CMD都是在这个用户下操作
ENV JAVA_HOME=/home/appsvr/jdk1.8.0_171                                       #申明JAVA_HOME 的相关变量
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar                #申明JAVA_HOME 的相关变量
ENV PATH=$JAVA_HOME/bin:$PATH                                                 #申明JAVA_HOME 的相关变量
ENV LANG zh_CN.UTF-8                                                          #修改字符集
ENV LC_CTYPE zh_CN.UTF-8                                                      #修改字符集
ENV TZ Asia/Shanghai                                                          #申明时区的变量,这个地方如果不声明的话,在使用java -jar启动应用时,应用的时区还是会和镜像中的时间相差8小时
CMD ["java","-server","-jar","/home/appsvr/app/access-gateway.jar"]           #镜像启动时执行的命令 此处的命令应当是标准输入输出,为了方便以后k8s中的日志收集,并且官方最佳实践也是这么推荐

三: DOCKERFILE的一些优化建议:

1: 选择合理的基础镜像,这里常用的有Centos,Ubuntu,Alpine。虽然Alpine有着绝对的大小优势(5.6M),但其是一个非常精简的Linux,并且没有glibc,为了避免程序运行时的一些错误,这里推荐生产环境下使用还当前系统一直的centos,如果只是测试相关软件和功能,可以使用Alpine。注意,在使用Alpine作为基础镜像安装JDK时,需要手工安装glibc
2:合理使用镜像的层级。 这里一个最明显的使用就是:所有的RUN指令一个放在同一层,避免镜像中使用多个RUN指令。同时,如果使用RUN 指令来yum软件,yum完成后需要清除缓存
3:合理使用dockeringore: 我们在执行docker build 时,会将构建上下文目录下所有的文件递归打包发送给docker server,如果构建上下文目录中有较多无用文件时,会明显拖慢构建速度(这个地方虽然不会影响镜像大小,但是会影响速度)。 这时,我们需要在构建上下文目录中创建.dockeringore文件,来过滤掉不需要的文件(ADD或者COPY指令的源文件不能再dockeringore文件中)。
4:合理调整指令的顺序: 通常,ADD或者COPY指令应当位于RUN指令之后,ENV应该位于CMD指令之前,ADD指令之后,CMD位于最后。详细可见上文中的示例。(已上文的JDK镜像为例,如果我们将ADD指令放在RUN之前,docker build构建出镜像后,会发现比之前的大许多)
5:分阶段构建: DOCKERFILE的分阶段构建更多的适用于构建之后可以直接运行的二进制文件,如 C,GO写出的代码,结合我们的java程序,个人理解并不适用。但是可以想象一个场景,我们在一个镜像中完成 拉代码+mvn打包+运行jar包所有的操作,如果我们不使用分阶段构建的话,在一个镜像中需要安装jdk+mvn+git,这样就会使镜像变得非常庞大。这时候如果使用分阶段构建的话,可以在第一阶段使用git+mvn拉取代码并打包生成jar包,在第二阶段使用--from关键字来直接拷贝出上一阶段打出的jar包,这样实际运行处的镜像就会小很多。 具体用法可以网上查找资料自行了解下。
6: 使用dive工具分析镜像的各层级: https://github.com/wagoodman/dive

四: docker build时的上下文目录:

docker build -f access-gateway-docker-file -t access-gaeway:v1 /home/ubuntu/target  其中,/home/ubuntu/target就是docker build时的上下文目录。

在实行docker build时 显示的  Sending build context to Docker daemon    115MB   就是上文中说的 将构建上下文目录下所有的文件递归打包发送给docker server 的文件大小

你可能感兴趣的:(01_DOCKERFILE语法简述和示例)