前言
本讲是从Docker系列讲解课程,单独抽离出来的一个小节,重点介绍:Dockerfle基础命令和 Dockerfile的使用,提升自己的同时,希望对你也有所帮助。
概述
1.Dockerfile是什么
它是一个没有后缀名的文本文档,里面是组合镜像的一些命令,Docker build命令构建镜像时,通过读取Dockerfile中的指令的顺序(自上到下)自动生成镜像。
它的存在就好比自动驾驶技术中的导航功能(解放了驾驶员的双手)。
只需定义出发地、目的地,当然也可以定义更为详细行程路线。
2.Dockerfile怎么使用
语法: docker build -t -f Dockerfile目录 机构/镜像名<:tags>
注:Dockerfile如果是在当前目录,可不用-f指定;-t 构建镜像前自动检测dockerfile语法。
3.Dockerfile内容怎么定义
FROM tomcat:latest 用于设置基准镜像(在哪个镜像基础上,进一步扩展)
MAINTAINER succ.com 维护者(镜像所属团体)
WORKDIR /usr/local/tomcat/webapps 用于切换工作目录(如果不存在会自动创建)
ADD docker-web ./docker-web 将宿主机当前目录下的文件复制到容器内指定目录下
下面依次介绍8大核心命令的释义、用法示例,它们都是在Dockerfile中编写的,都是大写。
vim Dockerfile #这个文件没有后缀
一、FROM 指定基准镜像
指定当前镜像,以哪个镜像的哪个版本为依托,继续构建新的镜像。
语法
FROM <image> #仅指定镜像名称,不指定版本号(默认是latest版本)
FROM <image>:<tag> #指定镜像名称+版本号
FROM <image>@<digest> #指定镜像名称+校验序列号
注:#docker images --digests 获取镜像digests,当镜像内容发生变化时,digest也会随之变化。
FROM nginx
FROM nginx:1.18.0-alpine
FROM node:12.18.4-alpine@sha256:757574c5a2102627de54971a0083d4ecd24eb48fdf06b234d063f19f7bbc22fb
注意事项
如无特殊需求,我们一般会选择一个较为稳定,且体积比较小的alpine版本或者simp版本。
二、MAINTAINER& LABEL 描述性/说明信息
作用:增强镜像的阅读性,不会对功能造成影响,建议详细描述!
MAINTAINER 指明镜像的归属者或维护团体/机构名称/域名(仅此一份)
LABLE 更为详细的一些描述信息 (可有多份,且可以自定义)
#这里写了多份,仅为展示效果,实际只能有一份
MAINTAINER china.succ
MAINTAINER mayun
MAINTAINER mayun@qq.com
LABEL version = "1.0"
LABEL description="succ.edu"
LABEL createdate ="2022-05-01"
三、WORKDIR 设置工作目录
WORKDIR 设置的,目录需要是绝对路径,如果不存在,会自动创建。
在Dockerfile最外层首次出现,则是指明通过docker exec -it 进入容器内部后,默认进入的工作目录(无需再用cd命令切换)。
如果Dockerfile中命令比较多,需要来回切换工作目录,则可以随时再次定义新的WORKDIR
WORKDIR /usr/local
WORKDIR /usr/local/newdir #如果不存在会被自动创建,尽量使用绝对路径
四、ADD & COPY 将宿主机的文件上传到镜像中
区别和作用
add除了复制,还具备添加远程文件功能(文件以http://开头),类似于linux的wget
add是增强版的copy,add自带解压,copy不带解压。两者都支持目录中有空格。
注意事项
1、ADD指令不支持认证,从远程获取资源如果需要认证(交互),则只能使用RUN wget或RUN curl替代。
2、如果不是需要解压,优先使用COPY命令,效率更高、更节省资源。
ADD hello / #把hello从宿主机复制到容器内部的根路径
ADD test.tar.gz / #把压缩包从宿主机添加到容器的根目录后,自动解压
ADD hello . #把hello文件复制到当前workdir工作目录的根目录
COPY test.txt /etc/nginx #仅从宿主机复制文件到容器内部的指定目录
ADD demo.tar.gz /usr/share/nginx/html #复制文件,并自动解压到指定目录
命令解析: ADD (宿主机目录+)文件 空格 (容器内目录+)文件
宿主目录,默认是执行docker build时所在的宿主机目录 ;空格 ;示例中,后面的/是指容器内部跟目录,而 . 是容器内部的当前目录(默认是WORKDIR的目录)
五、ENV 设置环境常量
简单的说,它就是一个全局常量,被设置后,进入容器内部,在任意位置都可以访问这个常量的值,比如# echo $var_bl。
好比本地设置了JAVA_HOME环境变量一样,在CMD窗口任意目录,都可以打印/获取该常量。
ENV WORKPATH /tmp
ENV http_proxy ""
ENV JAVA_HOME /usr/local/openjdk8
ENV test=mayun-xiaoma
ENV mycat=mimi
RUN $JAVA_HOME/bin/java-jar test.jar
尽量使用环境常量,可提高程序维护性,如果JAVA_HOME需要调整为其他JDK版本,那么只需要调整一处位置即可,比如把/usr/local/openjdk8调整为jdk9。
注意:这些环境常量可以通过docker run命令的--env 或-e参数来进行修改。
六、RUN & CMD & ENTRYPOINT 运行指令
三者都是执行命令,但是它们的执行时机是不同的
RUN 仅在Build构建时执行的命令
CMD 用来设置容器启动后默认执行的命令(参数),它可被docker run后面的命令参数替换;
ENTRYPOINT 容器run启动时执行的命令
1.RUN 在生成镜像时需要执行的命令
#示例,演示run命令的两种不同写法
RUN yum install -y vim #Shell命令格式
RUN ["yum "," install" ,"-y","vim"] #Exec命令格式
Dockerfile中的RUN命令,只有在docker build 命令构建镜像时会自动运行,docker run的时候,并不会运行(注意,部分精简版的镜像,本身只提供最基础的linux命令比如vi,不自带vim)。
扩展:
1.shell运行方式
使用Shell执行时,当前shell是父进程,生成一个子shell进程。
在子shell中执行脚本。脚本执行完毕,退出子shell,回到当前shell。
子进程的退出,不会对父进程造成任何影响。
2.exec运行方式(官方推荐)
使用Exec方式,会用Exec进程替换当前进程,并且保持PID不变。执行完毕,直接退出,不会退回之前的进程环境
2.CMD用来设置容器启动后默认执行的命令(参数)
作用:可以单独使用,但不一定会被执行,也可作为其他命令的补充参数使用
dockerfile 中如果存在多个CMD指令,仅能保证最后一个生效。
在dockerfile 文件中,RUN后面可以包含CMD命令,此时它前面的CMD可能会被忽略。
CMD echo "YYDS"
ENTRYPOINT echo "Hello world"
ENTRYPOINT ["ps"]
CMD ["-ef"] #注:-ef 查看进程的完整格式,它不是一个单独的命令,而是ps后面跟的参数
注意:docker run命令末尾,可以添加参数覆盖Dockerfile中CMD的默认参数,更为灵活。
下面run命令带的参数-aux,优先级比较高,会覆盖上面CMD ["-ef"],相当于把它替换为CMD ["-aux"]
docker run nginx:run -aux
3.ENTRYPOINT 容器启动时需要执行的命令
与cmd类似,也是容器启动时需要执行的命令(注意:需提前给Dockerfile脚本,赋予执行权限 chmod +x Dockerfile),但是不会被启动容器时指定的命令覆盖,只会将指定的命令当做参数传递给Dockerfile中的entrypoint。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序,从而覆盖其他 ENTRYPOINT 指令指定的程序;
语法格式:
ENTRYPOINT <command> 或 ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
RUN ["echo","image building!!"]
CMD ["-c"]
ENTRYPOINT ["top","-b"]
最后一个enterpoint一定会被执行,cmd就不同了,不一定会被执行。
4.小结
1.CMD命令,在Dockerfile中,可以单独使用,但不一定会被执行,也可以作为enterpoint命令的一部分,作为参数使用。
2.ENTRYPOINT如果在Dockerfile中有多个,则仅最后一个会被运行。
3.如果在Dockerfile中即使用了ENTRYPOINT,也使用了CMD,两者会被合并执行,CMD可作为前者的默认参数使用
七、USER 指定运行容器时的用户名或 UID
Dockerfile指定USER用户后, 后续的命令 RUN、CMD、ENTRYPOINT 都将使用该用户
语法: USER <user>[:<group>] 或 USER <UID>[:<GID>]
##Dockerfile内容
FROM nginx:1.18.0-alpine
USER root
docker build . -t nginx:user #构建镜像
docker images 查看镜像列表
docker inspect nginx:user | grep User
八、EXPOSE声明对外暴露的端口
EXPOSE参数在Dockerfile中是可以不写(docker run -p时依然可以指定暴露端口),
为了规范化Dockerfile,让读者对其外暴露的端口一目了然,建议还是要写。
#docker run -d -p 8000:8080
8080 就是容器内对外暴露的端口,-p 极具灵活性。
#测试EXPOSE
FROM nginx:1.18.0-alpine
COPY 8080.conf /etc/nginx/conf.d
COPY index.html /usr/share/nginx
EXPOSE 8080
-p常见的有五种方式
1.宿主机随机端口,映射容器所有端口
#docker run -itd -P nginx /bin/bash 注意:这里是大写的P
2.宿主机随机端口,映射容器的指定端口
#docker run -itd -p 80 nginx /bin/bash 注:这个80是容器内的80端口
3.宿主机指定端口,映射容器指定端口(常用)
#docker run -itd -p 80:80 nginx /bin/bash
#docker run -itd -p 8080:80 nginx /bin/bash
#docker run -itd -p 443:443 nginx /bin/bash
#docker run -itd -p 80:80 -p 443:443 nginx /bin/bash
#docker run -itd -p 80:80 -p 443:443 --restart=always nginx
4.宿主机指定指定IP+端口、映射到容器指定端口
#docker run -itd -p 172.0.0.10:8080:80 nginx /bin/bash
5.宿主机指定IP+随机端口,映射容器指定端口
#docker run -itd -p 172.0.0.10::80 nginx /bin/bash
九、总结
通过vim Dockerfile,把内容编辑好了,怎么用呢?
首先,需要docker bulid -t -f Dockerfile路径,来构建镜像
然后,用docker run 来运行容器(镜像是死的,只读的,容器是活的,它建立在镜像之上)
最后,可以通过docker exec -it 进入容器内部
docker build . -t nginx:env #构建镜像
docker run -t --rm --name nginx-env nginx:env #启动容器
docker run -it --rm --name nginx-env nginx:env /bin/sh #启动容器,并进入容器内部
docker exec -it nginx:env /bin/bash #直接进入容器内部
echo $mycat #打印环境变量
mimi
exit 退#出容器,返回宿主机
注:--rm参数说明
在Docker容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据。
因此,可以通过--rm
命令,让容器在退出(被关闭)时,自动清除挂载的卷,以便清除数据。
还有两个次常用的命令,将会在后续,docker的高级应用K8s里陆续介绍。
VOLUME:容器数据卷(点击进入尝鲜)
ONBUILD:当构建一个被继承的dockerFile时的运行命令,父镜像在被子镜像继承后,父镜像的onbuild被触发
尾言
本讲内容是从 Docker入门到进阶里面抽离出来的内容,从而使原文更加有序、重点突出。希望对大家有所帮助,如果觉得还不错,动动小手,点赞表示支持一下吧。
附注
你还可能对以下内容感兴趣
1、如何获取Docker的最新版本 | 如何获取Tomcat/JDK/Nginx指定版本镜像