本文转载自微信公众号「小郎码知答」,作者郎同学。转载本文请联系小郎码知答公众号。
前言
hello,大家好 ,我是郎同学,一个想要每天博学一点点的小青年。
最近几天,项目超忙,忙什么呢,一方面是忙着项目的第三轮发测,另一方面是忙着给项目组的后端服务上云,作为一名后端开发工程师,写了一周的Shell脚本,哎呀,那个酸爽哦,我还想在回味一次。
最令我恶心的是,公司自研的容器云平台一点都不稳定(听说容器云小组要把底层语言java转成Go,导致近一段时间都不怎么维护容器云平台了)。在容器云平台构建镜像时常常因为拉取jar包超时而导致构建失败,当我好不容易构建完成,最终来到各类应用服务,中间件编排时,还需要对各类依赖关系、端口、IP一一进行环境变量的配置,真的是欲仙欲死,欲罢不能。
但是,经过这次项目,我的shell编程能力达到了前所未有的高度(虽然在外人眼中依旧很菜)。
写的最多无非是Dockerfile,以前总觉得Dockerfile构建镜像很牛逼,写多了就发现来来回回那几个命令,难的是shell编程中的反人类语法,今天下班早,我就总结下Dockerfile的知识点,希望可以帮助到大家。
1、Dockerfile原理
在学习Dokcerfile前,我们需要了解下Dockerfile、Docker镜像及Dcoker容器间的关系。
容器化
Docker的核心思想就是将应用容器化。
应用容器化通常分为以下几个步骤:
(1)编写应用代码
(2)编写Dokcerfile脚本,该脚本包含当前应用的描述、依赖以及该如何运行这个应用
(3)对Dockerfile脚本执行docker image build命令,构建镜像
(4)构建完成的镜像被使用,完成容器化的过程
因此,编写优秀的Dockerfile文件对构建镜像必不可少。
DockerFile是由一系列命令和参数,用以构建docker镜像的文件,docker能够读取Dockerfile指定的指令自动构建,从上到下的每一个指令都会创建一个镜像层,即镜像都是多层叠加而成,因此,层越多,效率越低,创建镜像,层越少越好。因此能在一个指令完成的动作尽量通过一个指令定义。
在Dokcerfile编写指令的过程中,需要先确定制作镜像的目录,即包含Dockerfile文件所在的目录通常称为构建上下文。
NOTE:Dockerfile文件必须以字母D开头。
下面,就让我们在学习Dockerfile命令过程中理解镜像的构建。
2、Dockerfile常用命令
我们先看一个Dockerfile的指令表
指令 | 作用 |
---|---|
FROM | 构建镜像使用的基础镜像 |
MAINTAINER | 设置镜像的作者 |
RUN | 编译镜像时需要运行的指令 |
CMD | 镜像的启动命令 |
LABEL | 设置镜像的启动标签 |
EXPOSE | 设置镜像暴露的端口 |
ENV | 设置容器的环境变量 |
ADD | 编译镜像时复制文件到镜像中 |
COPY | 编译镜像时复制文件到镜像中(与ADD命令有区别) |
ENTRYPOINT | 容器的入口程序 |
VOLUME | 设置容器的挂载卷 |
USER | 执行命令的用户名 |
WORKDIR | 进入容器的目录 |
ARG | 编译镜像时加入的参数 |
指令看起来很多,其实理解起来并不难,下面,我们对这些指令一一作出解释
2.1 FROM
每个Dockerfile文件的第一行都是FROM指令,FROM指令指定的镜像都会作为当前镜像的基础镜像层。
使用格式:
- FROM <image> #默认最新版的镜像
- FROM <image>[:<tag>] #指定tag版本镜像
- FROM <image>[@<digest>] # 使用加密后的摘要获取镜像
2.2 MAINTAINER
该指令用于确定维护该镜像的作者信息
使用格式为:
- MAINTAINER <name>
目前这个指令已经废弃了,可以使用指令LABEL
- LABEL user="simon" key2="value2"
多个信息可以使用多个键值对表示
2.3 RUN
RUN命令为构建镜像时指令的命令
使用格式:
- RUN <command>
- RUN ["executable", "param1","param1"]
第一种格式在在shell终端中运行,即/bin/sh -c(默认);
NOTE: bash与bash -c
bash -c后面接执行的命令
bash后面接可执行的脚本
第二种格式类似于函数调用,可以将executable理解为可执程序,后面就是两个参数
举个例子:
- RUN yum install -y vim
- RUN ["/bin/bash","-c","yum install -y vim"]
每条RUN指定将在当前镜像基础上执行指定命令,并提交为新的镜像,当命令较长时,可以使用\来换行
2.4 CMD
CMD命令为容器启动时要运行的命令
使用格式:
- CMD ["executable","param1","param2"]
- CMD ["param1","param2"]
- CMD command param1 param2
第一种格式和第二种格式都是在可执行程序加上参数形式
举例
- CMD [ "bash", "-c, "jav -jar demo_application.jar"]
- CMD [ "java -jar", "demo_application.jar" ]
第三种比较简单
- CMD Java -jar demo_application.jar
2.5 LABEL
LABEL为镜像指定标签
- LABEL <key>=<value> <key>=<value> <key>=<value> ...
我们经常使用LABEL指令代替MAINTAINER指令
2.6 EXPOSE
EXPOSE是暴露容器运行时的端口,但是EXPOSE并不会使容器访问主机的端口,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数。
使用格式:
- EXPOSE 8848 #NACOS
- EXPOSE 8070 #APOLLO
2.7 ENV
ENV是设置环境变量,以便在脚本中使用
使用格式:
- ENV <key> <value>
- ENV <key>=<value> ..
2.8 ADD
ADD是复制命令,将Dockerfile上下文目录中文件/路径复制容器的指定目录中
使用格式:
- ADD <src>... <dest>
- ADD ["<src>",... "<dest>"]
src指的是的上下文目录下的文件,dest指的是容器中的路径
NOTE:
当复制一个压缩文件时,使用ADD指令可以自定解压
ADD可以复制url到容器中
2.9 COPY
COPY类似于ADD,拷贝文件和目录到容器中,它可以从构建上下文目录中<原路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
使用格式:
- COPY src dest
- COPY ["<src>",... "<dest>"]
2.10 ENTRYPOINT
ENTRYPOINT和CMD指令类似,都是在容器启动时执行
使用格式:
- ENTRYPOINT ["executable", "param1", "param2"]
- ENTRYPOINT command param1 param2
2.11 VOLUME
VOLUME指令实现挂载功能,用于定义容器运行时可以挂载到宿主机的目录
使用格式:
- VOLUME ["/data"]
2.12 USER
USER设置启动容器的用户
使用格式:
- USER simon gsimon
simon为用户,gsimon为用户组
2.1.3 WORKDIR
WORKDIR设置容器内的工作目录,当创建容器后,终端默认登录进来的工作目录。
使用格式:
- WORKDIR /path/to/workdir
3、一个简单的Dockerfile文件实例
3.1 编写Dockerfile文件
- # 基于哪个镜像
- From java:8
- #暴露端口
- EXPOSE 8080
- #创建工作目录
- RUN mkdir -p /com/simon/study
- # 复制文件到容器
- ADD target/demo_application.jar /com/simon/study
- #进入工作目录
- WORKDIR /com/simon/study
- # 配置容器启动后执行的命令
- ENTRYPOINT ["java","-jar","demo_application.jar"]
3.2 使用docker build命令构建镜像
- docker build -t demo_application:v1.0
docker build -t 镜像名称:标签 ,使用-t选项指定了镜像的标签。
3.3 启动镜像
- docker run -p 8080:8080 demo-application:v1.0
4、总结
这篇文章只是简单的介绍了Dockerfile的使用,并没有针对上云做具体的介绍。事实上,编写上云脚本不仅仅只是编写Dockerfile,它还会牵扯到其它的脚本配合使用,与其它脚本相比,Dockerfile算是很简单的了,因为其它脚本还要编写大量的中间件的环境变量,用户/目录的授权,SSL证书的检测等等。
如果对上云感兴趣的同学,可以私信我,相信我能帮助到你!