DockerFile 编译语法详解

Posted lyshark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DockerFile 编译语法详解相关的知识,希望对你有一定的参考价值。


title: DockerFile 编译语法详解(5)
date: 2018-12-16 16:53:20
tags:

  • Docker
    categories: Docker
    copyright: true
    ---

Docker是基于Go语言实现的开源容器项目,Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口,Docker诞生于2013年年初,最初发起者是dotCloud公司.Docker自开源后受到广泛的关注和讨论,目前已有多个相关项目(包括Docker三剑客、Kubernetes等),逐渐形成了围绕Docker容器的生态体系,由于Docker在业界造成的影响力实在太大,dotCloud公司后来也直接改名为Docker Inc,并专注于Docker相关技术和产品的开发.

Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像,本小结首先介绍Dockerfile典型的基本结构和它支持的众多指令,并具体讲解通过这些指令来编写定制镜像的Dockerfile,以及如何生成镜像.最后介绍使用Dockerfile的一些最佳实践经验.

DockerFile基本结构

Dockerfile由一行行命令语句组成,并且支持以#开头的注释行,一般而言,Dockerfile分为四部分.基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令.例如下面的一个小例子.

# This Dockerfile uses the ubuntu image

FROM ubuntu:lastest
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user [email protected]
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx

其中,一开始必须指明所基于的镜像名称,接下来一般是说明维护者信息.后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令.每运行一条RUN指令,镜像就添加新的一层,并提交.最后是CMD指令,用来指定运行容器时的操作命令.

实例1:debian:latest基础镜像基础上安装Nginx环境,从而创建一个新的nginx镜像.

FROM debian:latest
MAINTAINER NGINX Docker Maintainers "[email protected]"
ENV NGINX_VERSION 1.10.1-1~jessie
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC64107
9A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/debian/ jessie nginx" >> /etc/
apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

实例2: 基于buildpack-deps:latest基础镜像,安装Golang相关环境,制作一个GO语言的运行环境镜像.

FROM buildpack-deps:lastest
# gcc for cgo
RUN apt-get update && apt-get install -y --no-install-recommends g++ gcc libc6-dev make && rm -rf /var/lib/apt/lists/*
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd
7561275a87aeb
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && tar -C /usr/local -xzf golang.tar.gz && rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/


DockerFile命令详解

指令的一般格式为INSTRUCTION arguments指令包括FROM、MAINTAINER、RUN等,参见下表.

指 令 指 令 说 明
FROM 创建镜像的基础镜像
MAINTAINER 维护者信息(说明)
RUN 运行命令,安装软件用
CMD 启动容器时默认执行的命令
LABEL 指生成镜像的元数据标签信息
EXPOSE 声明镜像内服务所监听的端口
ENV 声明环境变量
ADD 复制指令,将拷贝到容器中的
COPY(推荐) 复制指令,将拷贝到容器中的
ENTRYPOINT 指定镜像的默认入口
VOLUME 创建数据卷挂载点
USER 指定运行容器时的用户名或UID
WORKDIR 配置工作目录
ARG 指定镜像内使用的参数
ONBUILD 配置当所创建镜像作为其他镜像基础时,所执行的命令
STOPSIGNAL 容器退出的信号值
HEALTHCHECK 如何进行健康检查
SHELL 指定使用SHELL时的默认shell类型

接下来,我将详细介绍几个常用命令的参数的详细说明信息.

FROM:(指定基础镜像的名称)

构建指令,必须指定且需要在Dockerfile其他指令的前面.后续的指令都依赖于该指令指定的image,FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库.

example:
    FROM centos:latest
    FROM ubuntu:14.04

MAINTAINER:(指定镜像创建者信息)

构建指令,用于将image的制作者相关的信息写入到image中,当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息.

example:
    MAINTAINER  LyShark "www.mkdirs.com"

RUN:(运行命令,安装软件用)

RUN指令是用来执行命令行命令的,由于命令行的强大能力,RUN指令在定制镜像时是最常用的指令之一.

设置指令,用于container启动时指定的操作.该操作可以是执行自定义脚本,也可以是执行系统命令.该指令只能在文件中存在一次,如果有多个,则只执行最后一条.

FROM centos:latest
    RUN yum install -y gcc libc6-dev make
    RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
    RUN mkdir -p /usr/src/redis
    RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
    RUN make -C /usr/src/redis
    RUN make -C /usr/src/redis install

Dockerfile 中每一个指令都会建立一层,RUN也不例外.每一个RUN的行为,就和刚才我们手工建立镜像的过程一样,新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像.

而上面的这种写法,创建了 6 层镜像.这是完全没有意义的,不仅仅增加了构建部署的时间,也很容易出错,这是很多初学 Docker 的人常犯的一个错误,Union FS 是有最大层数限制的,比如 AUFS曾经是最大不得超过 42 层,现在是不得超过127 层.

上面的 Dockerfile 正确的写法应该是这样:

FROM centos:latest
RUN buildDeps='gcc libc6-dev make'     && apt-get install -y $buildDeps     && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"     && mkdir -p /usr/src/redis     && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1     && make -C /usr/src/redis     && make -C /usr/src/redis install     && rm -rf /var/lib/apt/lists/*     && rm redis.tar.gz     && rm -r /usr/src/redis     && apt-get purge -y --auto-remove $buildDeps

CMD:(设置容器启动时执行的操作)

设置指令,用于容器启动时指定的操作,该操作可以是执行自定义脚本,也可以是执行系统命令,该指令只能在文件中存在一次,如果有多个,则只执行最后一条.

example:
    CMD echo "Hello, World!"

ENTRYPOINT:(设置容器启动时执行的操作)

设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效.

example:
    ENTRYPOINT ls -l 

该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用.当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效.如下命令:CMD指令将不会被执行,只有ENTRYPOINT指令被执行

example:
    CMD echo "Hello, World!" 
    ENTRYPOINT ls -l  

另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分:ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数.

example:
    FROM centos:latest
    CMD ["-l"]  
    ENTRYPOINT ["/usr/bin/ls"]  

USER:(设置container容器的用户)

设置指令,设置启动容器的用户,默认是root用户.或者说以那个身份的用户运行容器,如下所示运行memcached,并以daemon用户运行.

example:
    USER daemon  =  ENTRYPOINT ["memcached", "-u", "daemon"]  

EXPOSE:(指定容器需要映射到宿主机器的端口)

设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口.当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口.要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号.也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用.EXPOSE指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用-p选项.

example:
    映射一个端口
    EXPOSE 22
    相应的运行容器使用的命令
    docker run -p port1 image
  
    映射多个端口
    EXPOSE port1 port2 port3
    相应的运行容器使用的命令
    docker run -p port1 -p port2 -p port3 image

    还可以指定需要映射到宿主机器上的某个端口号
    docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image

ENV:(用于设置环境变量)

构建指令,在image中设置一个环境变量.设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量.假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:

example:
    ENV JAVA_HOME /path/to/java/dirent

ADD:(从src复制文件到容器的dest路径)

example:    
    ADD <src> <dest>  
        <src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url
        <dest> 是容器中的绝对路径

COPY:(从src复制文件到容器的dest路径)

example:    
    COPY <src> <dest>

VOLUME:(指定挂载点)

设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用.我们知道容器使用的是AUFS这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失.当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令.

examp:  
    FROM base  
    VOLUME ["/tmp/data"]

WORKDIR:(切换目录)

设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效.

example:
    WORKDIR /p1 WORKDIR p2 RUN vim a.txt

ONBUILD:(在子镜像中执行)

ONBUILD指定的命令在构建镜像时并不执行,而是在它的子镜像中执行.

example:    
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src

好了关于编译命令还有很多,这里就不一一列举了,更多指令操作语法请自行百度,下面我们来看使用DockerFile编译构建一些好玩的东西吧,相信看完下面的小例子,你就能丰衣足食了.

构建Apache镜像

Apache是一个高稳定性的、商业级别的开源Web服务器.目前Apache已经是世界使用排名第一的Web服务器软件,由于其良好的跨平台和安全性,Apache被广泛应用在多种平台和操作系统上.作为Apache软件基金会支持的项目,它的开发者社区完善而高效.自1995年发布至今,一直以高标准进行维护与开发.Apache名称源自美国的西南部一个印第安人部落:阿帕奇族,它支持类UNIX和Windows系统.

1.首先我们要解决Docker容器内不得网络问题.修改DockerDNS,默认没有文件自行创建即可.

[[email protected] ~]# vim /etc/default/docker

docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114"

[[email protected] ~]# systemctl restart docker

2.接着在当前目录创建一个Dockerfile文件,和一个index.html文件,文件内容如下.

[[email protected] ~]# vim DockerFile

FROM centos:latest
MAINTAINER [email protected]

RUN yum install -y -q apr apr-util httpd
COPY ./index.html /var/www/html/

EXPOSE 80
ENTRYPOINT apachectl start && tail -f /var/log/httpd/access_log

3.使用docker build命令创建centos:httpd镜像,注意命令最后的"."表示当前目录.

[[email protected] ~]# docker build -t centos:httpd .

Sending build context to Docker daemon  18.94kB
Step 1/6 : FROM centos:latest
....省略....
Successfully built 65d0de3819df
Successfully tagged centos:httpd

4.下面开始使用run指令测试镜像,可以使用-P参数映射需要开放的端口(22和80端口)

[[email protected] ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              httpd               65d0de3819df        36 seconds ago      305MB
centos              latest              1e1148e4cc2c        11 days ago         202MB

[[email protected] ~]# docker run -itd -p 80:80 centos:httpd


构建Nginx镜像

Nginx是一款功能强大的开源反向代理服务器,支持HTTP、HTTPS、SMTP、POP3、IMAP等协议.它也可以作为负载均衡器、HTTP缓存或Web服务器.Nginx一开始就专注于高并发和高性能的应用场景,它使用类BSD开源协议,支持Linux、BSD、Mac、Solaris、AIX等类Unix系统,同时也有Windows上的移植版本.

1.首先我们要解决Docker容器内不得网络问题.修改DockerDNS,默认没有文件自行创建即可.

[[email protected] ~]# vim /etc/default/docker

docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114"

[[email protected] ~]# systemctl restart docker

2.接着在当前目录创建一个Dockerfile文件,和一个index.html文件,文件内容如下.

[[email protected] ~]# vim DockerFile

FROM centos:latest
MAINTAINER [email protected]

RUN yum install -y epel-release
RUN yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
RUN rpm -i http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum install -y nginx

EXPOSE 80
ENTRYPOINT nginx && tail -f /var/log/nginx/access.log   #tail必须加,否则容器瞬间终止

3.开始通过dockerfile编译生成nginx:centos镜像文件.

[[email protected] ~]# docker build -t nginx:centos .

Sending build context to Docker daemon  18.43kB
Step 1/8 : FROM centos:latest
....省略....
Successfully built 956a361043bc
Successfully tagged nginx:centos

4.查看生成的镜像文件,并运行这个镜像测试一下吧.
```BASH
[[email protected] ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx centos 956a361043bc About a minute ago 591MB
centos latest 1e1148e4cc2c 11 days ago 202MB

[[email protected] ~]# docker run --name nginx -p 80:80 -d nginx:centos
[[email protected] ~]# curl 127.0.0.1
```

构建Tomcat镜像

Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和Java Server Page(JSP)的支持.同时,它提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等.由于Tomcat本身也内含了一个HTTP服务器,也可以当作一个单独的Web服务器来使用.下面介绍如何定制Tomcat镜像.

1.首先准备好原材料,Tomcat,jdk环境.

[[email protected] ~]# ls -lh
total 100M
-rw-r--r-- 1 root root  92M Dec 16 23:21 jdk.tar.gz
-rw-r--r-- 1 root root 7.6M Dec 16 23:21 tomcat.tar.gz

2.编写这个构建模板文件,如下内容.

[[email protected] ~]# vim Dockerfile

FROM centos:latest
MAINTAINER [email protected]

ADD ./tomcat.tar.gz /root
ADD ./jdk.tar.gz /root

ENV JAVA_HOME /root/jdk1.7.0_25
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 8080

ENTRYPOINT /root/apache-tomcat-7.0.42/bin/startup.sh && tail -F /root/apache-tomcat-7.0.42/logs/catalina.out

3.使用docker build命令创建centos:tomcat镜像,注意命令最后的"."表示当前目录.

[[email protected] ~]# docker build -t centos:tomcat .
Sending build context to Docker daemon  104.3MB
Step 1/8 : FROM centos:lastest
....省略....
Successfully built feac1f1c6ed4
Successfully tagged centos:tomcat

[[email protected] ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              tomcat              65d0de3819df        36 seconds ago      405MB
centos              latest              1e1148e4cc2c        11 days ago         202MB

4.下面开始使用run指令测试镜像,可以使用-P参数映射需要开放的端口(22和80端口)

[[email protected] ~]# docker run --name tomcat -p 80:8080 -d centos:tomcat
[[email protected] ~]# curl 127.0.0.1:80
[[email protected] ~]# docker save 镜像ID > /home/xxx.tar


以上是关于DockerFile 编译语法详解的主要内容,如果未能解决你的问题,请参考以下文章

dockerfile详解文件指令详解

dockerfile详解文件指令详解

Dockerfile语法自定义镜像构建详解

Dockerfile指令详解

20160203.CCPP体系详解(0013天)

Notepad++编辑器——Verilog代码片段直接编译