带你了解docker是什么----基础原理篇(一)

容器是如何工作的?

docker的架构

docker的核心组件如下:

  • docker的客户端:client。我们最常用的客户端就是docker命令。
  • docker服务器:docker daemon ,一Linux后台服务的方式运行。运行在docker host 上,负责创建、运行、监控容器,构建、存储镜像。默认下,智能响应本地host的客户端的请求。
  • docker镜像:image
  • registry
  • docker容器:container

组件之间的联系如下图
在这里插入图片描述

docker采用的是client/server的架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。
客户端和服务器可以运行在同一个host上。(我们电脑中一般使用的就是这种情况),当然客户端也可以通过socket与远程的服务器通信。

docker 镜像

常用命令

  • docker images :查看镜像的信息
  • docker run -it dockerID :运行指定ID的docker 镜像
  • build :从 dockerfile 构建镜像
  • tag:给镜像打tag
  • pull : 从registry下载镜像
  • push:将镜像上传到registry
  • rmi:删除docker host 中的镜像
  • search : 搜索docker hub 中的镜像
  • images:显示镜像列表
  • history:显示镜像构建历史
  • commit :从容器创建新镜像

base 镜像

base镜像含义为:(1)不依赖其他镜像,从scratch构建;(2)其他镜像可以在该镜像基础上进行扩展。
通常情况下,能称为base镜像的是各种Linux发行版的docker镜像,如Ubuntu、centOS等

一般基础镜像会与我们实际的大小有所出入。比如一个centOS才200MB左右,当时平时我们按照一个centOS至少都有几个G。原因如下:

  1. Linux操作系统大致是由内核空间和用户空间组成。如下图,在这里插入图片描述
  2. 内核指的是一个提供设备驱动、文件系统、进程管理、网络通信等功能的系统软件,但一个内核并不是一套完整的操作系统,它只是操作系统的核心。一些组织或厂商将Linux内核与各种软件和文档包装起来,并提供系统安装界面和系统配置、设定与管理工具,就构成了Linux的发行版本
  3. 内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉。用户空间的文件系统是rootfs,包含我们熟悉的 /dev 、 /proc、/bin等目录。如下图在这里插入图片描述
  4. 对于base镜像来说,底层直接使用host的kernel,自己只需要提供rootfs就可以了。(所以这也就解释了按照docker的时候,对于Windows操作系统需要安装一下一个Linux的一个发行版)。而对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序就可以了。
  5. 不同Linux发行版的区别主要就是rootfs,因此docker可以同时支持多种Linux镜像。同时,这也从侧面反映了主流的Linux发行版的内核是兼容的。什么说呢?比如我们在docker中有多个不同发行版的Linux,但是host中只有Ubuntu 的一个内核,那么其实,这些在docker中的Linux镜像使用的都是这个host中的内核。

镜像的分层结构

docker支持通过扩展现有镜像,创建新的镜像。
下图为一个具体的例子:
在这里插入图片描述

  1. 首先,这么做的一个好处就是共享资源。 比如,有多个镜像都从相同的base镜像构建而来的,那么docker host 只需要在磁盘上保存一份base镜像;同时内存中也需要加载一份base镜像就可以为所有容器服务了。而且,镜像的每一层都可以被共享。
  2. 多个容器共享一份基础镜像,那么在修改的时候就需要进行一些技巧:在docker中使用的就是创建一个容器层。 所有对容器的改动,无论添加、删除,还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像都是只读的。

构建镜像

对于Docker用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成的Docker官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。
当然,有的情况下我们还是需要自己来创建镜像的。docker提供了两种创建镜像的方法:①docker commit 命令(命令行方式);②使用dockerfile 构建文件。一般使用的是后者,因此,这篇介绍的是后者。

dockerfile

dockerfile 是一个文本文件,记录了镜像创建的所有步骤。

下面列举例子来说明使用dockerfile来创建镜像的一些细节
一个dockerfile文件中的内容如下
在这里插入图片描述
运行docker build 命令构建镜像

root@ubuntu:~# pwd ①
​​​​/root
​​​​root@ubuntu:~# ls ②
​​​​Dockerfile
​​​​root@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile . ③
​​​​Sending build context to Docker daemon 32.26 kB ④
​​​​Step 1 : FROM ubuntu ⑤
​​​​---> f753707788c5
​​​​Step 2 : RUN apt-get update && apt-get install -y vim ⑥
​​​​---> Running in 9f4d4166f7e3 ⑦
​​​​......
​​​​Setting up vim (2:7.4.1689-3ubuntu1.1) ...
​​​​---> 35ca89798937 ⑧
​​​​Removing intermediate container 9f4d4166f7e3 ⑨
​​​​Successfully built 35ca89798937 ⑩
​​​​root@ubuntu:~#​​
  1. 当前目录为 /root。
  2. Dockerfile准备就绪。
  3. 运行docker build命令,-t将新镜像命名为ubuntu-with-vi-dockerfile,命令末尾的.指明build context为当前目录。Docker默认会从build context中查找Dockerfile文件,我们也可以通过-f参数指定Dockerfile的位置。
  4. 从这步开始就是镜像真正的构建过程。首先Docker将build context中的所有文件发送给Docker daemon。build context为镜像构建提供所需要的文件或目录。
    Dockerfile中的ADD、COPY等命令可以将build context中的文件添加到镜像。此例中,build context为当前目录 /root,该目录下的所有文件和子目录都会被发送给Docker daemon。
    所以,使用build context就得小心了,不要将多余文件放到build context,特别不要把 /、/usr作为build context,否则构建过程会相当缓慢甚至失败。(也即是说我们创建指定镜像的时候,指定的目录有正确)
  5. Step 1:执行FROM,将Ubuntu作为base镜像。
    Ubuntu镜像ID为f753707788c5。
  6. Step 2:执行RUN,安装vim,具体步骤为 ⑦ ⑧ ⑨。
  7. 启动ID为9f4d4166f7e3的临时容器,在容器中通过apt-get安装vim。
  8. 安装成功后,将容器保存为镜像。(底层类似docker commit 命令)
  9. 删除临时容器。
    10.镜像构建成功。

镜像的缓存特性

docker 会缓存已有镜像的镜像层,构建新镜像时候,如果某镜像层已经存在,就直接使用,无需重新创建。

dockerfile 中每一个指令都会依赖一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。 简单来说,看下面的两个文件,内容都是一眼的就是指令的顺序有所不同。
在这里插入图片描述

在这里插入图片描述
对于第一个dockerfile文件在创建的时候,由于前面两行命令得到的镜像与之前创建的相同因此,就会使用缓存中的镜像。而对于第二个就需要重新下载了。(因此,有时候指令的顺序也是我们考虑的一个要点)

dockerfile 构建镜像过程

  1. 从base镜像运行一个容器。
  2. 执行一条指令,对容器做修改。
  3. 执行类似docker commit的操作,生成一个新的镜像层。
  4. Docker再基于刚刚提交的镜像运行一个新容器。
  5. 重复2~4步,直到Dockerfile中的所有指令执行完毕。

从这个过程可以看出,如果Dockerfile由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,这对调试Dockerfile非常有帮助。我们可以运行最新的这个镜像定位指令失败的原因。

如下边的一个调试例子
dockerfile中的内容如下
在这里插入图片描述
执行docker build 后,结果如下

在这里插入图片描述
Dockerfile在执行第三步RUN指令时失败。我们可以利用第二步创建的镜像22d31cc52b3e进行调试,方法是通过docker run -it启动镜像的一个容器,如图3-31所示。
在这里插入图片描述
手工执行RUN指令很容易定位失败的原因是busybox镜像中没有bash。虽然这是个极其简单的例子,但它很好地展示了调试Dockerfile的方法。

dockerfile 常用指令

  1. form : 指定base镜像
  2. copy : 将文件 从build context 复制到镜像。支持两种格式:copy src dest 与copy [“srt”,“dest”] .src 只能指定build context 中的文件或目录
  3. add : 与copy 类似,从build context 复制文件到镜像。不同的是,如果src是归档文件(tar、zip),文件会自动解压到dest
  4. env : 设置环境变量
  5. volume : 将文件或目录声明为volume。
  6. workdir : 为后面的run 、 cmp 、add或copy 指令设置镜像中的当前工作目录
  7. run :在容器中运行指定的命令
  8. cmd : 容器启动时运行指定的命令, 可以有多个cmd指令,但是只要最后一个生效。
  9. maintainer : 设置镜像的作者

下面以一个较为详细地使用 dockerfile 文件来创建镜像来详细说明各个命令的作用
在这里插入图片描述
构建镜像,细节如下图

在这里插入图片描述

  1. 构建前确保build context中存在需要的文件。
  2. 依次执行Dockerfile指令,完成构建。(其中下一行显示,将相关的文件传输到服务器)

运行容器,验证镜像内容,如图所示。
在这里插入图片描述

① 进入容器,当前目录即为WORKDIR。
如果WORKDIR不存在,Docker会自动为我们创建。
② WORKDIR中保存了我们希望的文件和目录:
目录bunch:由ADD指令从build context复制的归档文件bunch.tar.gz,已经自动解压。(这就像我们智能解压压缩包一样,得到的是一个压缩包名字的文件夹)
文件tmpfile1:由RUN指令创建。
文件tmpfile2:由COPY指令从build context复制。
③ ENV指令定义的环境变量已经生效。

dockerfile 支持以“#”开头的注释

RUN 、CMD和ENTRYPOINT

RUN、CMD和ENTRYPOINT这三个Dockerfile指令看上去很类似,很容易混淆。这里就详细讨论它们的区别。
简单地说:
(1)RUN:执行命令并创建新的镜像层,RUN经常用于安装软件包。
(2)CMD:设置容器启动后默认执行的命令及其参数,但CMD能够被docker run后面跟的命令行参数替换。
(3)ENTRYPOINT:配置容器启动时运行的命令。

一、 RUN

RUN指令通常用于安装应用和软件包。

RUN在当前镜像的顶部执行命令,并创建新的镜像层。dockerfile 中常常包含多个RUN指令

下面为使用RUN安装多个包的例子:

RUN apt-get update && apt-get install-y\bzr\cvs\git\mercurial\
​​​​subversion​​

apt-get update 和apt-get install 被放在一个RUN指令中执行,这样能够保证每次安装的是最新的包。如果apt-get install 在单独的RUN中执行,则会使用apt-get update 创建镜像层,而这一层可能是很久之前缓存的了。

二、 CMD

CMD 指令允许用户指定容器的默认执行命令。

此命令会在容器启动且docker run 没有指定其他命令时运行。

  • 如果docker run 指定了其他命令,cmd 指定的默认命令将被忽略。
  • 如果有多个CMD指令,则只有最后一个有效。

shell 和Excel 格式

我们可以用两种方式指定RUN、CMD和ENTRYPOINT要运行的命令。

一、Shell 格式:<instruction><command>
例如:

RUN apt-get install python3
​​​​CMD echo "Hello world"
​​​​ENTRYPOINT echo "Hello world"​​

当指令执行时,shell格式底层会调用 /bin/sh -c [command]

二、Excel 格式:<instruction> ["executable", "param1", "param2", ...]​​
例如:

​​​​RUN ["apt-get", "install", "python3"]
​​​​CMD ["/bin/echo", "Hello world"]
​​​​ENTRYPOINT ["/bin/echo", "Hello world"]​​

当指令执行时,会直接调用 [command],不会被shell解析。

CMD和ENTRYPOINT推荐使用Excel格式,因为这样指令可读性更强。RUN则两种方式都可以。

分发镜像

分发镜像指的是如何在多个docker host 上使用镜像。

有以下几种可用的方法:

  1. 用相同的dockerfile 在其他host 构建镜像。
  2. 将镜像上传到公共registry,host 直接下载使用。
  3. 搭建私有的registry供本地host 使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值