目录

基础知识

Client 客户端

Host 主机(Docker 引擎)

Image 镜像

Container 容器

镜像分层

可写的容器层

Volume 数据卷

Registry 注册中心

总结

简单的使用docker流程

K8S

K8S中pod

3.2 亲和性(Affinity)与非亲和性(anti-affinity)

3.2.1节点亲和性(Node affinity)

3.2.2 pod亲和性(Inter-pod affinity)与反亲和性(anti-affinity)

3.2.3污点(Taints)与容忍(tolerations)


 

基础知识

https://www.docker.org.cn/docker/194.html

https://www.runoob.com/docker/windows-docker-install.html

Docker 是一个客户端-服务器(C/S)架构程序Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker 提供了一个命令行工具 Docker 以及一整套 RESTful API。

Client 客户端

Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker 提供了一个命令行工具 Docker 以及一整套 RESTful API。你可以在同一台宿主机上运行 Docker 守护进程和客户端,也可以从本地的 Docker 客户端连接到运行在另一台宿主机上的远程 Docker 守护进程

Host 主机(Docker 引擎)

一个物理或者虚拟的机器用于执行 Docker 守护进程和容器

Image 镜像

什么是 Docker 镜像?简单的理解,Docker 镜像就是一个 Linux 的文件系统(Root FileSystem),这个文件系统里面包含可以运行在 Linux 内核的程序以及相应的数据。
通过镜像启动一个容器,一个镜像就是一个可执行的包,其中包括运行应用程序所需要的所有内容:包含代码,运行时间,库,环境变量和配置文件等
Docker 把 App 文件打包成为一个镜像,并且采用类似多次快照的存储技术,可以实现:
多个 App 可以共用相同的底层镜像(初始的操作系统镜像);
App 运行时的 IO 操作和镜像文件隔离;
通过挂载包含不同配置/数据文件的目录或者卷(Volume),单个 App 镜像可以用来运行无数个不同业务的容器。

Container 容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

镜像分层

Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。

 

从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
镜像分层最大的一个好处就是共享资源比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。这就是容器 Copy-on-Write 特性。

 

可写的容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的

镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改
总结下来就是:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享

Volume 数据卷

实际上我们的容器就好像是一个简易版的操作系统,只不过系统中只安装了我们的程序运行所需要的环境,前边说到我们的容器是可以删除的,那如果删除了,容器中的程序产生的需要持久化的数据怎么办呢?容器运行的时候我们可以进容器去查看,容器一旦删除就什么都没有了

所以数据卷就是来解决这个问题的,是用来将数据持久化到我们宿主机上,与容器间实现数据共享,简单的说就是将宿主机的目录映射到容器中的目录,应用程序在容器中的目录读写数据会同步到宿主机上,这样容器产生的数据就可以持久化了,比如我们的数据库容器,就可以把数据存储到我们宿主机上的真实磁盘中

Registry 注册中心

Docker 用 Registry 来保存用户构建的镜像。Registry 分为公共和私有两种。Docker 公司运营公共的 Registry 叫做 Docker Hub。用户可以在 Docker Hub 注册账号,分享并保存自己的镜像。

Docker 公司提供了公共的镜像仓库 hub.docker.com(Docker 称之为 Repository)提供了庞大的镜像集合供使用。

一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

总结

Docker 官网写着这样一句话:Build and Ship any Application Anywhere,再结合刚才我们所理解的内容,总结下来就是:一次构建,到处运行

此外,Docker 公司提供了公共的镜像仓库 hub.docker.com(Docker 称之为 Repository),GitHub connect,自动构建镜像,大大简化了应用分发、部署、升级流程。加上 Docker 可以非常方便的建立各种自定义的镜像文件,这些都是 Docker 成为最流行的容器技术的重要因素。

通过以上这些技术的组合,最后的结果就是:绝大部分应用,开发者都可以通过 docker build 创建镜像,通过 docker push 上传镜像,用户通过 docker pull 下载镜像,使用 docker run 运行容器应用。用户不再需要去关心如何搭建环境,如何安装,如何解决不同发行版的库冲突——而且通常不会消耗更多的硬件资源,不会明显降低性能。

 

简单的使用docker流程

https://www.docker.org.cn/book/docker/what-is-docker-16.html

 

K8S

kubernetes中文社区:https://www.kubernetes.org.cn/

k8s全称kubernetes,这个名字大家应该都不陌生,k8s是为容器服务而生的一个可移植容器的编排管理工具,越来越多的公司正在拥抱k8s,并且当前k8s已经主导了云业务流程,推动了微服务架构等热门技术的普及和落地,正在如火如荼的发展。那么称霸容器领域的k8s究竟是有什么魔力呢?

首先,我们从容器技术谈起,在容器技术之前,大家开发用虚拟机比较多,比如vmware和openstack,我们可以使用虚拟机在我们的操作系统中模拟出多台子电脑(Linux),子电脑之间是相互隔离的,但是虚拟机对于开发和运维人员而言,存在启动慢,占用空间大,不易迁移的缺点。举一个我亲身经历过的场景吧,之前在vmware中开发了一个线下平台,为了保证每次能够顺利使用,我们就把这个虚拟机导出为OVF,然后随身携带,用的时候在服务器中部署,这里就充分体现了虚拟机的缺点。

接着,容器化技术应运而生,它不需要虚拟出整个操作系统,只需要虚拟一个小规模的环境即可,而且启动速度很快,除了运行其中应用以外,基本不消耗额外的系统资源。Docker是应用最为广泛的容器技术,通过打包镜像,启动容器来创建一个服务。但是随着应用越来越复杂,容器的数量也越来越多,由此衍生了管理运维容器的重大问题,而且随着云计算的发展,云端最大的挑战,容器在漂移。在此业务驱动下,k8s问世,提出了一套全新的基于容器技术的分布式架构领先方案,在整个容器技术领域的发展是一个重大突破与创新。

那么,K8S实现了什么?

从架构设计层面,我们关注的可用性,伸缩性都可以结合k8s得到很好的解决,如果你想使用微服务架构,搭配k8s,真的是完美,再从部署运维层面,服务部署,服务监控,应用扩容和故障处理,k8s都提供了很好的解决方案。

具体来说,主要包括以下几点:

  1. 服务发现与调度
  2. 负载均衡
  3. 服务自愈
  4. 服务弹性扩容
  5. 横向扩容
  6. 存储卷挂载

总而言之,k8s可以使我们应用的部署和运维更加方便。

最后,我们看下k8s的架构:

 

k8s集群由Master节点和Node(Worker)节点组成。

Master节点

Master节点指的是集群控制节点,管理和控制整个集群,基本上k8s的所有控制命令都发给它,它负责具体的执行过程。在Master上主要运行着:

  1. Kubernetes Controller Manager(kube-controller-manager):k8s中所有资源对象的自动化控制中心,维护管理集群的状态,比如故障检测,自动扩展,滚动更新等。
  2. Kubernetes Scheduler(kube-scheduler): 负责资源调度,按照预定的调度策略将Pod调度到相应的机器上。
  3. etcd:保存整个集群的状态。

Node节点

除了master以外的节点被称为Node或者Worker节点,可以在master中使用命令 kubectl get nodes查看集群中的node节点。每个Node都会被Master分配一些工作负载(Docker容器),当某个Node宕机时,该节点上的工作负载就会被Master自动转移到其它节点上。在Node上主要运行着:

  1. kubelet:负责Pod对应的容器的创建、启停等任务,同时与Master密切协作,实现集群管理的基本功能
  2. kube-proxy:实现service的通信与负载均衡
  3. docker(Docker Engine):Docker引擎,负责本机的容器创建和管理

 

K8S中pod

一.什么是POD

在Kubernetes集群中,Pod是所有业务类型的基础,也是K8S管理的最小单位级它是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及如何运行的规范。在Pod中,所有容器都被同一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod是它们的逻辑主机,Pod包含业务相关的多个应用容器。

Pod有两个必须知道的特点。

网络:每一个Pod都会被指派一个唯一的Ip地址,在Pod中的每一个容器共享网络命名空间,包括Ip地址和网络端口。在同一个Pod中的容器可以同locahost进行互相通信。当Pod中的容器需要与Pod外的实体进行通信时,则需要通过端口等共享的网络资源

存储:Pod能够被指定共享存储卷的集合,在Pod中所有的容器能够访问共享存储卷,允许这些容器共享数据。存储卷也允许在一个Pod持久化数据,以防止其中的容器需要被重启

二. Pod的工作方式

K8s一般不直接创建Pod。 而是通过控制器和模版配置来管理和调度

2.1 Pod模版

eage对应模版

2.2 Pod重启

在Pod中的容器可能会由于异常等原因导致其终止退出,Kubernetes提供了重启策略以重启容器。重启策略对同一个Pod的所有容器起作用,容器的重启由Node上的kubelet执行。Pod支持三种重启策略,在配置文件中通过restartPolicy字段设置重启策略:

  • Always:只要退出就会重启。
  • OnFailure:只有在失败退出(exit code不等于0)时,才会重启。
  • Never:只要退出,就不再重启

注意,这里的重启是指在Pod的宿主Node上进行本地重启,而不是调度到其它Node上。

2.3资源限制

Kubernetes通过cgroups限制容器的CPU和内存等计算资源,包括requests(请求,调度器保证调度到资源充足的Node上)和limits(上限)等:

2.4健康检查

在Pod部署到Kubernetes集群中以后,为了确保Pod处于健康正常的运行状态,Kubernetes提供了两种探针,用于检测容器的状态:

  • Liveness Probe :检查容器是否处于运行状态。如果检测失败,kubelet将会杀掉掉容器,并根据重启策略进行下一步的操作。如果容器没有提供Liveness Probe,则默认状态为Success;
  • ReadinessProbe :检查容器是否已经处于可接受服务请求的状态。如果Readiness Probe失败,端点控制器将会从服务端点(与Pod匹配的)中移除容器的IP地址。Readiness的默认值为Failure,如果一个容器未提供Readiness,则默认是Success。

kubelet在容器上周期性的执行探针以检测容器的健康状态,kubelet通过调用被容器实现的处理器来实现检测,在Kubernetes中有三类处理器:

  • ExecAction :在容器中执行一个指定的命令。如果命令的退出状态为0,则判断认为是成功的;
  • TCPSocketAction :在容器IP地址的特定端口上执行一个TCP检查,如果端口处于打开状态,则视为成功;
  • HTTPGetAcction :在容器IP地址的特定端口和路径上执行一个HTTP Get请求使用container的IP地址和指定的端口以及请求的路径作为url,用户可以通过host参数设置请求的地址,通过scheme参数设置协议类型(HTTP、HTTPS)如果其响应代码在200~400之间,设为成功。

健康检测的结果为下面三种情况:

  • Success :表示容器通过检测
  • Failure :表示容器没有通过检测
  • Unknown :表示容器容器失败

2.5初始化容器

在开发一个程序时,通常初化代码与主体业务代码放置在同一个程序中。为什么kubernetes提供初始化容器这种功能,将初始化工作从普通容器中隔离出来?这种特性有什么用呢?初始化容器与普通容器有各自独立的image,本质上是将初始化逻辑与主体业务逻辑分离并放置在不同的image中,以下是初始化容器的主要用处:

1.初始化容器可以包含不能随普通容器一起发布出去的敏感信息。

2.初始化容器可以包含用户自定义的代码、工具,如sed、awk、python等方便完成初始化、设置工作。

3.因为初始化逻辑与主体业务逻辑分布在不同的image中,因此image构建者与主体业务逻辑开发者可以各自独立的工作。

4.初始化容器使用Linux namespace,不同于普通应用容器,具有不同的文件系统视图,并且对于低层的操作系统有更大的访问权限。

5.当应用启动的前置条件不具备时,初始化容器可以阻止普通应用容器启动,避免在条件不具备时反复启动注定会失败的容器而浪费系统资源。

 

三.POD调度

3.1 选择节点(nodeSelector)

nodeSelector是目前最为简单的一种pod运行时调度限制,Pod.spec.nodeSelector通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,而后调度pod到目标节点,该匹配规则属于强制约束。

3.2 亲和性(Affinity)与非亲和性(anti-affinity)

三大优势

  • 表述语法更加多样化,不再仅受限于强制约束与匹配。
  • 调度规则不再是强制约束(hard),取而代之的是软限(soft)或偏好(preference)。
  • 指定pod可以和哪些pod部署在同一个/不同拓扑结构下。

3.2.1节点亲和性(Node affinity)

1.requiredDuringSchedulingIgnoredDuringExecution:

可认为一种强制限制,如果 Node 的标签发生了变化导致其没有符合 Pod 的调度要求节点,那么pod调度就会失败。

2.preferredDuringSchedulingIgnoredDuringExecution:

软限或偏好,同样如果 Node 的标签发生了变化导致其不再符合 pod 的调度要求,pod 依然会调度运行。

检查结果符合预期,pod nginx成功部署到非master节点且CPU高配的机器上。

 

3.2.2 pod亲和性(Inter-pod affinity)与反亲和性(anti-affinity)

podAffinity用于调度pod可以和哪些pod部署在同一拓扑结构之下。而podAntiAffinity相反,其用于规定pod不可以和哪些pod部署在同一拓扑结构下。通过pod affinity与anti-affinity来解决pod和pod之间的关系。

 

本示例中假设部署场景为:期望is服务与oltp服务就近部署,而不希望与solr服务部署同一拓扑结构上。

3.2.3污点(Taints)与容忍(tolerations)

对于Node affinity,无论是强制约束(hard)或偏好(preference)方式,都是调度pod到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taints ,除非 Pod也被标识为可以耐受污点节点,否则该Taints节点不会被调度pod。Taints)与tolerations当前处于beta阶段,
Taints节点应用场景比如用户希望把Kubernetes Master节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 pod。pod不会再被调度到taint标记过的节点。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐