老公趴下!62图给你讲Docker

第一趴---Docker容器圈简介                                               Docker容器圈简介 第二趴---Docker基本操作                                         

第一趴---Docker容器圈简介

attachments-2021-03-Do5fxYX3605718d75427d,png

                                                                                                     Docker容器圈简介

第二趴---Docker基本操作

attachments-2021-03-jrJDjteT605718ea3fa7c,png

                                                                                     Docker基本操作                              

容器圈

容器这个新生事物,现在还可以说是新生事物吗?对于我们学生而言,我觉得没毛病,你说呢?

容器技术可说重塑了整个云计算市场的形态,带动了一批年轻有为的容器技术儿,不过「容器」这个概念是 Docker 公司发明的么,不是,它只是众多 Pass 项目中的最底层,没人关注的那一部分而已。

什么是Pass项目?

Pass 项目之所会被很多公司所接受,自然是因为解放了部分开发人员的劳动力,尽快干玩活儿早点下班。其依赖的就是「应用托管」的能力,在电脑上斗过地主的应该知道,托管了以后就会自动出牌,同样的道理,为了尽量的弥补本地和云上的环境差异,就出现了 Pass 开源项目。

举个例子来说,运维人员小仙云上部署一个 Cloud Foundry 项目,开发人员只需要简单的一行代码就可以实现将本地的应用部署到云上

attachments-2021-03-kZHByMcv60571b23d240f,png

就这样一行代码就实现了将本地应用上传到云上,属实很轻松。

那么这个命令执行的基本原理是怎样的?

实际上,我们可以将其最核心的组件理解为一套应用的打包分发机制。云上部署的 Cloud Foundry 会为大部分编程语言定义一种打包的格式,当开发人员执行命令的时候,实际上是将可执行文件启动脚本打包上传到云上的Coulud Foudry 中,然后 Cloud Foundry 通过相应的调度器选择一个虚拟机的 Agent 将压缩包下载后启动

那如何区分虚拟机中的不同应用呢?

虚拟机一般不可能只跑一个应用,因为这样确实也太浪费资源了,我们可以想想,现在手上的电脑,可以用 Vmvare 导入几个虚拟机,所以诸如 Cloud Foundry 通过引入操作系统的 Cgroups 和 Namespace 等机制,从而来为每个应用单独创建一个叫做「沙盒」的隔离环境,然后在这些「沙盒」中启动应用,通过这样的方法就让虚拟机中应用各自互不干扰,让其自由翱翔,至于 Cgroups 和 **Namespace **的实现原理,后续我们再共同的探讨

这里所谓的隔离环境就是「容器」。

那 Docker 和这 Pass 项目的 Cloud Foundry 的容器有啥不一样?

自然不一样,不然现在我们一旦提到容器,想到的不会是 Docker,而是 Cloud Foundry 了吧。Cloud Foundry 的首席产品经理就觉得没什么,毕竟自己放的屁都是香的!

不一样,而且当时还发了一份报告,报告中还写到:“ Docker 不就是使用了  Cgroups  和  Namespace  实现的「沙盒」而已,不用过于关注”。

没想到的是,随后短短的几个月,Docker 项目迅速起飞以至于其他所有  Paas  社区都还没来及反应过来,就已经宣告出局

什么魔力让 Docker 一发不可收拾?

就是提出了镜像的概念。上面我们说过,Paas  提供的一套应用打包的功能,看起很轻松省事,但是一旦使用了Paas,你就要终身服务于它,毕竟他是提供商,是「爸爸」,用户需要为每个版本,每种语言去维护一个包,这个打包的过程是需要多次的尝试,多次试错后,才能摸清本地应用和远端 Paas 的脾气,从而顺利部署。

而 Docker 镜像恰恰就是解决了打包这一根本问题。

什么是Docker镜像?

Docker 镜像也是一个压缩包,只是这个压缩包不只是可执行文件,环境部署脚本,它还包含了完整的操作系统。因为大部分的镜像都是基于某个操作系统来构建,所以很轻松的就可以构建本地和远端一样的环境。

这就很牛皮了,如果我们的应用是在 Centos7 上部署,我们只需要将项目环境部署在基于 Centos7 的环境中,然后无论在哪里去解压这个压缩包,都可以保证环境的一致性。在整个过程中,我们根本不需要进行任何的配置,因为这个压缩包可以保证:本地的环境和云端是一致的,这也是 Docker 镜像的精髓

开发者体验到了 Docker 的便利,从而很快宣布 Paas 时代的结束,不过对于大规模应用的部署,Docker 能否实现在当时还是个问号

就在 2014 年的 DockerCon 上,紧接着发布了自研的「Docker swarm」,Docker 就这样 一度奔向高潮,即将就到达了自己梦想之巅。

为什么会推出Docker Swarm?

虽然 Docker 通过「容器」完成了对 Paas 的「降维打击」,但是 Docker 的目的是:如何让更多的开发者将项目部署在自己的项目上,从技术,商业,市场多方位的争取开发者的群体,为此形成自家的  Paas 平台做铺垫

Docker 项目虽然很受欢迎,就目前看来只是一个创建和启动容器的小工具。需要应该清楚的一点是,用户最终部署的还是他们的网站,服务甚至云计算业务。所以推出一个完整的整体对外提供集群管理功能的 Swarm 势在必行,这个项目中的最大亮点即直接使用了 Docker 原生的 API 来完成对集群的管理。

对于单机项目,只需要执行下面一条语句即可实现容器

attachments-2021-03-LCYJUqTb60571b5c97ed8,jpg

对于多机的项目,只需要执行

attachments-2021-03-68wiu8KX60571b7e0d71e,jpg

你看,从单机切换到多机,使用的方法也就参数不同而已,所以这样一个原生的「Docker容器集群管理」一发布就受到大家的青睐。随着自身生态的逐渐完善,借助这一波浪潮并通过各种并购来强大自己的平层能力

要说最成功的案例,非 Fig 项目莫属。之所以这么屌,是因为作者提出了「容器编排」的概念。

什么是容器编排?

其实这也不是什么新鲜内容,比如在 Linux 中的 Makefile和常见的 SHELL 脚本,它是一种通过工具或者配置来完成一组虚拟机或者关联资源的定义、配置、创建等工具。

容器的编排是怎么样的呢

我们先以 Fig 为例,假设开发人员小黑,现在要部署一个项目,其中包含了应用容器 A,数据库容器 B,负载容器 C,这个时候 Fig 只需要将三个容器定义在一个配置文件,然后指定他们的关联关系,执行下面的命令即可

attachments-2021-03-jOj9IbFr60571ba771e1e,png

当然也可以在 Fig 的配置文件中配置各种容器的副本,然后加上 Swarm 的集群管理功能,这样不就是 Paas 了么。只是这个项目被收购以后,修改名字为 compose 了,后续也会的 compose 进行详细的阐述

就这样一个以「鲸鱼」为商标的 Docker,火遍全球,因为它秉持将「开发者」群体放在食物链的顶端。一分钟实现网站的部署,三分钟搭建集群,这么多年以来,很多后端开发者很少将眼光放在 Linux 技术上,开发者们为了深入的了解 Docker 的技术原理,终于将眼光放入诸如 Cgroups 和 Namespace 技术中。

就在这一时之间,后端及云计算领域的大佬都汇聚于这个「小鲸鱼」的身边。随后到了考虑集群的方案,论集群的管理调度能力,还不得不提 Berkeley 的 Mesos,专注于大数据领域,更加关注的是计算密集型的业务。凭借着它天生的两层调度机制,让它很快发布了一个叫做 Marathon 的项目,这个项目随即成为了 Swarm 的有力竞争对手。

这还没完,说了这么久,还没有提到在基础设施领域翘楚的 Google 公司,是的,同在这一年,宣告了一个叫做 Kubernetes  项目的诞生。

随着  Docker 生态的建立,Docker swarmDocker composeMachine 形成了三件套,此时大量围绕Docker 项目的网络,存储,监控都涌现。在令人兴奋的背后,是对它更多的担忧,这主要来源于对 Docker 商业化战略的顾虑,Docker 公司对于 Docker 着绝对的权威并在多个场合直接和谷歌,微软对干

其实在 Docker 兴起的时候,谷歌也开源了一个 Linux 容器:Imctfy,在当时这个项目在 Docker 面前真是弟弟,所以向 Docker 公司表示想合作的意愿,Docker 显然不同意,且在之后的不久自己发布了一个容器运行时的库 Libcontainer,可能由于太急躁,其代码可读性极差,不稳定和频繁的变更,让社区叫苦不迭

为了切割 Docker 项目的话语权,决定成立一个中立的基金会。所以于 2015 年将这个 Libcontainer 捐出,并修改名称为 Runc,然后依据 RunC 项目,制定了一套容器和镜像的标准和规范----OCI

什么是OCI

为了让 Docker 不能太嚣张,其他玩家构建自身平台的时候不依赖于 Docker 项目,提出一个标准和规范----OCI。这一标准并没有改变 Docker 在容器领域一家独大的现状。Google 坐不住了,必须得搞点大招

**Google **给 RedHat 等伙伴打了电话,说咱们共同牵头发起一个基金会-----CNCF。目的很简单,以 kubernetes 为基础,建立一个以由开源基础设置主导,按照独立基金会方式运营的平台级社区,来对抗 Docker 公司为核心的容器商业生态

为了做好这个事儿,CNCF 必须完成两件事儿

  • 必须在编排领取足够的优势

  • CNCF 必须以 kubernetes 为核心,覆盖更多的场景

CNCF 如何解决第一个问题----编排能力

Swarm 的无缝集成以及 Mesos 的大规模集群的调度管理能力,很明显,如果继续往这两个方向发展,后面的路不一定好走。所以,kubernetes 选择的方式是 Borg,其基础特性是 Google 在容器化基础设施多年来实践的经验,这也正是项目从一开始就避免了和 Swarm ,mesos 社区同质化的重要手段

看似很有技巧,怎么落地?

RedHat 正好擅长这玩意呀,它能真正的理解开源社区运作和项目研发真谛的合作伙伴。作为 Docker 一方,主要不管的强调「Docker native」,但是由于 kubernetes 没有跟 Swarm 展开同质化的竞争,所以这个「Docker Native」的说法并没有什么杀伤力。反而其独特的设计理念和号召力,让其构建了一个完全与众不同的容器编排管理生态。

就这样很快就把 Swarm 甩在了身后。随机开始探讨第二个问题,CNCF 添加了一系列容器工具和项目,面对这样的压迫,Docker 在2016年决定放弃现有的 Swarm项目,而是将容器编排等全部内置到 Docker 项目中。

而 kubunetes 的应对方案也蛮有意思,开启「民主化架构」,kubernetes 为开发者暴露可以扩展的插件机制,让用户可以随意的通过植入代码的方式介入到 kubernetes 的每一个阶段,很快,整个容器圈出现了优秀的作品:火热的微服务治理项目 lstio 等

面对 kubernetes 的 强力攻击,Docker 公司不得不面对失败的事实,只好放弃开源社区专注于商业化转型,所以于2017年将容器运行时部分 containerd 捐赠给了 CNCF,从而将 Docker 项目改名为 Moby,然后交给社区维护,于 2017 年,**Docker **公司宣布将在企业版内置 kubernetes 项目,这也标志了 kubernetes「编排之争」的结束

Docker能做什么

Docker 是一个用于开发,发布,运行应用的程序于一体的开放平台。如果我们需要将货物整齐的摆放在船上且互不影响,那么一种可行的方案即通过集装箱进行标准化,我们将各种货品通过集装箱打包,然后统一的放在船上进行运输,Docker其实就是这样一个将各种软件进行打包成集装箱,然后分发。

Docker的安装

Docker 是一个跨平台的解决方案,支持各大平台比如 CentosUbuntu等 Linux 发行版。下面讲述的是在Centos 中的使用,安装

  • 卸载当前已经存在的旧版 Docker,执行下面的命令

attachments-2021-03-20ielwLo60571bcb5b2c2,png

添加Docker安装源

attachments-2021-03-4OayM5UX60571bed4a788,png

安装最新版本

attachments-2021-03-TXhPuhF460571bff4ae98,png

如果需要安装指定版本,可以通过下面命令查看版本并选择需要的版本

attachments-2021-03-1xjLfXGk60571c12b8126,jpg

安装完成,启动Docker

attachments-2021-03-ictUJzSE60571c2549eaf,jpg

按照国际案例,先跑一个 helloworld

attachments-2021-03-DYmwHkeT60571c36c8b21,jpg

运行上述命令,Docker 首先会检查本地是否有 hello-world 这个镜像,如果发现本地没有这个镜像,Docker 就会去 Docker Hub 官方仓库下载此镜像,然后运行它。最后我们看到该镜像输出 "Hello from Docker!" 并退出。

Docker核心概念

Docker 的操作主要围绕镜像容器仓库三大核心概念

什么是镜像?

一句话说即镜像是 Docker 容器启动的先决条件,因为镜像会提供容器运行的一些基础文件和配置文件,是容器启动的基础。说白了,要启动容器,需要镜像来提供一些基础环境。

使用的镜像的方式有哪些?

  • 自定义创建镜像。首先找一个基础镜像,比如此镜像是 Centos,然后在此镜像基础上自定义需要的内容。举个例子,基础镜像为 Centos,先安装 Nginx 服务,然后部署咱们的应用程序,最后做一些自定义的配置,这样一个镜像就完成了,此镜像的操作系统是 Centos,其中包含了 Nginx 服务

  • 从仓库寻找别人已经做好的镜像。直接去 **Docker hub **或者其他公开仓库 下载即可

什么是容器?

容器是镜像的运行实体。镜像是静态的只读文件,可是容器是要运行的,需要可写文件层。所以容器运行着真正的应用进程,所以自然会有创建,运行,停止,暂停和删除五种状态

既然容器是直接运行的运行程序,那它是有自己的命名空间嘛?

容器有自己独立的命名空间和资源限制,意味着在容器内部,你无法看到主机上面的进程,环境变量等信息,这就是容器和物理机上的进程本质区别

什么是仓库?

镜像仓库类似于代码仓库,用来分发和存储镜像,分为公共镜像私有镜像Docker hub 是 Docker 的官方公开镜像仓库,很多的官方镜像都可以在上面找到,但是访问很慢,所以可以找国内的镜像源,当然后面我们也会自己搭建一个私有镜像仓库

三者的关系是怎么样的?

attachments-2021-03-shb5RrLy60571c69af401,jpg

上图清晰的展现了镜像是容器的基石,容器是在镜像的基础上创建的。一个镜像可以创建多个容器,仓库用来存放和分发镜像

Docker架构

容器技术的发展可说突飞猛进了,市面上除了 Docker 容器还有 coreos 的 rkt,lxc 等,这么多种容器,是不是需要一个标准呢,不然就太容易乱套了

你可能会说直接把 Docker 作为标准不就好了,但是有这么多相关的容器技术,谁不想吃个好瓜,除此之外,当时的编排的技术也竞争火爆,当时的三主力分别是 Docker Swarmkubernetes 以及 mesos。作为原生的 Docker Swarm 自然优势明显,但是 kubernetes 不同意啊,它们觉得调度形式太单一了

因此爆发了容器大战,OCI 也就在此出现。

OCI 是开放的容器标准,轻量级开放的治理结构,目前主要有两个标准,分别是容器运行时标准和容器镜像标准

在如此竞争激烈下面,Docker 的架构成为了下面这个样子

attachments-2021-03-YR9z8zvd60571c82389fa,jpg

Docker 的整体架构为 CS 架构,客户端和服务端两部分组成,客户端发送命令,服务端接受处理指令,其通信的方式有多种,即可以通过 Unix 套接字通信,也可以网络链接远程通信

Docker客户端

我们平时通常使用 Docker 命令行的方式和服务端打交道,其实还可以通过 **REST API **的方式和 Docker 服务端交互,甚至使用各种预言的 sdk 和 Docker 的服务端交互,美滋滋

Docker服务端

Docker 服务端是 Docker 后台服务的总称。其中 Dockerd 是一个非常重要的后台进程,它负责响应并处理Docker 客户端的请求,然后转化为 Docker 的具体操作

Docker 重要的组件

我们去 Docker 默认安装路径先看看有哪些组件

attachments-2021-03-cTD5FPAi60571cab88d01,jpg

这里主要说明下 runc 和 contained 组件

  • runc:是一个用来运行容器的轻量级工具

  • contained:是容器标准化后的产物,从 Dockerd 剥离出来,contained 通过 contained-shim 启动并管理runc,可以说 contained 是真正管理容器的生命周期

    attachments-2021-03-HiZEOzrH60571cc04d389,png

    通过上图,可以看到,dockerd 通过 gRPC 与 containerd 通信,由于 dockerd  与真正的容器运行时,runC 中间有了 containerd 这一  OCI  标准层,使得 dockerd 可以确保接口向下兼容。

    gRPC 是一种远程服务调用。containerd-shim 的意思是垫片,类似于拧螺丝时夹在螺丝和螺母之间的垫片。containerd-shim 的主要作用是将 containerd 和真正的容器进程解耦,使用 containerd-shim 作为容器进程的父进程,从而实现重启 dockerd 不影响已经启动的容器进程。

    docker 各个组件之间的关系

    • 启动一个容器

      attachments-2021-03-UWoy50kF60571d026a516,png

      启动完成,通过下面命令查看 docker 的 pid

      attachments-2021-03-kGsAK1fm60571d16b2f08,png

      此时发现其 pid 为 4428,随后我们查看进程之间的关系

      • 通过 pstree 查看进程之间的关系

        attachments-2021-03-TndsWmOg60571d30e6417,png

        注意,docker19 就看不到两者是父子关系了

        可以先使用 ps aux | grep contained ,然后使用 pstree 查看 contained 的 pid ,实际上,Docker 启动的时候,contained 就启动了,dockerd 和 contained 一直就存在。当执行了docker run以后,contained 就会创建 contained-shim 充当垫片进程,然后启动容器的真正进程 sleep 3600,这和架构图一致

        075528566666

        Docker相关组件

        • docker

        对于我们最直观的即 Docker 命令,作为 Docker 客户端的完整实现,通过 Docker 命令来实现所有的 Docker 客户与服务端的通信

        Docker 客户端于服务端的交互过程是怎么样的呢

        Docker 组件向服务端发送请求后,服务端根据请求执行具体的动作并将结果返回给 DockerDocker 解析服务端的返回结果,并将结果通过命令行标准输出展示给用户。这样一次完整的客户端服务端请求就完成了

        • dockerd

        dockerd 为 Docker 服务端后台的常驻进程,负责接收客户端的请求,处理具体的任务并将结果返回客户端

        那么 Docke r客户端采用哪几种方式发送请求

        第一种方式:通过 unix 套接字与服务端通信,配置的格式为:unix://socket_path。默认的 dockerd 生成的 socket文件存放在 /var/run/docker.sock,此文件只能是 root 用户才能访问,这也是为什么刚安装完 Docker 后只能root 来进行访问操作

        第二种方式:采用 TCP 的方式与服务端通信,配置格式为:tcp://host:por,为了保证安全,通常还需要使用TLS认证

        第三种方式:通过 fd 文件描述符的方式,配置格式为:fd://这种格式一般用于 systemd 管理的系统中。

        • docker-init

        在 Linux 中,有一个叫做 init 的进程,是所有进程的父进程,用来回收那些没有回收的进程,同样的道理,在容器内部,可以通过加上参数 --init 的方式,让 1 号进程管理所有的子进程,例如回收僵尸进程

        举个例子示范,以镜像 busybox 为例


attachments-2021-03-1Re8TZd160571d4e0395b,jpg

此时的 1 号进程为为 sh 进程,如果加上 --init

attachments-2021-03-C2ubQlH860571d7b423bc,jpg

你会发现,此时的 1 号进程为 docker-init,而不是 sh 了

  • docker-proxy

docker-proxy 用来将容器启动的端口映射到主机,方便主机的访问。

假设目前启动一个 nginx 容器并将容器的 80 端口映射到主机的 8080 端口

attachments-2021-03-DSsMauzU60571d9ee6175,jpg

查看容器 IP

attachments-2021-03-DXT5B8bY60571dcb58915,jpg
此时使用 ps 查看主机是否有 docker-proxy 进程

attachments-2021-03-5vQTeSNC60571df64a20c,jpg
可以发现当进行端口映射的时候,docker 为我们创建了一个 docker-proxy  进程,并且通过参数将容器的 IP 和端口传递给 docker-proxy,然后 proxy 通过 iptables 完成 nat 的转发

attachments-2021-03-eR81AqSX60571e14879bb,jpg

从最后一句可以看出,当我们主机访问 8080 端口的时候,iptable 将流量会转发给 172.17.0.2 的 80 ,从而实现主机上直接访问容器的业务

使用 curl 访问一下 nginx 容器

attachments-2021-03-u0I6ToGH60571e2a9e8af,jpg

contained组件

  • containerd

contained主要负责容器的生命周期管理,同时还会负责一些其他的功能

主要负责那些功能?

镜像的管理

接收dockerd的请求

管理存储相关资源

管理网络资源

  • containerd-shim

containerd-shim 的意思是垫片,类似于拧螺丝时夹在螺丝和螺母之间的垫片。containerd-shim 的主要作用是将 containerd 和真正的容器进程解耦,使用 containerd-shim 作为容器进程的父进程,从而实现重启 containerd 不影响已经启动的容器进程。

  • ctr

ctr 实际上是 containerd-ctr,它是 containerd 的客户端,主要用来开发和调试,在没有 dockerd 的环境中,ctr 可以充当 docker 客户端的部分角色,直接向 containerd 守护进程发送操作容器的请求。

Docker镜像使用

来,继续,我们看看镜像是什么。镜像是一个只读的镜像模版且包含了启动容器所需要的文件结构内容。镜像不包含动态数据,构建完成将不会改变

对于镜像都有哪些操作?

attachments-2021-03-VZR7ZJSs60571e5450f22,jpg

对于镜像的操作分为:

  • 拉取镜像:通过 docker pull 拉取远程仓库的镜像

  • 重命名镜像:通过 docker tag 重命名镜像

  • 查看镜像:通过 docker image ls 查看本地已经存在的镜像

  • 删除镜像:通过 docekr rmi 删除没有用的镜像

  • 构建镜像

  • 第一种是通过 docker build 命令基于 dockerfile 构建镜像,推荐

  • 第二种是通过 docker commit 基于运行的容器提交为镜像

拉取镜像

拉取镜像直接使用 docker pull 命令即可,命令的格式如下

attachments-2021-03-MZ5o00vV60571e6874e6c,jpg

  • registry 为注册的服务器,docker 默认会从官网 docker.io 上拉取镜像,当然可以将 registry 注册为自己的服务器

  • repository 为镜像仓库,library 为默认的镜像仓库

  • image 为镜像的名称

  • tag 为给镜像打的标签

现在举个例子,这里有个镜像叫做 busybox,这个镜像集成了上百个常用的 Linux 命令,可以通过这个镜像方便快捷的查找生产环境中的问题,下面我们一起操作一波

  • docker pull busybox

首先会在本地镜像库查找,如果不存在本地库则直接去官网拉取镜像。拉取完镜像后随即查看镜像

  • 查看镜像---docker images

如果要查看指定的镜像,则使用docker image ls命令进一步查询

  • 重命名镜像采用打标签的方式重命名,格式如下

    attachments-2021-03-I7O32pA060571e907381c,png

    我们仔细观察这两个镜像,就会发现这两个镜像的 IMAGE ID其实是一样的,这是什么原因呢

    实际上他们都是指向的同一个镜像文件,只不过其别名不一样而已,如果此时不想要mybox镜像,想删除这个镜像

    • 使用 docker rmi 删除镜像

    此时再次使用 docker images 查看确实删除了

    如何自己构建自己镜像呢

    之前说过,有两种方式,一种是通过 docker commit 的方式,一种是 docker build 的方式。首先看看使用容器提交镜像的方式

    attachments-2021-03-QHNEmdgL60571ea508eee,png

    此时启动了一个busybox容器并进入到容器,并在容器中创建一个文件,并写入内容

    attachments-2021-03-VlATuz5A60571eb719346,png

    此时就在当前目录下创建了一个hello.txt文件并写入了内容。现在新建另外一个窗口,然后提交为一个镜像

    attachments-2021-03-5LjKpi0W60571ec8afe5e,png

    然后使用 docker image ls 查看发现确实生成了镜像

    然后我们再看看使用 dockerfile 的方式

    • dockerfile的每一行的命令都会生成独立的镜像层并拥有唯一的id

    • dockerfile命令是完全透明的,通过查看dockerfile的内容,就可以知道镜像是怎么一步步构建的

    • dockerfile为纯文本,方便做版本控制

    先看看都有哪些命令

    attachments-2021-03-1SOoxwwM60571edd3b8f9,jpg

    这么多,不存在的,我们先看一个dockerfile就知道如何用了

    attachments-2021-03-NcQImyqR60571ef3e8c03,jpg

    • 首先第一行表示基于什么镜像构建

    • 第二行是拷贝文件nginx。repo 到容器内的 /etc/yum.repos.d

    • 第三行为容器中运行 yum install 命令,安装 nginx 命令到容器

    • 第四行为生命容器使用 80 端口对外开放

    • 第五行定义容器启动时的环境变量HOST=mynginx,容器启动后可以获取到环境变量 HOST 的值为 mynginx。

    • 第六行定义容器的启动命令,命令格式为json 数组。这里设置了容器的启动命令为 nginx ,并且添加了 nginx 的启动参数 -g 'daemon off;' ,使得 nginx 以前台的方式启动。

    基本操作已经会了,现在我们看看镜像的实现原理

attachments-2021-03-oVhKXtvV60571f2bb5730,jpg

  • 第一行:创建一个 busybox 镜像层

  • 第二行:拷贝本机 test 文件到镜像内

  • 第三行 在tmp 文件夹创建一个目录 testdir

为了清楚的看见镜像的存储结构,通过 docker build 构建镜像

attachments-2021-03-l1IctI4J60571f529269d,jpg

因为我的 docker 使用的是 overlay2 文件驱动,所以进入到/var/lib/docker/overlay2 ,使用 tree 查看

可以清楚的看到,dockerfile 的每一行命令都会生成一个镜像层

attachments-2021-03-fKla97cM60571f6755573,jpg

Docker容器操作

我们通过一个镜像可以轻松的创建一个容器,一个镜像可以有多个容器,在运行容器的时候,实际上是在容器内部创建了这个文件系统的读写副本,如下图所示

attachments-2021-03-M5agRUaT60571f8b9a83a,jpg

容器的生命周期是怎么样的?

容器的生命周期一共有五个状态分别为

  • created  初建状态

  • running  运行状态

  • stopped 停止状态

  • opaused 暂停状态

  • deleted  删除状态

通过 docker cretate 进入容器的初建状态,然后通过 docker start 进入运行状态,通过 docker stop 进入停止状态,运行状态的容器可以通过 docker pause 让其变为暂停状态,为了详细的查看这些过程,我们实操一下

  • 创建并启动容器

    attachments-2021-03-PBKMTXag60571fa4c816e,png

    通过 docker create 创建的容器处于停止的状态,使用 docker start busybox 进入启动状态

  • attachments-2021-03-5fUYkect60571fb9c1beb,png

    当使用 docker run 创建并启动容器的时候,docker 后台的执行逻辑为

    • 首先检查本地是否有 busybox 镜像,不存在则取 dockerhub 中拉取

    • 使用 busybox 镜像启动一个容器

    • 分配文件系统,并在镜像的只读层外创建一个读写层

    • 从 docker ip 池分配个 ip 给容器

    • 运行镜像

    可以进入交互模式么

    同时使用-it 参数可以让我们进入交互模式,容器内部和主机是完全隔离的。另外由于此时的 sh 为 1 号进程,所以如果通过 exit 退出 sh,那么容器也就退出,所以对于容器而言,杀死容器中的主进程,那么容器也就会被杀死

    通过 docker stop 停止容器,其原理是给运行中的容器给 sigterm 信号,如果容器为 1 号进程接受并处理sigterm,则等待 1 号进程处理完毕后就退出,如果等待一段时间后还是没有处理,则会通过发送 sigkill 命令强制终止容器

    如何进入容器?

    想要进入容器,有三种方案,分别是 docker attach,docker exec,nsenter 等

    • 使用 docker attach 方式进入容器

      attachments-2021-03-SjNBlESe60571ff794970,jpg

      通过 docker ps -a 查看当前的进程信息

      attachments-2021-03-V8SfZFRx6057200ee9fb3,jpg

      可是当我们在进行窗口进行 docker attach 的时候,这个命令就不好用了,所以使用 docker exec 的方式

      • 使用 docker exec进入容器

        attachments-2021-03-QOmeoiJt6057202c3057e,jpg

        奇怪的发现居然是两个sh 进程,主要是因为,当我们使用 docker exec方式进入容器的时候,会单独启动一个 sh 进程,此时的多个窗口都是独立且不受干扰,也是非常常用的方式

        • 删除容器

        现在基本上知道了如何创建,启动容器,那么怎么删除容器呢

        使用docker rm的方式删除容器

      attachments-2021-03-JdzaI9TG605720412e50c,png

      如果此时,容器正在运行,那么需要添加-f的方式停止正在运行的容器

      如果想要导出容器怎么操作呢

      这简单,不过在导出之前先进入容器创建一个文件

      attachments-2021-03-6dGoATFz60572053be607,png

      然后导出为文件

      attachments-2021-03-YdNLML6u60572066a8514,png

      此时会在当前目录生成一个 busybox.tar 文件,此时就可以将其拷贝到其他的机器上使用

      那如何导入容器呢

      通过 docker import的方式导入,然后使用docker run启动就完成了容器的迁移

      attachments-2021-03-MtRe7BSa6057207c145f1,png

      此时容器名称为 busybox:test,然后我们使用 docker run 启动并进入容器

      attachments-2021-03-wdRusUGb60572091e8233,png

      此时发现之前在/tmp创建的目录也被迁移了过来

      仓库

      容器的基本操作应该都会了,那么我们应该如何去存储和分发这些镜像,这就需要介绍下仓库;

      我们可以使用共有镜像仓库分发,也可以搭建私有的仓库

      仓库是啥玩意

      钱钱仓库放钱,这个仓库放镜像。Github 放代码,我们理解镜像的仓库可以联想 Github 仓库。

      在学习的过程中,不太能区分注册服务器和仓库的关系。注册服务器其实是用来存放仓库的实际机器,而仓库我们可以将其理解为具体的项目或者目录。一个注册服务器可以存放多个仓库,每个仓库可以存放多个镜像

      公有仓库

      Docker hub 是当前全球最大的镜像市场,差不多超过 10w 个容器镜像,大部分操作系统镜像都来自于此。


      attachments-2021-03-BLwhjli8605720c254236,png

      如何使用公共镜像仓库和存储镜像

      • 注册 Docker hub

        attachments-2021-03-6kMJtG7F605720ec8c979,png


        创建仓库

        attachments-2021-03-bq4pMrne6057210275939,png

        • 实战镜像推送到仓库

        此时假设我的账户是 xiaolantest,创建一个 busybox 的仓库,随后将镜像推送到仓库中。

        第一步:拉取 busybox 镜像

        attachments-2021-03-YFxS91io6057213fce582,png

        第二步:推送镜像之前先登录镜像服务器(注意用户名密码哦),出现 login Succeeded表示登录成功

      • attachments-2021-03-KCirC6U4605721526fb76,png
        第三步:推送之前还要做一件事,重新对镜像命名,这样测能正确的推动到自己创建的仓库中
        attachments-2021-03-BmUSRqez6057216949195,png
        第四步:docker push 到仓库中
        attachments-2021-03-Pu3YiyaM6057218d9f181,png

        私有仓库

        Docker 官方提供了开源的镜像仓库 Distribution,镜像存放于 Docker hub 的 Registry中

        • 启动本地镜像仓库

          attachments-2021-03-aa22oGxd605721a2420df,png

        使用 docker ps查看启动的容器
        attachments-2021-03-hg43rqXw605721d1a9289,png
        • 重命名镜像

        此时 Docker 为busybox镜像创建了一个别名localhost:5000/busybox,localhost:5000为主机名和端口,Docker 将会把镜像推送到这个地址。attachments-2021-03-Cbt0xxLE605721e93e391,png

        推送镜像到本地仓库

        attachments-2021-03-15ohwyKN605721fe3b92b,png

        • 删除之前存在的镜像

        此时,我们验证一下从本地镜像仓库拉取镜像。首先,我们删除本地的busybox和localhost:5000/busybox镜像。

        attachments-2021-03-7FzHqztB60572254869ec,png

        查看当前本地镜像

        attachments-2021-03-kCEzVWQe605722695ac74,png

        可以看到此时本地已经没有busybox这个镜像了。下面,我们从本地镜像仓库拉取busybox镜像:

        attachments-2021-03-ZOYlkVUg6057227ac97a7,png

        随后再使用 docker image ls busybox 命令,这时可以看到我们已经成功从私有镜像仓库拉取 busybox 镜像到本地了




  • 发表于 2021-03-21 18:07
  • 阅读 ( 47 )

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
shitian
shitian

662 篇文章

作家榜 »

  1. shitian 662 文章
  2. 石天 437 文章
  3. 每天惠23 33 文章
  4. 小A 29 文章