1 Dockerfile介绍
前面的docker镜像管理章节有说到,构建镜像的方式有两种:
- 一种是基于容器制作
- 另一种就是通过Dockerfile。Dockerfile其实就是我们用来构建Docker镜像的源码,当然这不是所谓的编程源码,而是一些命令的组合,只要理解它的逻辑和语法格式,就可以编写Dockerfile了。
简要概括Dockerfile的作用:它可以让用户个性化定制Docker镜像。因为工作环境中的需求各式各样,网络上的镜像很难满足实际的需求。
2 基本结构
-
Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。 -
Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。 -
Dockerfile整体就两类语句组成
- Comment 注释信息
- Instruction arguments 指令 参数,一行一个指令
- Dockerfile文件名首字母必须大写。
- Dockerfile指令不区分大小写,但是为方便和参数做区分,通常指令使用大写字母。
-
Dockerfile中指令按顺序从上至下依次执行。 -
Dockerfile中第一个非注释行必须是FROM指令,用来指定制作当前镜像依据的是哪个基础镜像。 -
Dockerfile中需要调用的文件必须跟Dockerfile文件在同一目录下,或者在其子目录下,父目录或者其它路径无效。
2.1 Dockerfile分为四部分
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时默认要执行的指令
3 Dockerfile 基础知识
指令的一般格式为INSTRUCTION arguments ,指令包括:
FROM #基础镜像,一切从这里开始构建
MAINTAINER #镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD #步骤,tomcat镜像,这个tomcat的压缩包!添加内容
WORKDIR #镜像的工作目录
VOLUME #挂载的目录
EXPOSE #暴露端口配置
CMD #指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令
COPY #类似ADD,将我们文件拷贝到镜像中
ENV #构建的时候设置环境遍量
//示例
#第一行必须指定基于的基础镜像
FROM centos
#维护人的信息
LABEL MAINTAINER="CWT <161774597@qq.com>"
#安装httpd软件包
RUN yum -y update && \
yum -y install httpd
#开启80端口
EXPOSE 80
#复制网站首页文件至镜像中web站点下
ADD index.html /var/www/html/index.html
#复制该脚本至镜像中,并修改其权限
ADD httpd.sh /httpd.sh
RUN chmod 775 /httpd.sh
#当启动容器时默认要执行的动作
CMD ["/httpd.sh"]
其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。 后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。 最后是CMD指令来指定运行容器时的操作指令。
4 Dockerfile常用指令
4.1 FROM
第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)
//语法格式:FROM <image>或FROM <imagge>:<tag>
//构建新镜像是基于那个镜像
FROM centos:7
4.2 LABEL MAINTAINER
指定维护者信息
//语法格式: MAINTAINER <name email_address>
LABEL MAINTAINER='1@126.com'
4.3 RUN
RUN指令将对镜像执行跟随的命令
//RUN指令的语法格式有两种:
shell格式:(默认用/bin/sh -c来执行)
RUN <command> RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec格式:
RUN ["executable","param1","param2"] RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意: 每运行一条RUN指令,镜像添加新的一层,并提交,所以过多无意义的层,会造成镜像膨胀过大。所以当命令较长时可以使用 \ 来换行
RUN echo "hello world\nhello tom" > /tmp/abc && \
cat /tmp/abc
4.4 CMD
- 指定启动容器时默认执行的命令,即:如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么就会使用执行CMD指定的默认的命令
- 每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行
- 如果用户启动容器时指定了运行的命令,如:docker run xxx /bin/bash,则/bin/bash 会覆盖 CMD 指定的命令
//语法格式:
CMD ["executable","param1","param2"]使用exec执行,推荐方式
CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用
CMD ["param1","param2"]提供给ENTRYPOINT的默认参数
例如:CMD ["nginx", "-g", "daemon off;"]
4.5 EXPOSE
EXPOSE用于告诉Docker服务器容器暴露的端口号,供互联系统使用。 在启动容器时通过-P,Docker主机会自动分配一个端口转发到指定的端口,使用-p则可以具体指定哪个本地端口映射过来
//语法格式:EXPOSE <port> [<port>...]
例如:EXPOSE 80 443 22
4.6 ENV
指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持
//语法格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
例如:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
4.7 COPY
- 复制本地主机的(为Dockerfile所在目录的相对路径,文件或目录)为容器中的。目标路径不存在时会自动创建
- 使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
- 如果是目录,只复制目录内容,而非目录本身
//语法格式:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
4.8 ADD
-
该命令将复制指定的到容器中的。其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(会自动解压为目录) -
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
-
如果src是目录,只复制目录中的内容,而非目录本身 -
如果src是一个 URL ,下载后的文件权限自动设置为 600
//语法格式:
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
例如:
ADD test /absoluteDir/
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz
4.9 ENTRYPOINT
- 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,如果在docker run的后面提供了参数会被当作参数传递给 ENTRYPOINT 指令指定的程序。
- 每个Dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。
- 但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
//语法格式:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2(在shell中执行)
例如:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
运行容器:docker run nginx:test #没有传参
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
docker run nginx:test -c /etc/nginx/new.conf #传参
容器内会默认运行以下命令
nginx -c /etc/nginx/new.conf
4.10 VOLUME
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
//语法格式:
VOLUME ["<容器内路径1>", "<容器内路径2>"...]
VOLUME <路径>
//例如
VOLUME /data
4.11 USER
- 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户
- 这个用户必须是事先建立好的,否则无法切换
- 要临时获取管理员权限可以使用 gosu,而不推荐 sudo
- 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
//语法格式:
USER <user>[:<group>]
USER <UID>[:<GID>]
例如:
RUN groupadd -r mysql && useradd -r -g mysql mysql
USER mysql
4.12 WORKDIR
-
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。 -
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。 -
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
//语法格式:
WORKDIR <工作目录路径>
例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
最终路径为/a/b/c
4.13 ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
//语法格式:ONBUILD [INSTRUCTION]
例如,Dockerfile使用如下的内容创建了镜像test-build
[...]
ONBUILD ADD nginx.conf /usr/local/nignx/nginx.conf
ONBUILD RUN mkdir /data
[...]
此时,如果基于test-build创建新的镜像时,新的Dockerfile中使用FROM test-build指定基础镜像时,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令。
FROM test-build
# Automatically run the following
ADD nginx.conf /usr/local/nignx/nginx.conf
RUN mkdir /data
5 构建镜像注意事项
-
编写完成Dockerfile后,可以通过docker build命令来创建镜像。 -
基本的格式为docker build [选项] 路径,该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有内容发送给Docker服务端,由服务端来创建镜像。因此一般建议放置Dockerfile的目录为空目录。 -
另外,可以通过 .dockerignore 文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。 -
要指定镜像的标签信息,可以通过-t选项。 -
例如,指定Dockerfile所在路径为/tmp/docker_builder/,并且希望生成镜像标签为build_repo/first_image,可以使用下面的命令
docker build -t build_repo/first_image /tmp/docker_builder/
6 使用Dockerfile构建apache镜像
//创建目录
[root@docker ~]# ls
anaconda-ks.cfg
[root@docker ~]# mkdir /apache
[root@Docker ~]# cd /apache/
[root@Docker apache]# touch Dockerfile
[root@Docker apache]# ls
Dockerfile
[root@Docker apache]# mkdir packages
[root@Docker apache]# cd packages/
[root@Docker packages]# mv /usr/src/apr-1.7.0.tar.gz .
[root@Docker packages]# mv /usr/src/apr-util-1.6.1.tar.gz .
[root@Docker packages]# mv /usr/src/httpd-2.4.48.tar.gz .
[root@Docker ~]# tree
.
├── anaconda-ks.cfg
└── apache
├── Dockerfile
└── packages
├── apr-1.7.0.tar.gz
├── apr-util-1.6.1.tar.gz
└── httpd-2.4.48.tar.gz
/编写dockerfile
[root@Docker ~]# cat apache/Dockerfile
[root@docker apache]# cat Dockerfile
# 第一行必须指定基于的基础镜像
FROM centos
# 维护者信息
LABEL MAINIAINER='123@qq.com'
# 将源码包传到指定文件,并会自动解压
ADD packages/* /usr/src/
# 切换到当前所在目录
WORKDIR /usr/src/
# 镜像操作指令
# 下载所需的安装包
RUN yum -y install openssl-devel pcre-devel pcre expat-devel libtool gcc gcc-c++ make && \
# 编译安装apr
cd apr-1.7.0 && sed -i '/$RM "$cfgfile"/d' configure && \
./configure --prefix=/usr/local/apr && make && make install && \
# 编译安装apr-util
cd ../apr-util-1.6.1 && \
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && \
make && make install && \
# 编译安装httpd
cd ../httpd-2.4.48 && \
./configure --prefix=/usr/local/apache \
--enable-so \
--enable-ssl \
--enable-cgi \
--enable-rewrite \
--with-zlib \
--with-pcre \
--with-apr=/usr/local/apr \
--with-apr-util=/usr/local/apr-util/ \
--enable-modules=most \
--enable-mpms-shared=all \
--with-mpm=prefork && \
make && make install
sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf
#设置存储卷
VOLUME ["/usr/local/apache/htdocs/"]
#启动命令
CMD ["/usr/local/apache/bin/apachectl","-D","FOREGROUND"]
//创建镜像
[root@Docker ~]# docker build -t caiaoc/apache:v1.0 /apache/
[root@docker apache]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
caiaoc/apache v1.0 b1386d62fb74 2 hours ago 701MB
nginx latest f652ca386ed1 5 days ago 141MB
busybox latest d23834f29b38 7 days ago 1.24MB
httpd latest ad17c88403e2 2 weeks ago 143MB
centos latest 5d0da3dc9764 2 months ago 231MB
//使用刚刚创建的镜像启动容器,开放端口,创建容器
[root@docker apache]# docker run --name apache1 -itd -p 80:80 caiaoc/apache:v1.0
7e6e7a2bc6b460eba55d55a61acdf89ac8d9e316ffa73ca0e541fddf378d9791
[root@docker apache]# docker exec -it apache1 /bin/bash
[root@7e6e7a2bc6b4 src]# ss -antl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
通过网页访问测试
|