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有区别。

各个指令详细介绍如下:

FROM mysql:5.6
说明:FROM指令用来指定基础镜像信息,FROM必须为第一个指令,tag是可选的,如果不写tag,会使用latest版本的基础镜像,alpine、busybox镜像
一般可以作为基础镜像。

MAINTAINER Benjamin Yang <[email protected]>	
说明: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指令,仅最后一个生效。

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 ~]# 

你可能感兴趣的:(docker,docker,java,容器)