• Dockerfile讲解


    前言

    环境:centos7.9 docker version 20.10.14

    构建镜像

    如何构建一个镜像?我们知道,构建镜像一般有两种方法:
    1、手动修改容器内容,比如安装一个工具等等,然后使用docker commit 容器id 镜像:tag 来创建新的镜像
    2、通过在Dockerfile中定义一系列的指令和参数来构建镜像,dockerfile是一个包含用于组合镜像的命令的文本文档,可以使用在命令行中调用任何命令, 然后docker通过读取Dockerfile中的指令自动生成镜像,docker build命令用于从Dockerfile构建镜像。

    Dockerfile的主要组成

    Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

    Dockerfile指令

    注意:Dockerfile文件必须以Dockerfile为文件名字,这命名是有特殊含义的,后面会讲到。
    Dockerfile的指令与两种书写形式,一种是shell格式,另一种是exec格式。

    FROM mysql:5.6						#FROM指令定义基础镜像,FROM指令必须是第一个指令
    MAINTAINER Benjamin <qq.com>		#MAINTAINER指令指定维护者信息,此指令为可选
    ENV JAVA_HOMR="/usr/local/java"		#ENV定义环境变量,后续指令中可以通过$JAVA_HOME来引用环境变量,ENV定义的变量可以在容器中使用
    ARG name="xiaolming"				#ARG也是定义环境变量,与ENV不同的是,ARG定义的环境变量只能在Dockerfile中使用,在容器中不存在
    RUN yum install -y httpd			#RUN指令用于运行一个命令,如使用yum安装httpd服务
    COPY /file*.txt /file/				#COPY用于复制宿主机文件到容器指定目录,COPY支持通配符
    ADD	hello-world /app/				#ADD也是用于复制宿主机文件到容器指定目录,ADD也支持通配符,与COPY不同的是,ADD会自动解压文件
    WORKDIR /app/						#WORKDIR指令用于用于设置当前工作目录
    USER root							#USER指令用于切换用户
    VOLUME	/data						#VOLUME指令用于定义匿名卷,表示将容器内的/data目录挂载为匿名卷到宿主机上
    EXPOSE	80 8089/udp					#EXPOSE用于声明容器端口,如果未指定协议,则默认为TCP,仅仅是声明,并没有绑定宿主机端口映射
    CMD ["nginx", "-g", "daemon off;"]	#CMD指令的作用是指定容器主进程的默认启动指令
    ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]	#ENTRYPOINT指令也是指定容器主进程的默认启动指令,但与CMD有区别。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    各个指令详细介绍如下:

    FROM mysql:5.6
    说明:FROM指令用来指定基础镜像信息,FROM必须为第一个指令,tag是可选的,如果不写tag,会使用latest版本的基础镜像,alpine、busybox镜像
    一般可以作为基础镜像。
    
    MAINTAINER Benjamin Yang <133xxxx2282@163.com>	
    说明:MAINTAINER 指令用来指定维护者信息,告诉别人谁负责维护它,当然你可以不指定维护者信息。
    
    ENV <key> <value>
    ENV <key>=<value>...
    ENV  sex "man"
    ENV  name="xiaolming"
    说明:ENV指令用于定义环境变量,定义好后的变量,在后续的指令中就可以直接使用 $name的形式引用环境变量,同时,ENV定义的变量即能在Dockerfile中使用,还能在容器中使用。
    
    ARG sex "man"
    ARG name="xiaolming"
    说明:ARG指令也是用于定义环境变量,与ENV定义环境变量相比,ARG定义的环境变量只能在Dockerfile中使用,换句话说,ARG所设置的构建环境的环境变量在将来容器运行时是不会存在的。
    
    RUN <command> (shell格式,该指令在shell中运行,默认情况下/bin/sh -c在Linux运行)
    RUN ["executable", "param1", "param2"](exec格式)
    RUN ["yum", "install", "httpd"]
    RUN yum install -y httpd  && yum -y install wget
    说明:RUN指令用来指定操作指令,比如yun安装一个依赖、软件等等,RUN指令有两种方式:一种是直接shell执行,另外一种是exce
    注意,每执行一个RUN指令都会生成一层镜像,RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指
    定--no-cache参数。
    我们为了减少RUN生成的镜像层,可以使用&&符号来将多个RUN指令合起来。
    
    COPY <src>... <dest>
    COPY ["", ... ""]
    COPY hello-world /app/		#注意:目标路径/app/一定要加斜杠,不然就表示重命名hello-world文件根app文件了,/app/不存在则自动创建目录
    COPY /file*.txt /file/		#COPY支持通配符匹配文件
    说明:COPY指令用于复制宿主机文件到容器内指定路径,COPY指令复制tar,tar.gz等格式的文件时,并不会自动解压tar、tar.gz等压缩包,仅复制文
    件而已。COPY复制文件时会保留文件的元属性,如文件属组,创建时间,读、写、执行权限等元数据。
    
    ADD <src>... <dest>
    ADD	hello-world /app/
    ADD https://cdn.mysql.com/archives/mysql-8.0/mysql-8.0.25-linux-glibc2.12-i686.tar.xz /home/mysql/
    说明:ADD指令也是复制宿主机文件到容器内指定路径,但ADD比COPY更高级,ADD指令复制tar,tar.gz,gzip,bzip2以及xz的情况下等格式的文件时,
    会自动解压压缩包文件,同时ADD指令的<源路径>可以是一个 URL,Docker引擎会试图去下载,然后放置到 <目标路径>。下载后的文件权限自动设置为600 
    ,如果需要更改权限,需要再增加一层RUN进行权限修改。如果下载的是一个压缩包,一般情况是 RUN 指令,然后使用wget或curl去下载,然后更改权
    限、解压、清理下载的源文件。
    
    WORKDIR <dir>
    WORKDIR /app/
    说明:WORKDIR目录用于设置当前工作目录,ORKDIR /app/就表示进入/app/目录,如果目录不存在则自动创建目录
    
    USER root
    说明:USER指令用于切换用户执行后续操作。
    
    VOLUME	/data
    说明:VOLUME指令用于定义匿名卷,表示将容器内的/data目录挂载为一个匿名卷到宿主机上,这个匿名卷卷名由docker自动生成;
    ps: 一般不会在 Dockerfile 中用到VOLUME指令,我们更常见的还是在 docker run 的时候指定 -v 参数来指定挂载的数据卷。
    
    
    EXPOSE <port> [<port>/<protocol>...]
    EXPOSE	80 
    EXPOSE	80/tcp 8089/udp
    说明:EXPOSE指令告诉Docker容器在运行时监听指定的网络端口。如果未指定协议,则默认为TCP。
    EXPOSE指令仅仅是声明运行时容器打算使用什么端口,并不会自动在宿主进行端口映射。
    
    CMD指令有三种格式:
    CMD ["executable","param1","param2"] (exec格式,一般推荐使用的格式)
    CMD ["param1","param2"] (参数列表格式)
    CMD command param1 param2 (shell格式)
    CMD nginx -g "daemon off;"
    CMD ["nginx", "-g", "daemon off;"]
    说明:CMD指令的作用是指定容器主进程的默认启动指令。同时,如果在docker run运行时指定了新的指令行参数则会覆盖这个CMD默认指令。
    
    
    ENTERYPOINT指令格式:
    ENTERYPOINT command (shell模式)
    ENTERYPOINT ["executable","param1","param2"] (exec模式)
    ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
    ENTERYPOINT不会被docker run 的指令行参数指定的指令所覆盖,而且这些指令行参数会被当作参数送给 ENTERYPOINT 指令指定的程序,
    但是,如果运行 docker run 时使用了--entrypoint 选项,将覆盖 entrypoint 指令指定的程序,
    使用ENTERYPOINT的优点是:在执行 docker run 的时候可以指定ENTRYPOINT 运行所需的参数。
    注意:如果Dockerfile中存在多个ENTRYPOMIT指令,仅最后一个生效。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    Dockerfile实战

    下面通过编写一个简单的Python网站程序,再编写Dockerfile文件来构建镜像,运行镜像,如下:
    注意:Dockerfile文件必须以Dockerfile为文件名字。

    [root@node2 ~]# mdkir dockerfile									#先创建一个目录
    [root@node2 ~]# cd dockerfile										#进入目录
    [root@node2 dockerfile]# docker pull  centos:7.8.2003				#下载一个centos7版本的基础镜像
    [root@node2 dockerfile]# vim  my_website.py 						#编写我们的网站python程序
    #coding:utf8
    from flask import Flask
    app=Flask(__name__)
    @app.route('/')
    def hello():
        return "Being single is better than being in an unfaithful relationship."
    if __name__=="__main__":
       app.run(host='0.0.0.0',port=8080)								#网站对外暴露的是8080端口
    
    [root@node2 dockerfile]# vim Dockerfile								#编写dockerfile文件,文件名是固定,必须是Dockerfile
    FROM centos:7.8.2003												#FROM指定基础镜像为centos:7.8.2003
    RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo		#下载yum源
    RUn curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo				#下载epel源
    RUN yum makecache													#建立缓存
    RUN yum -y install python3-devel python3-pip						#安装python环境
    RUN pip3 install flask												#安装flask
    COPY my_website.py /opt/												#把我们的python程序复制到容器的/opt目录
    WORKDIR /opt/														#指定当前工作目录是/opt
    EXPOSE 8080															#对外暴露端口为8080,因为我们python程序就是8080端口
    CMD ["python3","my_website.py"]										#容器启动时运行python程序
    [root@node2 dockerfile]# 
    
    #构建镜像,--no-cache表示不缓存,镜像是分层的,如果已经构建过了则docker会使用缓存,这里使用--no-cache表示不使用缓存
    # -t 指定镜像名称和版本,如果不指定-t ,则构建出来的镜像没有名称和版本号
    # 最后一个点.表示当前目录,docker build指令会默认寻找当前目录下名叫Dockerfile的文件进行构建镜像
    [root@node2 dockerfile]# docker build --no-cache  -t my_website:1.1.1 .
    					 
    #看到下面的Successfully 表示镜像构建成功				 
    Successfully built e72b9af57bca
    Successfully tagged my_website:1.1.1
    [root@node2 dockerfile]# docker images  my_website					#查看镜像
    REPOSITORY   TAG        IMAGE ID       CREATED         SIZE
    my_website   1.1.1      e72b9af57bca   6 seconds ago   1.05GB
    
    [root@node2 dockerfile]# docker run -d -it --name my_website -p 80:8080  my_website:1.1.1	#启动并运行my_website:1.1.1镜像
    
    #查看my_website容器状态,已经是启动了,对外暴露80端口,容器内部端口是8080
    [root@node2 dockerfile]# docker ps -a
    CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS                                   NAMES
    1a0f7c714c4b   my_website:1.1.1   "python3 my_website.…"   18 minutes ago   Up 18 minutes   0.0.0.0:80->8080/tcp, :::80->8080/tcp   my_website
    
    验证访问:
    [root@node2 ~]# curl http://192.168.44.135/						#访问网站,已经能正确访问了,谷歌浏览器访问也正常
    Being single is better than being in an unfaithful relationship.
    [root@node2 ~]# 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    【云计算赛项】职业技能竞赛--容器开发部分例题Pig快速开发框架
    Redis 大 key 要如何处理?
    图的关键路径(含多支交叉路径分离输出)
    浅谈6种流行的API架构风格
    分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )
    【iOS】—— 单例模式
    《剑指Offer》栈&队列全题——妙解思路,难度由浅入深
    【遗留】等待谁来帮助一下,webSocket的messagingTemplate跨域问题
    高等数学(第七版)同济大学 习题10-2(中5题) 个人解答
    机器学习day4
  • 原文地址:https://blog.csdn.net/MssGuo/article/details/126001887