Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令可以根据Dockerfile里面的指令编排来打包定制我们自己的docker镜像,首先我们来看一个通用的例子,制作自己的nginx镜像。
1.构建nginx镜像
# Base image
FROM centos:7
# MAINTAINER
MAINTAINER cbmiao <miaocbin@126.com>
# 将nginx以及pcre源代码加入镜像
ADD nginx-1.20.1.tar.gz /usr/local/src/
ADD pcre-8.45.tar.gz /usr/local/src/
# 安装编译器
RUN yum install -y gcc gcc-c++ make openssl-devel lsof
RUN useradd -s /sbin/nologin -M nginx
# 指定工作目录
WORKDIR /usr/local/src/nginx-1.20.1/
# 编译nginx
RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
# 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
# 暴露80端口
EXPOSE 80
# 容器默认启动命令
ENTRYPOINT ["nginx"]
以上是通过Dockerfile来定制我们自己的nginx的Dockerfile,包含了如下指令:
2. Dockerfile基本格式
2.1 FROM指令
FROM指令用于指定基础镜像,必须为Dockerfile的第一个指令
格式:
FROM <image>
FROM <image>:<tag>
示例:
FROM mysql:5.7
注意:
tag是可选的,如果不使用tag,则默认会使用latest版本的基础镜像
参数解释:
-
FROM mysql:5.7:第一行必须指定 基础镜像信息
2.2 MAINTAINER 指令
用于说明镜像维护者的信息,名字,邮箱,联系方式,实例如下
格式:
MAINTAINER <name>
示例:
MAINTAINER Michael Miu
MAINTAINER miaocbin@126.com
MAINTAINER Michael Miu <miaocbin@126.com>
2.3 COPY|ADD指令
这两个命令的用法类似,都可以用于添加本地文件到镜像中,如:
- 源路径可以有多个,相对于执行build的路径,如果源路径是一个目录,则该目录下面的所有内容都会被加入到容器,但目录本身不会被加入到容器;
- 目标路径:必须是绝对路径或者相对于WORKDIR的相对路径;若目标路径不存在,则会自动创建完整路径;目标路径如果是文件夹,则必须已/结尾;
- 路径中可以使用通配符
二者区别如下:
- COPY指令能够将构建命令所在的主机本地的文件或目录,复制到镜像文件系统。
- ADD指令不仅能够将构建命令所在的主机本地的文件或目录,而且能够将远程URL所对应的文件或目录,作为资源复制到镜像文件系统。
所以,可以认为ADD是增强版的COPY,支持将远程URL的资源加入到镜像的文件系统。
格式:
ADD|COPY <src>... <dest>
示例:
ADD|COPY tes* /mydir/ # 添加所有以"tes"开头的文件
ADD|COPY test mydir/ # 添加 "test" 到 WORKDIR/mydir/
ADD|COPY test /opt/ # 添加 "test" 到 /opt/
说明:
- 对于从远程URL获取资源的情况,由于ADD指令不支持认证,如果从远程获取资源需要认证,则只能使用RUN wget或RUN curl替代。
- 如果源路径的资源发生变化,则该ADD指令将使Docker Cache失效,Dockerfile中后续的所有指令都不能使用缓存。因此尽量将ADD指令放在Dockerfile的后面。
2.4 WORKDIR
设置工作目录,通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行
格式:
WORKDIR /path/to/workdir
示例:
WORKDIR /abc (这时工作目录为/abc)
2.5 RUN
构建镜像过程中执行命令(注意:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache)
格式:
RUN <command>
示例:
RUN yum -y install nginx
RUN pip install djaong
RUN mkdir test && rm -rf /var/lib/testfile
2.6 CMD
构建容器后调用,也就是在容器启动时才进行调用。注意:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD ["/usr/bin/wc","--help"]
CMD ping www.baidu.com
2.7 ENTRYPOINT
设置容器初始化命令,使其可执行化
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
ENTRYPOINT ["/usr/bin/wc","--help"]
注意:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
2.8 ENV
格式:
ENV <key> <value>
ENV <key>=<value>
示例:
ENV myName John
ENV myCat=tomcat
2.9 EXPOSE
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
3. Dockerfile镜像构建命令
利用Dockerfile构建自己的镜像命令
docker build . -t ImageName:ImageTag -f Dockerfile
3.1 执行构建过程
docker build . -t my-nginx:v1.20.1 -f Dockerfile
Sending build context to Docker daemon 3.163MB
Step 1/13 : FROM centos:7
---> 8652b9f0cb4c
Step 2/13 : LABEL maintainer="cbmiao <miaocbin@126.com>"
---> Using cache
---> 16c2487146bc
Step 3/13 : ENV DEBIAN_FRONTEND noninteractive
---> Using cache
---> 5f3132177398
Step 4/13 : ADD nginx-1.20.1.tar.gz /usr/local/src/
---> Using cache
---> 116344a28ea2
Step 5/13 : ADD pcre-8.45.tar.gz /usr/local/src
---> Using cache
---> 23451b87c29b
Step 6/13 : RUN yum install -y wget gcc gcc-c++ make openssl-devel
---> Using cache
---> dcaa1cbaf4bd
Step 7/13 : RUN useradd -s /sbin/nologin -M nginx
---> Using cache
---> e0ace7f20ffc
Step 8/13 : WORKDIR /usr/local/src/nginx-1.20.1/
---> Using cache
---> d437722febe2
Step 9/13 : RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
---> Using cache
---> 307b6228d110
Step 10/13 : RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
---> Using cache
---> dc8e0e800987
Step 11/13 : ENV PATH /usr/local/nginx/sbin:$PATH
---> Using cache
---> e5a1119dced2
Step 12/13 : EXPOSE 80
---> Using cache
---> 63c669be20e4
Step 13/13 : ENTRYPOINT ["nginx"]
---> Using cache
---> 391f75b825bd
Successfully built 391f75b825bd
Successfully tagged my-nginx:v1.20.1
3.2 查看构建结果
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx v1.20.1 391f75b825bd 17 minutes ago 490MB
3.3 运行镜像
# 利用我们刚构建的镜像来启动容器
docker run -d --name nginx-test my-nginx:v1.20.1
348a73f420181c36abf7a99c958ed76862503e930793331ab819629ea2bdc4a2
# 进入容器查看nginx状态
docker exec -ti nginx-test bash
[root@348a73f42018 nginx-1.20.1]#
# 确认80端口
[root@348a73f42018 nginx-1.20.1]# lsof -i :80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1 root 6u IPv4 645923 0t0 TCP *:http (LISTEN)
# 确认nginx进程已经启动成功
[root@348a73f42018 nginx-1.20.1]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 46096 3280 ? Ss 05:43 0:00 nginx: master process nginx
nginx 7 0.0 0.0 46532 1880 ? S 05:43 0:00 nginx: worker process
root 8 0.2 0.0 11828 1908 pts/0 Ss 05:43 0:00 bash
root 26 0.0 0.0 51732 1712 pts/0 R+ 05:43 0:00 ps aux
# 访问nginx也正常
[root@348a73f42018 nginx-1.20.1]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
若想让我们的nginx向外提供服务,还需要在启动容器时,将端口映射到主机,然后我们通过主机IP加上映射端口,就可以访问了
docker run -d --name nginx-test1 -p 80:80 my-nginx:v1.20.1
以上就添加了一个[-p 80:80]参数,将容器内的nginx的80端口,映射到宿主机。然后我们就可以通过宿主机的IP加上80端口访问刚才启动的nginx容器里的nginx服务,有关docker启动容器有不清楚的,可以看我的另外一篇博客:Docker简介及基本使用
4. Dockerfile构建镜像的原则
-
不必要的内容不要放在镜像中:以免增大镜像,同时也带来安全隐患;
-
减少不必要的层文件
-
减少网络传输操作:尽量使用本地文件,加快镜像构建速度,特别是后面我们将利用Jenkins做自动化构建的时候;
-
可以适当的包含一些调试命令
5. JAR包制作成docker镜像实例
FROM java:8u211
ENV JAVA_OPTS "-Xmx4096m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m"
ENV JAVA_HOME /usr/local/java
ENV PATH ${PATH}:${JAVA_HOME}/bin
COPY target/myweb.jar myweb.jar
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo ‘Asia/Shanghai‘ >/etc/timezone
EXPOSE 8080
CMD java ${JAVA_OPTS} -jar myweb.jar