Dockerfile文件

Dockerfile

基本结构

Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。

Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。

Docker分为四部分:

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时默认要执行的指令

例如:

# This dockerfile uses the centos image
# VERSION 1 - EDITION 1
# Author: lfdfp
# Command format: Instruction [arguments / command] ...

# 第一行必须指定基于的基础镜像
FROM centos

# 维护者信息
LABEL MAINTAINER='lfdfp 82762512451@qq.com'

# 镜像操作指令
FROM centos
RUN 
ADD nginx-1.18.0.tar.gz /usr/src
WORKDIR /usr/src/
RUN yum -y install gcc gcc-c++ zlib-devel openssl-devel pcre-devel make && \
cd nginx-1.18.0 && ./configure && make && make install 
RUN echo "\ndaemon off;" >> /usr/local/nginx/conf/nginx.conf

# 容器启动时默认要执行的指令
CMD ["/usr/local/nginx/sbin/nginx"]

其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。

指令

指令的一般格式为INSTRUCTION arguments,指令包括:

  • FROM
  • MAINTAINER
  • RUN
  • CMD
  • EXPOSE
  • ENV
  • ADD
  • COPY
  • ENTRYPOINT
  • VOLUME
  • USER
  • WORKDIR
  • ONBUILD
FROM

格式为FROM <image>FROM <imagge>:<tag>

第一条有效的指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。

# Here is the first line that is valid 
FROM centos
......
LABEL MAINTAINER

格式为LABEL MAINTAINER <name email_address>,指定作者信息

# Here is the first line that is valid 
FROM centos

LABEL MAINTAINER='lp 86425451@qq.com'
......
RUN

容器在构建时需要运行的命令,格式为RUN <command>RUN ["executable","param1","param2"]

前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其他终端可以通过第二种方式实现,例如:

RUN ["/usr/bin/echo","hello world"]

每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,例如:

RUN echo "hello world\nhello tom" > /tmp/abc && \
    cat /opt/abc
CMD

CMD支持三种格式:

  • CMD ["executable","param1","param2"]使用exec执行,推荐方式

    [root@localhost ~]# vim apache/Dockerfile
    ......
    CMD ["usr/local/apache/bin/apache","-D","FOREGROUND"]
    ......
    
    # 使用这种方式启动容器后查看执行的程序是
    [root@localhost ~]# docker ps 
    CONTAINER ID   IMAGE                       COMMAND                        CREATED        STATUS 
      ...           ...      "usr/local/apache/bin/apache","-D","FOREGROUND"    ...            ...         
    
    # 使用的是 "usr/local/apache/bin/apache","-D","FOREGROUND" 启动的容器             
    
  • CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用

    [root@localhost ~]# vim apache/Dockerfile
    ......
    CMD /usr/local/apache/bin/apache -D FOREGROUND
    ......
    
    # 使用这种方式启动容器后查看执行的程序是
    [root@localhost ~]# docker ps 
    CONTAINER ID   IMAGE                       COMMAND                                  CREATED       
      ...           ...      "/bin/sh -c /usr/local/apache/bin/apache -D FOREGROUND"        ...             
    
    # 使用的是 "/bin/sh -c usr/local/apache/bin/apache -D FOREGROUND # 使用的是/bin/sh -c 执行 启动的容器       
    
  • CMD ["param1","param2"]提供给ENTRYPOINT的默认参数

    [root@localhost ~]# vim apache/Dockerfile
    .......
    CMD ["-D","FOREGROUND"]                         # 传递给ENTRYPOINT的参数
    ENTRYPOINT ["/usr/local/apache/bin/apachectl"]  # 启动容器时的命令
    ......
    
    # 使用这种方式启动容器后查看执行的程序是
    [root@localhost ~]# docker ps 
    CONTAINER ID   IMAGE          COMMAND                                  CREATED        STATUS     PORTS    ...          ...  "/usr/local/apache/bin/apachectl -D FOREGROUND"    ...             ...    ...
    
    # 使用的是 "/usr/local/apache/bin/apachectl -D FOREGROUND" 传递参数 启动的容器
    

CMD用于指定启动容器时默认要执行的命令,每个Dockerfile只能有一条CMD命令。

[root@localhost ~]# cat test/Dockerfile
......

CMD sleep 300    # 当CMD只有一条的时候就执行当前命令

如果指定了多条命令,只有最后一条会被执行。

[root@localhost ~]# cat test/Dockerfile
......

CMD sleep 300    
CMD sleep 400
CMD sleep 500    # 当CMD有多条的时候就执行最后一条命令

如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

[root@localhost ~]# cat test/Dockerfile  # 查看
......

CMD ["sleep","500"]

[root@localhost ~]# docker build -t yunjisuanlp/test:v0.1 test  # 构建镜像
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 5d0da3dc9764
Step 2/2 : CMD ["sleep","500"]
 ---> Running in gfdgd5153dfg1
Removing intermediate container gfdgd5153dfg1
 ---> gdgd54s3g4r4gf
Successfully built gdgd54s3g4r4gf
Successfully tagged test:v0.1


# 未覆盖是运行的"sleep 500"
[root@localhost test]# docker run -itd --rm yunjisuanlp/test:v0.1   
bfhy55gd5fs6fs56f4sgf5dgd6g4d6esf54g6h6d4hg6h46gh
[root@localhost test]# docker ps
CONTAINER ID   IMAGE       COMMAND       CREATED         STATUS         PORTS     NAMES
5fgdfg45d4g4   test:v0.1   "sleep 500"   2 seconds ago   Up 2 seconds             dgfdgfdg_hgfhfgfsfd


# 覆盖之后 "sleep 500" 变成 /bin/sh
[root@localhost test]# docker run -itd --rm test:v0.2 /bin/sh
fbf0ec0e58fdf49358aca74efd2575464724fef5afa15890cc93193916016e65
[root@localhost test]# docker ps
CONTAINER ID   IMAGE       COMMAND       CREATED         STATUS         PORTS     NAMES
fgfd554d54d   test:v0.8   "/bin/sh"   3 seconds ago   Up 5 seconds             fgdjgd_Gdgdfgfd
EXPOSE

格式为EXPOSE <port> [<port>...]
例如:

[root@localhost ~]# cat test/Dockerfile  # 查看
......
EXPOSE  80
......

# 构建镜像后运行容器后查看
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS     
gdfg454gf4g4   test:v0.1   "/usr/sbin/httpd -D …"   2 seconds ago   Up 1 seconds   80/tcp  

EXPOSE指令实际上并不发布端口。它作为构建镜像的人和运行容器的人之间的一种文档,用于发布哪些端口。要在运行容器时实际发布端口,请在docker run上使用-p标志发布并映射一个或多个端口,或使用-p标志发布所有公开的端口并将它们映射到高阶端口。

ENV

格式为ENV <key> <value>。指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。例如:

ENV PG_MAJOR 9.3      # 主版本号
ENV PG_VERSION 9.3.4  # 次版本号
RUN curl -SL http://example.com/postgres-${PG_VERSION}.tar.xz | tar -xJC /usr/src/postgress && ... 
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH  # 环境变量
ADD

格式为ADD <src> <dest>

该命令将复制指定的到容器中的。其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(会自动解压)。

[root@localhost ~]# vim test/Dockerfile
......
ADD	 httpd-2.4.48.tar.gz /usr/src/   #将包传到指定的容器目录,如果是压缩包会自动解压,如果传的目录,会将目录里的文件传到指
定的容器目录内
......
COPY

格式为COPY <src> <dest>

复制本地主机的(为Dockerfile所在目录的相对路径,文件或目录)为容器中的。目标路径不存在时会自动创建。
当使用本地目录为源目录时,推荐使用COPY。

[root@localhost ~]# vim test/Dockerfile
......
COPY httpd.conf /usr/local/htttpd/conf/  # 复制指定文件到容器内
......
ENTRYPOINT

ENTRYPOINT有两种格式:

  • ENTRYPOINT [“executable”,“param1”,“param2”]

    [root@localhost ~]# vim apache/Dockerfile
    ......
    ENTRYPOINT ["/usr/local/apache/bin/apachectl","-D","FOREGROUND"]
    ......
    
    
    # 使用这种方式启动容器后查看执行的程序是
    [root@localhost ~]# docker ps 
    CONTAINER ID   IMAGE          COMMAND                                  CREATED        STATUS     PORTS    ...          ...  "/usr/local/apache/bin/apachectl -D FOREGROUND"    ...             ...    ...
    
    # 使用的是 "/usr/local/apache/bin/apachectl -D FOREGROUND" 启动的容器
    
  • ENTRYPOINT command param1 param2(在shell中执行)

    [root@localhost ~]# vim apache/Dockerfile
    .......
    ENTRYPOINT /usr/local/apache/bin/apachectl -D FOREGROUND
    .......
    
    # 使用这种方式启动容器后查看执行的程序是
    [root@localhost ~]# docker ps 
    CONTAINER ID   IMAGE                       COMMAND                                  CREATED       
      ...           ...      "/bin/sh -c /usr/local/apache/bin/apache -D FOREGROUND"        ...             
    
    # 使用的是 "/bin/sh -c usr/local/apache/bin/apache -D FOREGROUND # 使用的是/bin/sh -c 执行 启动的容器
    

配置容器启动后执行的命令,并且不可被docker run提供的参数覆盖。而且,如果在docker run的后面提供了参数,这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序。

[root@localhost ~]# docker run --name web --rm yunjisuanlp/httpd -v # 传递-v参数,查看版本
Server version: Apache/2.4.48 (Unix)
Server built:   Dec  8 2021 09:53:59
[root@localhost ~]# vim apache/Dockerfile
.......
CMD ["-D","FOREGROUND"]                         # 传递给ENTRYPOINT的参数
ENTRYPOINT ["/usr/local/apache/bin/apachectl"]  # 启动容器时的命令
......

# 使用这种方式启动容器后查看执行的程序是
[root@localhost ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                        CREATED        STATUS     PORTS     
    ...         ...  "/usr/local/apache/bin/apachectl -D FOREGROUND"          ...        ...         

# 使用的是 "/usr/local/apache/bin/apachectl -D FOREGROUND" 传递参数 启动的容器

每个Dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。

VOLUME

格式为VOLUME ["/data"]

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

USER

格式为USER daemon

指定运行容器时的用户名或UID,后续的RUN也会使用指定用户。

当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:

RUN groupadd -r postgres && useradd -r -g postgres postgres

要临时获取管理员权限可以使用gosu,而不推荐sudo。如果不指定,容器默认是root运行。

WORKDIR

格式为WORKDIR /path/to/workdir

为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为/a/b/c。

ONBUILD

格式为ONBUILD [INSTRUCTION]

配置当所创建的镜像作为其他镜像的基础镜像时,所执行的操作指令。

例如,Dockerfile使用如下的内容创建了镜像image-A

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

此时,如果基于image-A创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像时,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令。

FROM image-A

# Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild。

创建镜像

编写完成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/
编写源码安装apache的Dockerfile文件

创建目录

[root@localhost ~]# mkdir apache
[root@localhost ~]# cd apache/
[root@localhost apache]# mkdir files
[root@localhost apache]# touch Dockerfile
[root@localhost apache]# ls
Dockerfile  files

上传包到files目录

[root@localhost apache]# ls files/
apr-1.7.0.tar.gz  apr-util-1.6.1.tar.gz  httpd-2.4.48.tar.gz

编写Dockerfile文件内容

[root@localhost ~]# cat apache/Dockerfile 
FROM centos  # 基础镜像

LABEL MAINTAINER='gngdglp 70840453045@qq.com' # 作者的信息

ENV apache_version 2.4.48             # apache版本变量

ADD files/* /usr/src/  # 将files里的文件解压到容器内
WORKDIR /usr/src/      # 进入容器内的/usr/src/目录
RUN yum -y install openssl-devel pcre-devel pcre expat-devel libtool gcc gcc-c++ make which && \
    cd apr-1.7.0 && sed -i '/$RM "$cfgfile"/d' configure && \
    ./configure --prefix=/usr/local/apr && make && make install && \
    cd ../apr-util-1.6.1 && \
    ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && \
    make && make install && \
    cd ../httpd-${apache_version} && \
    ./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
   
ENV PATH /usr/local/apache/bin:$PATH  # 环境变量   
      
EXPOSE 80 8443   # 暴露端口
CMD ["-D","FOREGROUND"]  # 传递给ENTRYPOINT的参数
ENTRYPOINT ["/usr/local/apache/bin/apachectl"] # 启动容器时的命令

构建镜像

[root@localhost ~]# docker build -t yunjisuanlp/httpd apache # 指定新镜像名称为yunjisuanlp/httpd Dockerfile文件位置在apache目录下
Sending build context to Docker daemon  11.07MB
Step 1/7 : FROM centos
 ---> 5d0da3dc9764
Step 2/7 : LABEL MAINTAINER='gngdglp 70840453045@qq.com'
 ---> Running in a73b4021ea20
Removing intermediate container a73b4021ea20
 ---> e5a32e6539d8
Step 3/7 : ADD files/* /usr/src/
 ---> 985ff40b720c
Step 4/7 : WORKDIR /usr/src/
...................
Removing intermediate container 888a76e2ad8e
 ---> 6e955cc1b583
Step 8/10 : EXPOSE 80 8443
 ---> Running in e81054f83a3d
Removing intermediate container e81054f83a3d
 ---> 26b5266c2a5d
Step 9/10 : CMD ["-D","FOREGROUND"]
 ---> Running in 90b142a95d39
Removing intermediate container 90b142a95d39
 ---> 67699fa6fbaa
Step 10/10 : ENTRYPOINT ["/usr/local/apache/bin/apachectl"]
 ---> Running in 4c5e5818d56a
Removing intermediate container 4c5e5818d56a
 ---> 5b5218f83353
Successfully built 5b5218f83353
Successfully tagged yunjisuanlp/httpd:latest

查看镜像

[root@localhost ~]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
yunjisuanlp/httpd   latest    ef55dda7b63b   8 minutes ago   701MB # 新的
busybox             latest    d23834f29b38   7 days ago      1.24MB
centos              latest    5d0da3dc9764   2 months ago    231MB

使用新的镜像创建容器

[root@localhost ~]# docker run -it --name web yunjisuanlp/httpd  
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.2.2. Set the 'ServerName' directive globally to suppress this message

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS          PORTS              NAMES
3fe61fe82dc9   yunjisuanlp/httpd   "/usr/local/apache/b…"   21 seconds ago   Up 19 seconds   80/tcp, 8443/tcp   web

访问容器IP
[root@localhost ~]# curl 192.168.2.2
<html><body><h1>It works!</h1></body></html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值