『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

时间:2022-10-23 10:57:04

系列文章目录

本系列主要分为以下六大部分,正在更新中,尽请期待!

????点击关注本专栏


提示:已经更新的或正在更新的文章前面打勾了哈!


前言

到目前为止我们构建镜像的方法无疑是使用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来创建镜像呢?

接下来我带你手把手创建一个镜像,并且使用这个镜像创建容器且运行:

  1. 新建文件夹,用于专门存放dockerfile文件,并进入该文件夹
#创建文件夹
mkdir httpd -p;
#进入文件夹
cd httpd;

如下:

『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

  1. 下载centos:7镜像
docker pull centos:7

如下:

『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

  1. 编辑测试页面
vim index.html 
#页面内容
test page

如下:

『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

  1. 编辑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"]

如下:

『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

  1. 构建镜像
# v66是标签名
docker build -t httpd:v66 .
  1. 查看ID并且创建容器
docker images
docker run -itd -p 66:80 f3e5bafcdba6 

最后进行访问http://本机ip:66,如果看到一下界面说明你成功了!

『 云原生·Docker』Dockerfile是什么?如何使用 Dockerfile文件构建镜像?

那么我们如何才能撰写出高效的 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镜像在使用上一处修改代替大量更新的灵活之处。