第十一章 Dockerfile构建镜像

一、Dockerfile含义

Dockerfile 由一行行命令语句组成, 并且支持以#开头的注释行。一般而言, Dockerfile 主体内容分为四部分:基础镜像信息、 维护者信息、 镜像操作指令和容器启动时执行指令。

#1.Dockerfile是什么?
构建镜像所使用的指令配置文件

#2.Dockerfile基础部分
1、基础镜像,构建一个镜像所依赖的镜像(必须)
2、构建镜像的指令,按照我们需求自定义镜像
3、指定镜像启动命令,(指定容器启动的方式)

#3.使用Dockerfile需要注意的几点
1、dockerfile必须命名为`Dockerfile`
2、尽量将Dockerfile放在空目录中,如果目录中必须有其他文件,则使用.dockerignore文件。
3、避免安装不必须的包。
4、每个容器应该只关注一个功能点。
5、最小化镜像的层数。
6、多行参数时应该分类。这样更清晰直白,便于阅读和review,另外,在每个换行符前都增加一个空格。
7、对构建缓存要有清楚的认识。

二、Dockerfile的使用

#1.格式:
	docker build [参数] [dockerfile的路径]

#2.原理
	在构建docker镜像的时候,实际上将当前目录移动到了一个虚拟目录当中,所有的操作路径都是以虚拟路径为准。

#3.参数:
	-c : 指定使用CPU大小
	-f : 指定dockerfile路径
	-t : 指定构建后的镜像名称

三、Dockerfile文件说明

Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。

1、FROM指令:指定基础镜像,必须为第一个命令

#1.解释:
	指定构建镜像的基础镜像(有且只能有一个基础镜像)

#2.格式:
	FROM [基础镜像]:[镜像版本号]
	FROM <image>
	FROM <image>:<tag>
	FROM <image>@<digest>

#3.示例:
  FROM mysql:5.6

#4.注:
  tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像

2、MAINTAINER指令:维护者信息

#1.解释:
	指定维护者信息(现在已经淘汰)

#2.格式:
	MAINTAINER [名字] [des] [...]
    MAINTAINER <name>

#3.示例:
    MAINTAINER Jasper Xu
    MAINTAINER sorex@163.com
    MAINTAINER Jasper Xu <sorex@163.com>

3、RUN指令:构建镜像时执行的命令

#1.解释:
	RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:

#2.执行方式:
1.shell执行
格式:
	RUN [linux命令]
    RUN <command>
    
2.exec执行
格式:
    RUN ["executable", "param1", "param2"]

#3.示例:
    RUN ["executable", "param1", "param2"]
    RUN apk update
    RUN ["/etc/execfile", "arg1", "arg1"]
    
#4.注:
	RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache

4、ADD指令:将本地文件添加到容器中

#1.解释:
	将本地文件添加到容器中,添加文件到镜像中,ADD指令有一个自动解压的功能(tar),ADD指令可以下载互联网上的文件但是不解压。

#2.格式:
	ADD [宿主主机文件路径(必须使用相对路径)]  [添加到镜像中的文件路径]
	ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径

#3.示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/
    
# 添加文件到容器当中
ADD ./1.txt /root

# 添加一个压缩包,测试是否会自动解压
ADD etcd-v3.0.17-darwin-amd64.zip /opt

# 在网上下载文件至镜像中(不会自动解压)
ADD https://mirrors.huaweicloud.com/etcd/v3.0.17/v3.0.17.tar.gz  /opt

# 测试正则
ADD etcd-v3.0.17* /tmp/

# 测试ADD文件
ADD mysql.txt /root/

#4.注:
	ADD指令支持正则(路径必须以/结尾)

5、COPY指令 :功能类似ADD,但是是不会自动解压文件,也不能访问网络资源

#1.解释:
	复制一个文件到镜像中

#2.格式:
	COPY [宿主主机文件路径(必须使用相对路径,只能向下找文件)]  [添加到镜像中的文件路径]
	COPY < src>… < dest>|[“< src>”,… “< dest>”]

#3.示例:
    # 测试COPY正则
    COPY etcd-v3.0.17* /etc/

    # 测试COPY文件
    COPY mysql.txt /opt/
    
    # 测试COPY
    COPY ./1.txt /opt

    # 测试COPY解压功能
    COPY etcd-v3.0.17-linux-amd64.tar.gz /opt
    
#4.注:
	COPY指令没有解压功能.
	COPY指令不支持互联网下载.
	COPY指令支持正则.
	
ps:指令逻辑和ADD十分相似,同样Docker Daemon会从编译目录寻找文件或目录,dest为镜像中的绝对路径或者相对于WORKDIR的路径

6、CMD指令: 构建容器后调用,也就是在容器启动时才进行调用

#1.解释:
	指定容器启动时默认命令

#2.格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)

#3.示例:
    CMD echo "This is a test." | wc -
    CMD ["/usr/bin/wc","--help"]
	CMD /bin/bash
	CMD ["nginx","-g","daemon off;"]
	
#4. 注:   
	CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

7、LABEL指令:用于为镜像添加元数据

#1.解释:
	使用LABEL指定元数据时
	
#2.格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    
#3.示例:
  LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
  LABEL key=value
  
#4.注:
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。

8、ENV指令:设置环境变量

#1.解释:
	指定环境变量
	
#2.格式:
    ENV <key> <value>  #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
    ENV <key>=<value> ...  #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行

#3.示例:
	ENV myName John Doe
	
    ENV myDog Rex The Dog
    
    ENV myCat=fluffy
    
	ENV NGINX_WORKER=5
        [root@docker ~/docker/nginx]# docker exec wizardly_cannon printenv
        PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
        NGINX_WORKER=5
        
	ENV NGINX_DES nginx server is very 666
		[root@docker ~/docker/nginx]# docker exec amazing_driscoll printenv
        PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
        NGINX_DES=nginx server is very 666
        
 #4.查看环境变量
 [root@m01 ~]# docker exec {containerID} env

9、EXPOSE指令:指定于外界交互的端口

#1.解释:
	指定向外暴露的端口

#2.格式:
    EXPOSE <port> [<port>...]

#3.示例:
    EXPOSE 80 443
    
    EXPOSE 8080 
    
    EXPOSE 11211/tcp 11211/udp

	EXPOSE 80 443 1000 10000
    [root@docker ~/docker/nginx]# docker run -d test/nginx:v12 
    e4f0b3a673dd9c83d2ecdb40c1726d3bed595890eeb9eab7fefb3218eb5650dc
    [root@docker ~/docker/nginx]# docker ps
    CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                                  NAMES
    e4f0b3a673dd   test/nginx:v12   "/docker-entrypoint.…"   3 seconds ago    Up 3 seconds    80/tcp, 443/tcp, 1000/tcp, 10000/tcp   naughty_fermat
    
    
    EXPOSE 80 443 1000/udp 10000
    [root@docker ~/docker/nginx]# docker ps
    CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                                  NAMES
    e1e4f2c18f40   test/nginx:v13   "/docker-entrypoint.…"   48 seconds ago   Up 48 seconds   80/tcp, 443/tcp, 10000/tcp, 1000/udp   hungry_aryabhata


#4.注:  
        EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口

10、VILUME指令: 用于指定持久化目录

#1.解释:指定挂载点

#2.格式:
  VOLUME ["/path/to/dir"]

#3.示例:
  VOLUME ["/data"]
  
  VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]

  VOLUME /data
  docker inspect test/nginx:v14
        "Mounts": [
            {
                "Type": "volume",
                "Name": "b9b87662e3296ea94db87b48ef642933751f53fe7bf715026f59043bc65335f0",
                "Source": "/var/lib/docker/volumes/b9b87662e3296ea94db87b48ef642933751f53fe7bf715026f59043bc65335f0/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

#4.注:  
	一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
		1.卷可以容器间共享和重用
		2.容器并不一定要和其它容器共享卷
		3.修改卷后会立即生效
		4.对卷的修改不会对镜像产生影响
		5.卷会一直存在,直到没有任何容器在使用它
		6.共享存储卷:docker run --valumes-from [共享容器的名称] [镜像名称]
		docker run -d --volumes-from upbeat_mcclintock test/nginx:v16
		7.如果使用-v参数,将挂载指定的目录,不使用则自动生成挂载。

11、ARG指令:1.1、 用于指定传递给构建运行时的变量

#1.解释:
	设置运行时参数,一般是在构建时使用

#2.格式:
	ARG key  : 需要用到docker build --build-arg key=value
	ARG key=value
	ARG <name>[=<default value>]

#3.示例:
	[root@docker ~/docker/nginx]# docker exec 7ed524e38ac8 cat log
	value
	
 	ARG site
 	
 	ARG build_user=www

12、ONBUILD指令:用于设置镜像触发器

#1.解释:
	镜像触发器(当当前镜像作为基础镜像时,执行)

#2.格式:
	ONBUILD [dockerfile指令]
	ONBUILD [INSTRUCTION]
	ONBUILD RUN touch 1.txt

#3.示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src

#4.注:  
    当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发

13. WORKDIR:工作目录,类似于cd命令

#1.格式:
  WORKDIR /path/to/workdir

#2.示例:
  WORKDIR /a (这时工作目录为/a)
  WORKDIR b (这时工作目录为/a/b)
  WORKDIR c (这时工作目录为/a/b/c)
  
#3.注:  
   通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。

四、Dockerfile构建镜像案例一

1.新建Dockerfile

1.新建目录
[root@m01 ~]# mkdir /docker/
[root@m01 ~]# cd /docker

2.新建Dockerfile
[root@m01 /docker]# cat Dockerfile 
#Is my first nginx Dockerfile
# Version 1.0

# Base images 基础镜像
FROM centos

#MAINTAINER 维护者信息
MAINTAINER jh

#ADD  文件放在当前目录下,拷过去会自动解压
ADD nginx-1.18.0.tar.gz /usr/local/  
ADD epel-release-latest-7.noarch.rpm /usr/local/  

#RUN 执行以下命令

RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y gcc gcc-c++ autoconf pcre pcre-devel make automake wget httpd-tools vim tree && yum clean all
RUN useradd -s /sbin/nologin -M www

#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.18.0 

RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_addition_module --with-http_auth_request_module --without-http_gzip_module && make && make install

RUN echo "daemon off;" >> /etc/nginx.conf

#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH

#EXPOSE 映射端口
EXPOSE 80

#CMD 运行以下命令
CMD ["nginx"]

2.上传相关安装包

[root@m01 /docker]# rz
-rw-r--r-- 1 root root       918 Jan 14 20:59 Dockerfile
-rw-r--r-- 1 root root     15448 Jan 14 19:44 epel-release-latest-7.noarch.rpm
-rw-r--r-- 1 root root   1039530 Jan 14 19:44 nginx-1.18.0.tar.gz

3.创建镜像

[root@m01 /docker]# docker build -t centos_nginx:v4 .
[root@m01 /docker]# docker images
REPOSITORY     TAG       IMAGE ID       CREATED         SIZE
centos_nginx   v4        f87c2b493910   7 minutes ago   483MB
centos         latest    300e315adb2f   5 weeks ago     209MB

4.备份镜像

[root@m01 /docker]# docker save f87c2b493910 > centos_nginx:v4.tar

5.运行容器

[root@m01 /docker]# docker run -d -p81:80 centos_nginx:v4 nginx -g "daemon off;"
535f5d0f2829c1d4642020f03e8d48616f31edfe111bab02173f0815892d3698

五、Dockerfile构建镜像案例二

1.新建Dockerfile

1.新建目录
[root@m01 ~]# mkdir /docker/
[root@m01 ~]# cd /docker

2.新建Dockerfile
[root@m01 /docker]# vim Dockerfile 
#Is my first nginx Dockerfile
# Version 1.0

# Base images 基础镜像
FROM centos

#MAINTAINER 维护者信息
MAINTAINER Jin Hui

#ADD  下载相关文件放在当前目录下,不会自动解压
ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/
ADD https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm /usr/local/ 

#RUN 执行以下命令
RUN tar xf /usr/local/nginx-1.18.0.tar.gz -C /usr/local/
RUN rpm -ivh /usr/local/epel-release-latest-8.noarch.rpm
RUN yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake wget httpd-tools vim tree && yum clean all
RUN useradd -s /sbin/nologin -M www

#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.18.0 

#RUN 执行以下命令
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_addition_module --with-http_auth_request_module --without-http_gzip_module && make && make install

#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH

#EXPOSE 映射端口
EXPOSE 80

#CMD 运行以下命令
CMD ["nginx","-g","daemon off;"]

2.构建镜像

[root@m01 /docker]# docker build --no-cache -t centos_nginx:v1 .
[root@m01 /docker]# docker images
REPOSITORY     TAG       IMAGE ID       CREATED         SIZE
centos_nginx   v1        ca2a0d26d619   21 minutes ago  521MB
centos         latest    300e315adb2f   5 weeks ago     209MB

3.备份镜像

[root@m01 /docker]# docker save ca2a0d26d619 > centos_nginx:v1.tar

4.运行容器

[root@m01 /docker]# docker run -d -p 80:80  --name nginx centos_nginx:v1
dd014764a0d192cb6185d3db92e34a8e0358cf125c20d0a68a80b6a598e84c63

5.测试镜像

[root@docker100 ~/1]# curl  127.0.0.1:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
         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>
原文地址:https://www.cnblogs.com/jhno1/p/15266704.html