title: DockerFile 编译语法详解(5)
date: 2018-12-16 16:53:20
tags:html
Docker是基于Go语言实现的开源容器项目,Docker让开发者能够打包他们的应用以及依赖包到一个可移植的容器中,而后发布到任何流行的 Linux 机器上,也能够实现虚拟化.容器是彻底使用沙箱机制,相互之间不会有任何接口,Docker诞生于2013年年初,最初发起者是dotCloud公司.Docker自开源后受到普遍的关注和讨论,目前已有多个相关项目(包括Docker三剑客、Kubernetes等),逐渐造成了围绕Docker容器的生态体系,因为Docker在业界形成的影响力实在太大,dotCloud公司后来也直接更名为Docker Inc,并专一于Docker相关技术和产品的开发.java
Dockerfile是一个文本格式的配置文件,用户可使用Dockerfile来快速建立自定义的镜像,本小结首先介绍Dockerfile典型的基本结构和它支持的众多指令,并具体讲解经过这些指令来编写定制镜像的Dockerfile,以及如何生成镜像.最后介绍使用Dockerfile的一些最佳实践经验.
python
Dockerfile由一行行命令语句组成,而且支持以#开头的注释行,通常而言,Dockerfile分为四部分.基础镜像信息、维护者信息、镜像操做指令和容器启动时执行指令.例以下面的一个小例子.linux
# This Dockerfile uses the ubuntu image FROM ubuntu:lastest # Maintainer: docker_user <docker_user at email.com> (@docker_user) MAINTAINER docker_user docker_user@email.com # 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指令,用来指定运行容器时的操做命令.nginx
实例1: 在debian:latest
基础镜像基础上安装Nginx环境,从而建立一个新的nginx镜像.golang
FROM debian:latest MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com" 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语言的运行环境镜像.redis
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/
指令的通常格式为INSTRUCTION arguments
指令包括FROM、MAINTAINER、RUN等,参见下表.docker
指 令 | 指 令 说 明 |
---|---|
FROM | 建立镜像的基础镜像 |
MAINTAINER | 维护者信息(说明) |
RUN | 运行命令,安装软件用 |
CMD | 启动容器时默认执行的命令 |
LABEL | 指生成镜像的元数据标签信息 |
EXPOSE | 声明镜像内服务所监听的端口 |
ENV | 声明环境变量 |
ADD | 复制指令,将
|
COPY(推荐) | 复制指令,将
|
ENTRYPOINT | 指定镜像的默认入口 |
VOLUME | 建立数据卷挂载点 |
USER | 指定运行容器时的用户名或UID |
WORKDIR | 配置工做目录 |
ARG | 指定镜像内使用的参数 |
ONBUILD | 配置当所建立镜像做为其余镜像基础时,所执行的命令 |
STOPSIGNAL | 容器退出的信号值 |
HEALTHCHECK | 如何进行健康检查 |
SHELL | 指定使用SHELL时的默认shell类型 |
接下来,我将详细介绍几个经常使用命令的参数的详细说明信息.shell
FROM:(指定基础镜像的名称)apache
构建指令,必须指定且须要在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是一个高稳定性的、商业级别的开源Web服务器.目前Apache已是世界使用排名第一的Web服务器软件,因为其良好的跨平台和安全性,Apache被普遍应用在多种平台和操做系统上.做为Apache软件基金会支持的项目,它的开发者社区完善而高效.自1995年发布至今,一直以高标准进行维护与开发.Apache名称源自美国的西南部一个印第安人部落:阿帕奇族,它支持类UNIX和Windows系统.
1.首先咱们要解决Docker容器内不得网络问题.修改DockerDNS,默认没有文件自行建立便可.
[root@localhost ~]# vim /etc/default/docker docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114" [root@localhost ~]# systemctl restart docker
2.接着在当前目录建立一个Dockerfile文件,和一个index.html文件,文件内容以下.
[root@localhost ~]# vim DockerFile FROM centos:latest MAINTAINER email@email.com 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
镜像,注意命令最后的"."表示当前目录.
[root@localhost ~]# 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端口)
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos httpd 65d0de3819df 36 seconds ago 305MB centos latest 1e1148e4cc2c 11 days ago 202MB [root@localhost ~]# docker run -itd -p 80:80 centos:httpd
Nginx是一款功能强大的开源反向代理服务器,支持HTTP、HTTPS、SMTP、POP三、IMAP等协议.它也能够做为负载均衡器、HTTP缓存或Web服务器.Nginx一开始就专一于高并发和高性能的应用场景,它使用类BSD开源协议,支持Linux、BSD、Mac、Solaris、AIX等类Unix系统,同时也有Windows上的移植版本.
1.首先咱们要解决Docker容器内不得网络问题.修改DockerDNS,默认没有文件自行建立便可.
[root@localhost ~]# vim /etc/default/docker docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114" [root@localhost ~]# systemctl restart docker
2.接着在当前目录建立一个Dockerfile文件,和一个index.html文件,文件内容以下.
[root@localhost ~]# vim DockerFile FROM centos:latest MAINTAINER email@email.com 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
镜像文件.
[root@localhost ~]# 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.查看生成的镜像文件,并运行这个镜像测试一下吧.
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx centos 956a361043bc About a minute ago 591MB centos latest 1e1148e4cc2c 11 days ago 202MB [root@localhost ~]# docker run --name nginx -p 80:80 -d nginx:centos [root@localhost ~]# curl 127.0.0.1
Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和Java Server Page(JSP)的支持.同时,它提供了做为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等.因为Tomcat自己也内含了一个HTTP服务器,也能够看成一个单独的Web服务器来使用.下面介绍如何定制Tomcat镜像.
1.首先准备好原材料,Tomcat,jdk环境.
[root@localhost ~]# 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.编写这个构建模板文件,以下内容.
[root@localhost ~]# vim Dockerfile FROM centos:latest MAINTAINER email@email.com 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
镜像,注意命令最后的"."表示当前目录.
[root@localhost ~]# 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 [root@localhost ~]# 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端口)
[root@localhost ~]# docker run --name tomcat -p 80:8080 -d centos:tomcat [root@localhost ~]# curl 127.0.0.1:80 [root@localhost ~]# docker save 镜像ID > /home/xxx.tar