Dockerfile 简单来说就是一个包含用于组合镜像的命令的文本文档,Docker 通过读取 Dockerfile 中的指令就可以按步骤生成镜像,那么在制作镜像之前,我们先了解一下镜像的原理。

1、镜像原理

只有了解镜像的原理,我们才能更清晰的通过 Dockerfile 制作镜像。

前面几篇文章我们简单介绍了docker中的镜像,镜像是只读的文件,提供了运行程序完整的软硬件资源,是应用程序的“集装箱”,包含运行某个软件所需的所有内容,包括代码、运行时环境、所需库、环境变量、配置文件等等。

那么镜像是如何做到这些的呢?

1.1 UnionFS(联合文件系统)

联合文件系统(Union File System):2004 年由纽约州立大学开发,它可以把多个目录内容联合挂载到同一个目录下,而目录的物理位置是分开的。UnionFS可以把只读和可读写文件系统合并在一起,具有写时复制功能,允许只读文件系统的修改可以保存到可写文件系统当中。

UnionFS(Union File System) 一次性加载多个文件系统,但是从外表看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

1.2 Docker 镜像加载原理

Docker 的镜像实际上就是由一层一层的文件系统组成,这里给出 Docker 官方的一张图:

Bootfs(boot file system):主要包含 bootloader 和 kernel,bootloader 主要是引导加载 kernel,比如 Linux 刚启动时会加载 bootfs 文件系统,在 Docker 镜像的最底层就是 bootfs。这一层与我们典型的 Linux/Unix 系统是一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs。

Rootfs(root file system):在 bootfs 之上,中间只读的 rootfs 的集合称为 Docker 镜像,Docker 镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。UnionFS 使得镜像的复用、定制变得更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

Container(容器):容器 = 镜像 + 读写层,从文件系统上看,Docker容器比Docker镜像多一层可读写的文件系统挂载层。借助于 UnionFS,容器内部的更改都被保存到了最上面的读写层,而其他层都是只读的,这样中间的只读 rootfs 是可以被多个容器复用的。UnionFS 将文件的更新挂载到老的文件之上,而不去修改那些不更新的内容,这就意味着即使虚拟的文件系统被反复修改,也能保证宿主机空间占用保持一个较低水平。

在 rootfs 的基础上,Docker 公司创新性地提出了使用 UnionFS,多个增量 rootfs 联合挂载一个完整 rootfs 的方案,通过“分层镜像”的设计,围绕 Docker 镜像,大家甚至可以协同工作,再加上 Docker 官方提供的镜像仓库,进一步减少了共享镜像的成本,这大大提高了开发部署的效率。

这样你也能理解为什么 docker 启动块,占用资源少了吧。

1.3 实操理解分层概念

这里我们下载一个 Tomcat9.0 镜像:

我们也可以通过上一篇文章讲解的命令查看镜像层结构:

docker inspect 镜像id

2、Dockerfile 的 helloworld

实例:创建一个能访问 Tomcat 首页的容器

2.1 手动创建

通常我们启动一个Tomcat容器,官方镜像是简化版的,在webapps 目录下没有任何内容,所有我们启动之后访问主页也是没有任何内容。

docker run -d -p 8080:8080 tomcat

但是官方镜像的 webapps.dist 目录下有首页文件,所以我们将 webapps.dist 目录下的所有文件复制到 webapps ,然后访问首页就有界面了。

1、进入启动的容器

docker exec -it 容器id /bin/bash

2、将webapps.dist 目录所有文件复制到 webapps 目录下

cp -r webapps.dist/* webapps/

再次访问首页:

2.2 Dockerfile 创建

PS: 不同命令没关系,后面会解释每条命令含义。

①、提前准备好 webapps 目录文件

我这里直接将官方Tomcat容器中的 webapps.dist 目录拷贝到本机的/home/webapps 目录下:

docker cp 容器ID:/usr/local/tomcat/webapps.dist /home/webapps

②、准备 dockerfile 文件

在本机 /home 目录下新建一个 Dockerfile 文件(可以任意命名,没有后缀),内容如下:

FROM tomcat:latest
MAINTAINER itcoke
WORKDIR /usr/local/tomcat/webapps
COPY ./webapps/ /usr/local/tomcat/webapps/

③、构建镜像

docker build -f Dockerfile -t itcoke/mytomcat:1.0 .

④、运行镜像

docker run -d -p 8081:8080 itcoke/mytomcat:1.0

⑤、访问首页测试

可以看到如下图的首页界面,即构建运行成功。

3、Dockerfile 指令详解

在上面了我们编写了一个 Dockerfile 文件,内容如下:

FROM tomcat:latest
MAINTAINER itcoke
WORKDIR /usr/local/tomcat/webapps
COPY ./webapps/ /usr/local/tomcat/webapps/

那这里面每条指令是什么意思呢?接下来我们揭开这层神秘的面纱。

3.1 编写规范

①、每条指令(每行开头关键字)都必须是大写字母;

②、执行顺序是按照编写顺序从上到下;

③、# 表示注释;

3.2 常用指令介绍

①、FROM

FROM centos #依赖官方基准镜像(centos:lastest)

FROM scratch #不依赖任何基准镜像

FROM tomcat:9.0-jdk8-openjdk #指定具体版本号

②、MAINTAINER

通常表示镜像来自哪个机构。类似还有比如 LABEL 标签,展示镜像的一些说明信息,不会对镜像有实际影响。

LABEL version=“1.0”

LABEL description="初版xxx服务"

③、WORKDIR

WORKDIR 路径 # WORKDIR /usr/local

指定工作目录,也是我们进入镜像的路径,如果指定路径不存在,该指令也会自动创建该目录。

PS:尽量使用绝对路径,这样更加清晰。

④、ADD 和 COPY

都是进行文件复制。

ADD 功能更加强大一点,支持压缩包的解压,还支持远程文件的复制。

⑤、ENV

设置环境常量。

比如:

ENV JAVA_HOME /usr/local/openjdk8

RUN ${JAVA_HOME}/bin/java -jar test.jar

尽量使用环境常量,这样可以提高程序的可维护性。

3.3 RUN 和 CMD 和 ENTRYPOINT

RUN: 在镜像构建时执行命令,比如 RUN yum -y install vim;

ENTRYPOINT:容器启动时执行的命令;

CMD:容器启动后执行默认的命令或参数;

①、RUN

构建时运行,有两种命令格式:

RUN yum install -y vim #Shell 命令格式

RUN ["yum","install","-y","vim"] #Exec命令格式

官方推荐使用 Exec 命令格式。

②、ENTRYPOINT

容器启动时执行的命令。

命令格式也是推荐使用 Exec。

注意:Dockerfile 中只有最后一个 ENTRYPOINT 会被执行。

③、CMD

用于设置默认执行的命令。

和ENTRYPOINT 命令一样,也是只有最后一个 CMD 命令会被执行,但是如果容器启动时附加指令,则CMD会被忽略。

CMD ["ps","-ef"] #推荐使用 Exec 格式。

比如有如下Dockerfile 文件:

构建,然后启动时(不附加命令),会输出 3:

如果启动时附加命令,则会执行附加的命令(下图附加 ls 命令),而不执行Dockerfile 中的CMD 命令:

也就是说 ENTRYPOINT 指令一定会执行,但是 CMD 指令不一定会执行。

3.4 docker build 命令

编写好的 Dockerfile 通过 docker build 构建镜像。

docker build [OPTIONS] PATH | URL | -

①、-f:指定要使用的 Dockerfile 文件路径。

②、-t(-tag):镜像的名字和标签,通常是 name:tag。

4、Dockerfile 构建 centos

我们拉取官方的 centos 系统,发现是一个简化版的,常用的一些 vim 命令,ifconfig 命令都无法使用。

于是我们就编写一个Dockerfilew 文件来构建一个自己的 centos系统,有两个要求:

①、安装好vim以及一些网络命令;

②、设置工作目录为 /usr/local;

按照要求,我们在 /home 目录下新建 Dockerfile_MyCentos 文件,内容如下:

FROM centos
WORKDIR /usr/local
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo "install successful"
CMD /bin/bash

通过如下语句构建:

docker build -f Dockerfile_MyCentos -t mycentos:1.0 .

PS:对于构建命令,加入你新建的 Dockerfile 文件名称就是【Dockerfile】,那可以不加 -f 文件名 来指定,docker 会自动寻找。

构建成功后,就生成了自己的镜像:

我们运行这个镜像,发现这个centos 系统,vim,ifconfig 等网络命令都可以用了。

5、推送镜像到阿里云

上面我们镜像制作完成,如何推送到阿里云呢?

5.1 登录阿里云

https://cr.console.aliyun.com/cn-hangzhou/instances

5.2 创建命名空间

5.3 创建镜像仓库

测试阶段选择本地仓库就行。

5.4 推送操作指南

点开创建的镜像仓库,就会看到详细的操作指南。

看到第 3 点,将镜像推送到 Registry:

docker login --username=182****5732 registry.cn-hangzhou.aliyuncs.com
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/itcoke/test:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/itcoke/test:[镜像版本号]

第一条命令是登录阿里云,输入时需要在此输入密码,如果忘记密码了,可以到【访问凭证】里面重新设置。

第二条是设置 tag:

docker tag e10136600f85 registry.cn-hangzhou.aliyuncs.com/itcoke/test:1.0

第三条命令是推送到阿里云:

docker push registry.cn-hangzhou.aliyuncs.com/itcoke/test:1.0

查看阿里云镜像版本,也能看到我们推送过去的镜像信息:

点开【层信息】,里面的内容就是我们编写的 Dockerfile 相关信息。

6、从阿里云pull镜像

7、退出登录

docker logout

docker run -p 8082:8080 -it --name tomcat02 4b8ea0a44f9a /bin/bash

Docker从入门到精通(五)——Dockerfile的更多相关文章

  1. Python运算符,python入门到精通[五]

    运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算.例如:2+3,其操作数是2和3,而运算符则是“+”.在计算器语言中运算符大致可以分为5种类型:算术运算符.连接运算符.关系运算符.赋值运 ...

  2. docker 从入门到精通

    转载请注明出处!!!! 1.Docker 基本指令 下载镜像 docker pull 镜像名称:版本 查看已有镜像 docker images 查看已有容器 docker ps 启动docker do ...

  3. MyBatis从入门到精通(五):MyBatis 注解方式的基本用法

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 1. @Select 注解 1.1 使 ...

  4. docker从入门到精通再到放弃

    docker说明 docker三大功能:构建(build).运输(ship).运行(run),只需要记下这三大功能就可以了 1.docker入门 docker安装及配置 a.docker源配置 cur ...

  5. 《OD Docker实战》Docker从入门到精通

    一. 安装Docker http://wiki.jikexueyuan.com/project/docker-technology-and-combat/ https://mos.meituan.co ...

  6. Docker从入门到精通(六)——容器通信

    想要变成 Docker 的高阶玩家,搞懂 Docker 的容器通信是必不可少的. 1.需求 通常一个 Web 项目上线,我们会把开发完成的服务部署在Tomcat 服务器里面,然后需要的持久化数据会存放 ...

  7. Docker从入门到精通(八)——Docker Compose

    恭喜大家,学到这里,对于 docker 的基础玩法大家应该都会了,下面会介绍 docker的一些编排工具. 1.为什么需要 Docker Compose? 官网镇楼:https://www.runoo ...

  8. Docker从入门到精通

    1 容器简介1.1 什么是 Linux 容器1.2 容器不就是虚拟化吗1.3 容器发展简史2 什么是 Docker?2.1 Docker 如何工作?2.2 Docker 技术是否与传统的 Linux ...

  9. Docker从入门到精通(一)——初识

    1.Docker 是什么? Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容 ...

随机推荐

  1. Duboo整合SpringBoot超级详细例子(附源码)

    dubbo3.0整合SpringBoot例子 dubbo新版本(3.0以上)在相对于 dubbo 旧版本(2.5.2.6.2.7),有很多的不相同的地方. 官方文档也说了新版本的特性: https:/ ...

  2. Android——ViewHolder的作用与用法

    转载至:https://www.cnblogs.com/wugu-ren/p/6106379.htmlViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重 ...

  3. [cf566C]Logistical Questions

    记$d(x,y)$为$x$到$y$的距离,$cost_{x}=\sum_{i=1}^{n}w_{i}d(x,i)^{\frac{3}{2}}$为$x$的代价 取$C$为足够大量,对于一条边权为$w$的 ...

  4. [atAGC049F]Happy Sequence

    定义$L=2\cdot 10^{5}$,$g(x)=\sum_{i=1}^{n}|b_{i}-x|-|a_{i}-x|$,则合法当且仅当$\forall 0\le x\le L,g(x)\ge 0$, ...

  5. 从零开始,使用Dapr简化微服务

    序言 现有的微服务模式需要再业务代码中集成大量基础设施模块,比如注册中心,服务发现,服务调用链路追踪,请求熔断,重试限流等等,使得系统过于臃肿重量级. Dapr作为新一代微服务模式,使用sidecar ...

  6. mybatis源码分析二

    这次分析mybatis的xml文件 1. <?xml version="1.0" encoding="UTF-8" ?> <configura ...

  7. Yarp 让系统内调度更灵活

    简介 Yarp 是微软团队开发的一个反向代理组件, 除了常规的 http 和 https 转换通讯,它最大的特点是可定制化,很容易根据特定场景开发出需要的定制代理通道. 详细介绍:https://de ...

  8. 入坑 OI 249561092 周年之际的一些感想

    2018.2.10~2021.2.10 又是一年的 2 月 10 日,今天的到来意味着我 OI 生涯的第三年已经结束,即将开启 OI 生涯的第四年了.回顾这三年以来自己由懵懂.无知慢慢变成熟的历程,感 ...

  9. mount 挂载详解

    挂接命令(mount) 首先,介绍一下挂接(mount)命令的使用方法,mount命令参数非常多,这里主要讲一下今天我们要用到的. 命令格式:mount [-t vfstype] [-o option ...

  10. RepeatModeler安装及使用

    如果进行重复序列的预测,则使用RepeatModeler,可自身比对进行查找 安装 (1)下载地址:http://www.repeatmasker.org/RepeatModeler/ (2)Repe ...