Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令可以根据Dockerfile里面的指令编排来打包定制我们自己的docker镜像,首先我们来看一个通用的例子,制作自己的nginx镜像。
# Base image
FROM centos:7
# MAINTAINER
MAINTAINER cbmiao
# 将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,包含了如下指令:
FROM指令用于指定基础镜像,必须为Dockerfile的第一个指令
# 格式:
# FROM
# FROM
# 示例:
FROM mysql:5.7
# 注意:
# tag是可选的,如果不使用tag,则默认会使用latest版本的基础镜像
参数解释:
FROM mysql:5.7:第一行必须指定 基础镜像信息
用于说明镜像维护者的信息,名字,邮箱,联系方式,实例如下
# 格式:
# MAINTAINER
# 示例:
MAINTAINER Michael Miu
MAINTAINER miaocbin@126.com
MAINTAINER Michael Miu
这两个命令的用法类似,都可以用于添加本地文件到镜像中(同样需求下,官方推荐使用 COPY),功能也类似,如:
二者区别如下:
# 格式:
# ADD|COPY
# 示例:
ADD|COPY tes* /mydir/ # 添加所有以"tes"开头的文件
ADD|COPY test mydir/ # 添加 "test" 到 WORKDIR/mydir/
ADD|COPY test /opt/ # 添加 "test" 到 /opt/
# [--chown=
说明:
指定工作目录,通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。(WORKDIR 指定的工作目录,必须是提前创建好的)
# 格式:
# WORKDIR /path/to/workdir
# 示例:
WORKDIR /abc (这时工作目录为/abc)
构建镜像过程中执行命令(注意:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache)
# 格式:
# RUN
# 示例:
RUN yum -y install nginx
RUN pip install djaong
RUN mkdir test && rm -rf /var/lib/testfile
类似于RUN指令,用于运行程序,但二者运行的时间点不同:
作用:为启动的容器指定默认要运行的程序,也就是在容器启动时才进行调用。程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker 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
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
# 格式:
# ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
# ENTRYPOINT command param1 param2 (shell内部命令)
# 示例:
ENTRYPOINT ["/usr/bin/wc","--help"]
注意:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
# 格式:
# ENV
# ENV
# 示例:
ENV myName John
ENV myCat=tomcat
声明端口,作用如下:
[ ...]# 格式:
# EXPOSE
# 示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
用来给镜像添加一些元数据(metadata),以键值对的形式
# 语法格式:
# LABEL
# 例如:添加镜像作者
LABEL org.opencontainers.image.authors="runoob"
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。作用:
# 格式:
# VOLUME ["<路径1>", "<路径2>"...]
# VOLUME <路径>
# 举例:
VOLUME [/var/lib/mysql]
利用Dockerfile构建自己的镜像命令
docker build . -t ImageName:ImageTag -f Dockerfile
上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
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
---> 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
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx v1.20.1 391f75b825bd 17 minutes ago 490MB
If you see this page, the nginx web server is successfully installed and For online documentation and support please refer to Thank you for using nginx.# 利用我们刚构建的镜像来启动容器
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
Welcome to nginx!
working. Further configuration is required.
nginx.org.
Commercial support is available at
nginx.com.
若想让我们的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简介及基本使用
不必要的内容不要放在镜像中:以免增大镜像,同时也带来安全隐患;
减少不必要的层文件
减少网络传输操作:尽量使用本地文件,加快镜像构建速度,特别是后面我们将利用Jenkins做自动化构建的时候;
可以适当的包含一些调试命令
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
人们永远没有足够的时间把它做好,但永远有足够的时间重新来过。
可是,因为并不是总有机会重做一遍,你必须做得更好,换句话说,
人们永远没有足够的时间去考虑到底是不是想要它,但永远有足够的时间去为之后悔。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
浅掘千口井,不如深挖一口井!当知识支撑不了野心时,那就静下心来学习吧!运维技术交流QQ群:618354452
个人微信公众号,定期发布技术文章和运维感悟。欢迎大家关注交流。