关于docker那点事儿——Dockerfile编写

Posted 偷学技术的梁胖胖yo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于docker那点事儿——Dockerfile编写相关的知识,希望对你有一定的参考价值。


前言

Dockerfile 说白了就是构建镜像的一个文件。它里面描述了一条条的指令,每一条指令都会构建新的一层。当执行docker build时,docker会按照我们Dockefile里预编写好的指令,去一层层构建,从而构建出一个新的镜像。

一、Dockerfile创建镜像

  1. 创建目录
mkdir any_name
cd any_name
  1. 编写Dockerfile文件
vim Dockerfile

# This is a comment 
FROM daocloud.io/library/nginx
MAINTAINER liang liang@localhost.localdomain
RUN mkdir /test

*注: 如果文件中有执行失败的指令,那么创建出来的镜像名字和tag都为none
  1. 构建镜像
docker build -t liang/nginx:v1 .     # . 一定要有 表示Dockerfile在当前目录 如果文件名不是Dockerfile 使用 -f 指定文件

二、Dockerfile常用指令

1、FROM 拉取基础镜像

功能为指定基础镜像,并且必须是第一条指令。如果不以任何镜像为基础,那么写法为:FROM scratch。

语法:FROM <image>:<tag>   其中<tag>为可选项,默认为latest

2、RUN 构建容器时执行命令

RUN命令有两种格式

Ⅰ. RUN <command>                # shell方式

Ⅱ. RUN ["executable", "param1", "param2"]     # 类似于函数调用,可将executable理解成为可执行文件,后面就是两个参数

*注:多行命令不要写多个RUN,写在一个RUN里,原因是Dockerfile中每一个指令都会建立一层

3、MAINTAINER

MAINTAINER <name>     # 指定作者

4、CMD 容器启动时要运行的命令

语法:Ⅰ. CMD ["executable","param1","param2"]    # CMD [ "sh", "-c", "echo $HOME" ]

       Ⅱ. CMD ["param1","param2"]          # CMD [ "echo", "$HOME" ]

       Ⅲ. CMD command param1 param2         # shell形式

*注:Ⅰ和Ⅱ两种方式一定要用双引号,千万不能写成单引号

5、ENV 设置环境变量

语法:ENV <key>=<value> ...    # 可一次设置多个

6、ADD 复制命令 类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用

语法:Ⅰ. ADD <src>... <dest>

       Ⅱ. ADD ["<src>",... "<dest>"]

<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径

<src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url

7、COPY 复制命令

语法:Ⅰ. COPY <src>... <dest>

        Ⅱ. COPY ["<src>",... "<dest>"]

8、EXPOSE 暴露监听端口给外部

*注:EXPOSE并不会使容器访问主机的端口,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上-p参数

9、WORKDIR 设置工作目录

语法:WORKDIR /path/to/workdir

对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。

10、VOLUME 实现挂载功能,可以将本地文件夹或者其他容器中的文件夹挂在到这个容器

语法:VOLUME ["/data"]

*注:一般不会在Dockerfile中用到,更常见的还是在docker run的时候指定-v数据卷

三、示例

1、Dockerfile构建nginx镜像

FROM centos:7.2.1511
ENV TZ=Asia/Shanghai
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

RUN yum -y install epel*  gcc openssl openssl-devel  pcre-devel zlib-devel

ADD nginx-1.14.0.tar.gz /opt/

WORKDIR /opt/nginx-1.14.0

RUN ./configure --prefix=/opt/nginx  --http-log-path=/opt/nginx/logs/access.log --error-log-path=/opt/nginx/logs/error.log --http-client-body-temp-path=/opt/nginx/client/  --http-proxy-temp-path=/opt/nginx/proxy/  --with-http_stub_status_module --with-file-aio --with-http_flv_module --with-http_gzip_static_module --with-stream --with-threads --user=www --group=www
RUN make && make install
RUN groupadd www && useradd -g www www
WORKDIR /opt/nginx
RUN rm -rf /opt/nginx-1.14.0

ENV NGINX_HOME=/opt/nginx
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/nginx/sbin

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

*注:此只是个例子,实际中如果没有满足需求的base image,如java程序使用java:8作为base image,可以使用Alpine镜像作为base image,轻量级且命令丰富,比centos镜像更适合做base image

2、Dockerfile构建微服务

#cat Dockerfile
FROM java:8
MAINTAINER liang_20210511
#ENV TZ=Asia/Shanghai
#ENV LANG=en_US.UTF-8
#ENV LANGUAGE=en_US:en
#ENV LC_ALL=en_US.UTF-8
ENV JAVA_OPTS="-Xms512m -Xmx512m"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ADD cmdb-server.tar /
WORKDIR /cmdb-server
EXPOSE 10013

#CMD ["java","-jar","cmdb-server.jar","-Dfile.encoding=utf-8"]
ENTRYPOINT ["/cmdb-server/entrypoint.sh"]

#cat entrypoint.sh 
#!/bin/sh
nohup java -server $JAVA_OPTS -jar cmdb-server.jar >/dev/null 2>&1 &
sleep 1
if [ $? -eq 0 ];then
tail -f logs/cmdb-server.log
fi

四、CMD与ENTRYPOINT比较

  cmd 和 entrypoint 指令都是用来指定容器启动时运行的命令。并且都有exec与shell两种模式。推荐使用exec模式,这样可以使容器接收的KILL信号,从而优雅的退出。这里牵扯到容器的daemon进程来管理容器的生命周期,以后有机会我们以后专门拿出来去探讨。

  cmd 指令

  cmd 指令的目的是:为容器提供默认的执行命令。

  cmd 指令有三种使用方式,其中的一种是为 entrypoint 提供默认的参数:

cmd ["param1","param2"]

  另外两种使用方式分别是 exec 模式和 shell 模式:

cmd ["executable","param1","param2"]

cmd command param1 param2

  注意命令行参数可以覆盖 cmd 指令的设置,但是只能是重写,却不能给 cmd 中的命令通过命令行传递参数。我们可以通过docker run参数的方式覆盖 cmd 指令提供的默认命令。

  entrypoint 指令

  entrypoint 指令的目的也是为容器指定默认执行的任务。

  entrypoint 指令有两种使用方式, exec 模式和 shell 模式:

entrypoint ["executable", "param1", "param2"] 

entrypoint command param1 param2

  在这里entrypoint 有一个特殊的用法,传参

  1、当我们使用exec模式时,docker run的指令可以作为参数传递给entrypoint 命令。比如:

from centos
entrypoint [ "top", "-n" ]

当我们执行docker run -- rm centos:test 1
此时容器里执行的命令:top -n 1

  2、cmd指令给entrypoint 传参,比如:

from centos
entrypoint [ "top", "-n" ]
cmd [ "1" ]

当我们执行docker run -- rm centos:test
此时容器里执行的命令:top -n -1

  3、docker run的指令覆盖cmd指令,传参给entrypoint

from centos
entrypoint [ "top", "-n" ]
cmd [ "1" ]

当我们执行docker run -- rm centos:test 3
此时容器里执行的命令:top -n -3

  其实cmd指令与entrypoint指令远比这些要复杂:


  当然,大家想深入了解的也可以参考官方给的解释自行实践对比一下:官方链接

以上是关于关于docker那点事儿——Dockerfile编写的主要内容,如果未能解决你的问题,请参考以下文章

关于docker那点事儿——docker compose简介

关于docker那点事儿——docker网络模式

关于SSL/TLS的那点事儿

关于SSL/TLS的那点事儿

AOP 那点事儿 ( 续集 )

我的AOP那点事儿--2