系列文章目录
本系列主要分为以下六大部分,正在更新中,尽请期待!
- 『 云原生·生之门』
- 『 云原生·前置知识』
- 『 云原生·Docker』
- 『 云原生·Kubernetes』
- 『 云原生·KubeSphere』
- 『 云原生·DevOps』
提示:已经更新的或正在更新的文章前面打勾了哈!
前言
到目前为止我们构建镜像的方法无疑是使用docker commit
命令基于已有镜像的容器来构建镜像,但是这样的缺点也很明显。
使用docker commit
命令创建容器时所有操作都是在容器内部进行的,其他人或者自己在较长时间后也不知道这个镜像是怎么做出来的,并且我们需要在容器内操作麻烦,效率低,不灵活。
所以我们一般推荐使用Dockerfile来创建镜像。
一、初识Dockerfile
Dockerfile文件本质是一个文本格式的配置文件,用户可以使用 Dockerfile 来快速创建自定义的镜像。
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言, Dockerfile主体内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
- 基础镜像:由FROM基础镜像这个命令来使用,标志着我们定制的镜像是以哪个镜像作为基础进行制作的;
- 维护者信息:这里要写上Dockerfile编写者的信息,一般写上自己的邮箱或者nickname就可以,用法是LABEL maintainer=“个人信息”;
- 镜像的操作命令:当我们需要定制一个镜像的时候,肯定是要运行一些命令(安装一些依赖,修改一些配置等等)来对基础镜像做一些修改的,一般使用RUN 具体命令来操作;
#正确的做法
bash RUN apt-get update && apt-get install vim,
#不提倡的做法
bash RUN apt-get update RUN apy-get install vim
- 容器启动时执行的命令: 需要用CMD来执行一些容器启动时的命令,注意与RUN的区别,CMD是在 docker run 执行的时候使用,而RUN则是在docker build 的时候使用。
接下来我们结合一个Dockerfile的例子来看看它的结构:
#========基础镜像==========
# Docker file for Hexo 3
FROM ubuntu:16.04
#=========维护者信息==========
MAINTAINER MUNGO
#=======镜像的操作命令========
# use aliyun's mirror for faster download speed
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# add pandoc repository
RUN sed -i 's/deb mirror.lupaworld.com/ubuntu vivid main universe/g' /etc/apt/sources.list
# instal basic tool
RUN apt-get update && \
apt-get install -y nodejs curl git-core pandoc yui-compressor && \
update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10 && \
curl -L https://npmjs.org/install.sh | sh && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV HEXO_VERSION 3.0.0
# install hexo
RUN npm install -g hexo@${HEXO_VERSION}
# set base dir
RUN mkdir /hexo
# set home dir
WORKDIR /hexo
EXPOSE 4000
#=========容器启动时执行的命令===============
CMD ["/bin/bash"]
在这个例子中可以清晰的看到Dockerfile主体内容是由四部分组成的。
二、Dockerfile的基本指令
1.配置指令
FROM
功能是指定所创建镜像的基础镜像,并且必须是第一条指令。如果在同一个 Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次),如下:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
如果不以任何镜像为基础,那么写法为: FROM scratch
,同时意味着接下来所写的指令作为镜像的第一层开始。
ARG
功能是定义创建镜像过程中使用的变量,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg <varname>=<value>
来指定参数,如下:
#定义变量key1
ARG key1
#定义变量key2,并赋默认值value2
ARG key2=value2
ENV
指定环境变量,在镜像生成过程中会被后续RUN 指令使用,在镜像启动的容器中也会存在。使用语法如下:
#一次设置一个变量
ENV <key> <value>
ENV <key>=<value>
#一次设置多个变量
ENV <key1>=<value1> <key2>=<value2> ..
EXPOSE
功能是声明镜像内服务监听的端口。注意该指令只是起到声明作用,并不会自动完成端口映射。
#设置监听端口为80
EXPOSE 80/tcp
如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上-P
参数
ENTRYPOINT
功能是指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。使用格式如下:
#类似于函数调用,可将executable理解成为可执行文件,后面就是两个参数。
ENTRYPOINT ["executable","param1","param2"]
#后面直接跟shell命令
ENTRYPOINT command param1 param2
每个 Dockerfile中只能有一个 ENTRYPOTNT
,当指定多个时只有最后一个起效。
VOLUME
功能是创建一个数据卷挂载点。运行容器时可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保持的数据等。使用格式如下:
VOLUME ["/data"]
一般的使用场景为需要持久化存储数据时。
USER
功能是设置启动容器的用户,可以是用户名和UID,使用格式如下:
#用户名
USER username
#UID
USER UID
当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在 Dockerfile中创建所需要的用户。
2.操作指令
RUN
功能是运行指定命令。每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。当命令较长时可以使用 \ 来换行。使用格式为:
#后面直接跟shell命令
RUN <command>
#类似于函数调用,可将executable理解成为可执行文件,后面就是两个参数。
RUN ["executable","param1","param2"]
RUN的默认权限是sudo
。需要注意的是,如果你需要执行多个RUN操作,那最好把它们合并在一行 (用&&连接),因为每执行一次RUN就会在docker上新建一层镜像,所以分开来写很多个RUN的结果就是会导致整个镜像无意义的过大膨胀;
CMD
功能是指定启动容器时默认执行的命令。使用格式如下:
#类似于函数调用,可将executable理解成为可执行文件,后面就是两个参数
CMD ["executable","param1","param2"]
#与第一种类似,可执行文件+参数
CMD ["param1',"param2"]
#shell这种执行方式和写法
CMD command param1 param2
参数一定要用双引号,千万不能写成单引号。原因是参数传递后,docker解析的是一个JSON数组。
并且每个 Dockerfile只能有一条CMD命令,如果指定了多条命令只有最后一条会被执行。
关于RUN和CMD:
-
RUN
是构容器时就运行的命令以及提交运行结果; -
CMD
是容器启动时执行的命令,在构建时并不运行,构建时仅仅指定了这个命令到底是个什么样子;
ADD
功能是添加内容到镜像,如果是压缩文件,则会自动进行解压。使用格式如下:
#<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径
#<src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url
ADD <src> <dest>
ADD ["<src>","<dest>"]
COPY
复制内容到镜像,COPY的<src>
只能是本地文件,而且不能自动解压。使用格式如下:
COPY <src> <dest>
COPY ["<src>","<dest>"]
将文件作为一个新的层添加到镜像中。通常使用 COPY 指令将应用代码赋值到镜像中。
三、使用Dockerfile创建镜像
对Dockerfile进行基本的学习之后,那么我们怎么样才能使用Dockerfile来创建镜像呢?
接下来我带你手把手创建一个镜像,并且使用这个镜像创建容器且运行:
- 新建文件夹,用于专门存放dockerfile文件,并进入该文件夹
#创建文件夹
mkdir httpd -p;
#进入文件夹
cd httpd;
如下:
- 下载centos:7镜像
docker pull centos:7
如下:
- 编辑测试页面
vim index.html
#页面内容
test page
如下:
- 编辑dockerfile文件
vim dockerfile
#文件内容
#使用centos:7 镜像
FROM centos:7
#执行的安装命令
RUN yum install httpd -y
#声明端口
EXPOSE 80
#拷贝网页文件
COPY index.html /home/myroot/httpd/index.html
#前台执行命令
CMD ["/home/myroot/httpd","-D","FOREGROUND"]
如下:
- 构建镜像
# v66是标签名
docker build -t httpd:v66 .
- 查看ID并且创建容器
docker images
docker run -itd -p 66:80 f3e5bafcdba6
最后进行访问http://本机ip:66
,如果看到一下界面说明你成功了!
那么我们如何才能撰写出高效的 Dockerfile呢?
- 精简镜像用途:尽量让每个镜像的用途都比较集中单一,避免构造大而复杂、多功能的镜像;
- 选用合适的基础镜像:容器的核心是应用,选择过大的父镜像(如 Ubuntu系统镜像会造成最终生成应用镜像的臃肿,推荐选用瘦身过的应用镜像(如node:s1im);
- 提供注释和维护者信息:Dockerfile也是一种代码,需要考虑方便后续的扩展和他人的使用;
- 减少镜像层数:如果希望所生成镜像的层数尽量少,则要尽量合并RUN、ADD和COPY指令。通常情况下,多个RUN指令可以合并为一条RUN指令;
- 使用. dockerignore文件:使用它可以标记在执行
docker build
时忽略的路径和文件,避免发送不必要的数据内容,从而加快整个镜像创建过程。 - 及时删除临时文件和缓存文件:特别是在执行apt-get指令后,
/var/ cache/apt
下面会缓存了一些安装包; - 提高生成速度:如合理使用 cache,减少内容目录下的文件,或使用
. dockerignore
文件指定等; - 调整合理的指令顺序:在开启 cache的情况下,内容不变的指令尽量放在前面,这样可以尽量复用;
- 减少外部源的干扰:如果确实要从外部引入数据,需要指定持久的地址,并带版本信息等。让他人可以复用而不出错;
看看本专栏文章有哪些吧!
本系列文章目录:
- 『 云原生·生之门』
- 『 云原生·前置知识』
- 『 云原生·Docker』
- 『 云原生·Kubernetes』
- 『 云原生·KubeSphere』
- 『 云原生·DevOps』
可以看出来本系列文章将会带你从-1到1的学习云原生的,一起加油吧!
总结
本篇我们一起学习了Dockerfile的相关知识,在使用Dockerfile构建镜像的过程中,我们可以体会到 Docker镜像在使用上一处修改代替大量更新的灵活之处。