当前位置: 首页 > news >正文

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

系列文章目录

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

  • 『 云原生·生之门』
  • 『 云原生·前置知识』
  • 『 云原生·Docker』
  • 『 云原生·Kubernetes』
  • 『 云原生·KubeSphere』
  • 『 云原生·DevOps』

🚩点击关注本专栏


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

文章目录

  • 系列文章目录
  • 前言
  • 一、初识Dockerfile
  • 二、Dockerfile的基本指令
    • 1.配置指令
    • 2.操作指令
  • 三、使用Dockerfile创建镜像
  • 总结


前言

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

如下:

在这里插入图片描述

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

如下:

在这里插入图片描述

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

如下:

在这里插入图片描述

  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"]

如下:

在这里插入图片描述

  1. 构建镜像
# v66是标签名
docker build -t httpd:v66 .
  1. 查看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镜像在使用上一处修改代替大量更新的灵活之处。

相关文章:

  • 【嵌入式数据库】一文带你吃透通过apiBaseUrl获取FlexManager监控点数据
  • XTTS基于rman全量迁移Oracle
  • [LeetCode]-使用特殊算法的题目-2
  • 比较CPU和GPU中的矩阵计算
  • 【数据结构】树形结构——线索二叉树
  • 突如其来的第一个1024要笑着过
  • 2022年都快结束了,Java的这些新技术、热门技术,你不会还不知道吧?
  • 【Linux】Linux文件权限的理解
  • 力扣(LeetCode)2008. 出租车的最大盈利(C语言)
  • 【正点原子I.MX6U-MINI应用篇】5、嵌入式Linux在LCD上显示BMP、JPG、PNG图片
  • 四非到保研厦大,我们还有多少路要走----技术人的保研之路
  • 美团Leaf分布式ID源码启动部署
  • 归一化小程序
  • 走过岁月我才发现——云IDE真方便(Python3.8环境测试)
  • SpringBoot核心技术 之 基础入门
  • angular2 简述
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • express如何解决request entity too large问题
  • iOS 颜色设置看我就够了
  • Java 多线程编程之:notify 和 wait 用法
  • JAVA_NIO系列——Channel和Buffer详解
  • Java的Interrupt与线程中断
  • SegmentFault 2015 Top Rank
  • ViewService——一种保证客户端与服务端同步的方法
  • 初识MongoDB分片
  • 从重复到重用
  • 对象管理器(defineProperty)学习笔记
  • 实习面试笔记
  • 双管齐下,VMware的容器新战略
  • 一文看透浏览器架构
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • const的用法,特别是用在函数前面与后面的区别
  • 湖北分布式智能数据采集方法有哪些?
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​Python 3 新特性:类型注解
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • ​香农与信息论三大定律
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #define
  • #include<初见C语言之指针(5)>
  • #QT(智能家居界面-界面切换)
  • (12)Linux 常见的三种进程状态
  • (2)(2.10) LTM telemetry
  • (23)Linux的软硬连接
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (简单) HDU 2612 Find a way,BFS。
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (三)终结任务
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • .NET 发展历程
  • .netcore 获取appsettings