[TOC]

@TOC

0x00 基础简述

1.发展经历

描述:近些年由于Cloud云计算(公有云)以及大数据的发展促进了企业从传统转型到数字信息化再到上云, 其中运维部署应用技术也从物理机转向虚拟化再转向了容器化,而又随着分布架构应用的火热,以及对业务快速迭代的的需要,便推动了如今的Kubernetes分布式架构运维平台,它实现了对容器资源的编排与控制, 这也是本次学习的重中之重;

1
2
3
4
5
6
7
# 公有云类型
Infrastructure as a Service (基础设施及服务) :阿里云、腾讯云、百度云、京东云、Google Cloud、AWS Cloud
# 提供给消费者的服务是对所有计算基础设施的利用,包括处理CPU、内存、存储、网络和其它基本的计算资源,用户能够部署和运行任意软件,包括操作系统和应用程序。
Platform as a Service (平台及服务) : 新浪云(SAE) | Google Cloud 平台(GCP)
# 提供给消费者的服务是把客户采用提供的开发语言和工具(例如Java,python, .Net等开发环境)开发的或收购的应用程序部署到供应商的云计算基础设施上去。
Software as a Service (软件即服务) : Office 365(云办公) 、 腾讯文档
# 提供给客户的服务是bai运营商运行在云计算基础设施上的应用程序,用户可以在各种设备上通过客户端界面访问,如浏览器。


部署时代变迁流程

描述:又回到部署时代变迁流程, 大致来说在部署应用程序的方式上,我们主要经历了三个时代:

  • (1)传统部署时代:早期企业直接将应用程序部署在物理机上。由于物理机上不能为应用程序定义资源使用边界,我们也就很难合理地分配计算资源。例如:如果多个应用程序运行在同一台物理机上,可能发生这样的情况:其中的一个应用程序消耗了大多数的计算资源,导致其他应用程序不能正常运行。应对此问题的一种解决办法是,将每一个应用程序运行在不同的物理机上。然而,这种做法无法大规模实施,因为资源利用率很低,且企业维护更多物理机的成本昂贵。
  • (2)虚拟化部署时代:针对上述问题,虚拟化技术应运而生。用户可以在单台物理机的CPU上运行多个虚拟机(Virtual Machine)。
    • 虚拟化技术使得应用程序被虚拟机相互分隔开,限制了应用程序之间的非法访问,进而提供了一定程度的安全性。
    • 虚拟化技术提高了物理机的资源利用率,可以更容易地安装或更新应用程序,降低了硬件成本,因此可以更好地规模化实施。
    • 每一个虚拟机可以认为是被虚拟化的物理机之上的一台完整的机器,其中运行了一台机器的所有组件,包括虚拟机自身的操作系统。
  • (3)容器化部署时代:容器与虚拟机类似,但是降低了隔离层级,共享了操作系统。因此,容器可以认为是轻量级的。
    • 与虚拟机相似,每个容器拥有自己的文件系统、CPU、内存、进程空间等
    • 运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦(不强制依赖宿主系统硬件环境)
    • 容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署
WeiyiGeek.DeplomentMethodChange

WeiyiGeek.DeplomentMethodChange

容器因具有许多优势而变得流行起来,这里再老生重谈一下容器化对我们带来的诸多好处:

  • 1.敏捷地创建和部署应用程序: 比VM创建容器镜像更快更方便;
  • 2.持续开发、集成和部署:通过快速、简便的回滚(由于映像不变性),提供可靠且频繁的容器映像生成和部署。
  • 3.分离开发和运维的关注点: 降低了开发和运维的耦合度
  • 4.可监控性: 操作系统级别的资源监控信息以及应用程序健康状态以及其他信号的监控信息
  • 5.开发、测试、生产不同阶段的环境一致性: 一次build到处运行;
  • 6.跨云服务商、跨操作系统发行版的可移植性: 在 Ubuntu、RHEL、CoreOS、本地、主要公共云和其他任何位置上运行。
  • 7.以应用程序为中心的管理:问题的焦点则是在操作系统的逻辑资源上运行一个应用程序,而VM注重于在虚拟硬件上运行一个操作系统
  • 8.松耦合、分布式、弹性、无约束的微服务:应用程序被切分成更小的、独立的微服务,并可以动态部署和管理,而不是一个部署在专属机器上的庞大的单片应用程序
  • 9.资源隔离:确保应用程序性能不受干扰
  • 10.资源利用:资源高效、高密度利用


前世今生

言归正传,让我们回顾一下 Kubernetesd 的前世今生,在KUbernetes出现前的一些资源管理器。

  • 1.Apache MESOS 分布式的资源管理框架 (2019-8 Twitter 宣布弃用MESOS转向Kubernetes) -> 退出舞台
  • 2.Docker Swarm 针对于 Docker 最薄弱的集群化、容器编排与服务构建 (2019-07 阿里云宣布 Docker Swarm从云平台构建选项中剔除) -> 即将退出舞台
    • 优点: 系统资源占用少(几十兆) 、支持大规模集群化
    • 缺点:功能单一滚动更新以及回滚需要运维人员自定义流程费时
  • 3.Kubernetes 由 Google 基于 Borg (博格)10年的容器化基础架构采用GO语言进行重写在2015年4月份发布后迅速在各个企业占有一席之地; -> 下一代分布式架构的王者
    • Google 每周运行数十亿个容器,Kubernetes 基于与之相同的原则来设计,能够在不扩张运维团队的情况下进行规模扩展。
    • 无论是本地测试,还是跨国公司,Kubernetes 的灵活性都能让你在应对复杂系统时得心应手。
    • Kubernetes 是开源系统,可以自由地部署在企业内部,私有云、混合云或公有云,让您轻松地做出合适的选择。
    • Kubernetes 的生态系统更大、增长更快,有更多的支持、服务和工具可供用户选择,可以将Kubernetes看做为Docker的上层架构。

以下是使用 google trends 对比在对于上述的容器编排工具 kubernetesdocker swarmmesos 三个关键词搜索热度的截图。

WeiyiGeek.2019

WeiyiGeek.2019


Q:那什么是Kubernetes系统?

答: Kubernetes (K8s)是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。
简单的说它就是一个全新基于容器技术的分布式架构方案,Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置(依据配置信息自动地执行容器化应用程序的管理)和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统。

参考地址: https://kubernetes.io/zh/docs/concepts/overview/what-is-kubernetes/


名称含义
描述: Kubernetes的名字起源于希腊语,含义是 舵手领航员向导,其logo即像一张渔网又像一个罗盘。
Google于2014年将Brog系统开源并命名为Kubernetes,它是构建在Google Brog 十五年运行大规模分布式系统的经验 基础之上,同时凝聚了社区的最佳创意和实践。

PS深层含义: 既然Docker把自己定位是驮着集装箱在大海遨游的鲸鱼,那么Kubernetes则是掌控大海从而捕获和指引这条鲸鱼按照其设定的路线巡游,从这里可以看出Google对其打造了新一代容器世界的伟大蓝图;

kubernetes 官网: https://kubernetes.io


2.简要介绍

Kubernetes 能完成什么工作

Q: 为什么需要 Kubernetes? 它能做什么?

答:容器是打包和运行应用程序的好方式但是免不了容器发生故障,在生产环境中您需要管理运行应用程序的容器并确保不会停机;
例如:当一个容器故障停机,需要另外一个容器需要立刻启动以替补停机的容器。类似的这种对容器的管理动作由系统来执行会更好更快速(而放弃传统的手工方式)。
Kubernetes针对此类问题提供了一个可弹性运行分布式系统的框架,可以使你非常健壮地运行分布式系统,它可以处理应用程序的伸缩、failover(故障转移)、部署模式等多种需求。
例如:Kubernetes 可以轻松管理系统的 Canary 部署。
Kubernets 也提供了完善的管理工具涵盖了开发/部署测试/运维监控的各个环节;


Q: Kubernetes 设计理念?
描述:其功能与架构都遵循了"一切以服务为中心,一切围绕服务运转"以及微服务的架构,简化开发流程与运维的成本;


Q: 什么是容器编排技术?
答:容器编排的技术定义是预定义流程的执行(先做A、再做B、然后做C)。与此相对应Kubernetes构建了一系列相互独立、可预排的控制过程,以持续不断地将系统从当前状态调整到声明的目标状态。

比如: 如何从 A 达到 C,并不重要集中化的控制也就不需要了,就是这样的设计思想使得Kubernetes使用更简单、更强大、稳健、反脆弱和可扩展

Q: K8s提供特性说明

  • 服务发现和负载均衡:通过DNS 名称或 IP 地址暴露容器的访问方式,并且可以在同组容器内分发负载以实现负载均衡;
  • 存储编排:可以自动挂载指定的存储系统,例如 本地存储/nfs/iscsi/云存储
  • 自动发布和回滚: 描述已部署容器的所需状态并将以合适的速率调整容器的实际状态, 可以自动执行部署创建新容器、删除现有容器并将其所有资源采用到新容器;
  • 自愈: 重新启动发生故障、替换容器、kill杀死不满足自定义健康检查条件的容器 (在容器就绪之前,避免调用者发现该容器)
  • 密钥及配置管理: 可以存储和管理敏感信息(例如,密码、OAuth token、ssh密钥等), 您可以更新容器应用程序的密钥、配置等信息,而无需重新构建容器的镜像;


Kubernetes 不是什么

描述:Kubernetes不是一个传统意义的、保罗万象的 PaaS(Platform as a Service)系统。
它主要在容器层面上工作而不是硬件层面,它提供了与PaaS相似的通用特性例如:部署、伸缩、负载均衡、日志、监控等; 然而K8a并不是一个单一整体,这些特性都是可选、可插拔的(高自定义)

Kubernetes提供用于搭建开发平台的基础模块,同时为用户提供了不同模块的选择性和多样性。

  • 1.不限制应用程序的类型: K8s目的广泛支持不同类型的工作负载,包括:有状态、无状态、数据处理等类型的应用,简单的说只要能在容器中运行的就可以在k8s上运行;
  • 2.不部署源码、不编译或构建应用程序: 可以作为部署平台参与到 CI/CD 流程,但是不涉及镜像构建和分发的过程 ,即持续集成、交付和部署 (CI/CD) 工作流由公司业务及技术要求决定;
    • 译者注:可选的有 Jenkins / Gitlab Runner / docker registry / harbor 等
  • 3.不提供应用程序级服务: 包括:中间件(例如,消息总线)、数据处理框架(例如Spark)、数据库(例如,mysql)、缓存(例如,Redis),或者分布式存储(例如,Ceph)。此类组件可以在 Kubernetes 上运行,或者可以被运行在 Kubernetes 上的应用程序访问;
  • 4.不限定日志、监控、报警的解决方案: k8s提供一些样例展示如何与日志、监控、报警等组件集成,同时提供收集、导出监控度量(metrics)的一套机制,用户可根据自己的需求进行选择日志、监控、以及报警组件;
    • 译者注:可选的有 ELK(日志) / Graphana(日志展示平台) / Pinpoint(分布式系统性能监控工具) / Skywalking (Skywalking分布式追踪与监控)/ Metrics Server (英 /ˈmetrɪks/ 容器监控) / Prometheus (容器监控) 等
  • 5.不提供或者限定配置语言(例如jsonnet): 提供一组声明式的 API您可以按照自己的方式定义部署信息。
    • 译者注:可选的有 helm / kustomize / kubectl / kubernetes dashboard / kuboard /octant / k9s
  • 6.不提供或限定任何机器的配置、维护、管理或自愈的系统。
    • 译者注:在这个级别上,可选的组件有 puppet、ansible、open stack
  • 7.实际上 Kubernetes 不是一个纯粹意义上的容器编排系统, 因为它消除了容器编排的需求。


总结简要K8s优点与劣势

  • (1) 优点
    • 开源(由于东家是Google不用担心项目更新迭代)
    • 轻量级、消耗资源小
    • 贴近底层
    • 弹性收缩
    • 负载均衡
  • (2) 劣势
    • 前期学习成本高, 体系庞大且冗杂;


Kubernetes 版本号格式
Kubernetes 版本号格式遵循 Semantic Versioning 版本控制规则, 版本号格式为 x.y.z,其中 x 为大版本号,y 为小版本号,z 为补丁版本号。

一般 Kubernetes 项目会维护最近的三个小版本分支(例如:2020年11月 -> 1.19, 1.18, 1.17)。

  • Kubernetes 1.19 及更高的版本将获得大约1年的补丁支持。
  • Kubernetes 1.18 及更早的版本获得大约9个月的补丁支持。

提供了有关 kubelet 与控制平面以及其他 Kubernetes 组件之间受支持的版本倾斜的更多信息:https://kubernetes.io/zh/docs/setup/release/version-skew-policy/


Q:如何学习Kubernetes系统?从哪几方面进行入手学习?
答: 笔者最初学习时候由于K8s知识体系太庞大了导致零零散散的学习了一些基础知识, 但是越学到后面就越吃力,所以又不得重新学习一些基础知识,下面就是本人学习思路:

  • 介绍说明:前世今生 Kubernetes基础介绍 Borg / Kubernetes 框架 KUbernetes关键字含义

  • 基础概念:什么是 Pod 控制器类型 K8S 网络通讯模式

  • 工具部署:单节点 构建 K8S 集群

  • 资源清单:资源 掌握资源清单的语法 编写 Pod 掌握 Pod 的生命周期***

  • Pod 控制器:掌握各种控制器的特点以及使用定义方式

  • 服务发现:掌握 SVC 原理及其构建方式

  • 存储:掌握多种存储类型的特点 并且能够在不同环境中选择合适的存储方案(有自己的简介)

  • 调度器:掌握调度器原理 能够根据要求把Pod 定义到想要的节点运行

  • 安全:集群的认证 鉴权 访问控制 原理及其流程

  • HELM:Linux yum 掌握 HELM 原理 HELM 模板自定义 HELM 部署一些常用插件

  • 运维:修改Kubeadm 达到证书可用期限为 10年 能够构建高可用的 Kubernetes 集群

  • 开发: Kubernetes 自开发实现特殊功能


Q: k8s适合人群学习研究?
描述: 项目经理、软件架构师、软件工程师、测试工程师、运维工程师以及其它网络技术爱好者;


Q: 学习参考文档?
答:入门必看文档系列以后看到K8s一律等同于Kubernetes只是方便国人发音;


3.系统架构

描述: 为了更好的了解与学习Kubernets就需借鉴对照Brog系统架构, 看出K8s如何基于Brog系统进行演变更新;

Borg 系统

1) Borg系统架构图如下:

WeiyiGeek.Borg系统架构图

WeiyiGeek.Borg系统架构图

2) 组件简单说明:

  • BorgMaster : 集群大脑主要负责各组件请求的分发,为了防止其单节点故障, 高可用集群副本数据最好是 >= 3 奇数个节点;
  • Borglet : 工作节点提供各类资源运行对应的容器, 并实时与Paxos进行联系监听,如果有请求取出(消费者)去执行该任务;
  • Persistent Store : 简写 Paxos 它是Google的一个键值对数据库;
  • Scheduler : 调度器将任务调度的数据写入Persistent Store(Paxos)而不是直接与Borglet节点进行联系;
  • 访问方式 : Borgcfg(Config File), Command-line Tools, Web Browsers;


Kubernetes 系统

1) K8s系统架构图如下:

WeiyiGeek.K8s系统架构图

WeiyiGeek.K8s系统架构图

2) 组件简单说明:

  • Kubernetes Master (Control Plane)
    • Control Plane Components : 控制平面组件对集群做出全局决策(比如调度),以及检测和响应集群事件(例如当不满足部署的 replicas 字段时启动新的 pod)
    • Kube-api-server : 所有服务请求访问统一入口, 基于HTTP协议进行的C/S架构开发;PS 由于HTTP协议本身支持多种请求方式和验证则没有必要采用TCP协议重写;
    • Kube-controller manager : 控制器组件其内部包含多个控制器,并且每个控制器都是一个单独的进程(节点控制器(NC)/ 副本控制器(RC 机制维持副本期望数目)/ 端点控制器(EC) / 服务帐户和令牌控制器 (SA & TC))
    • Cloud-controller manager : 云控制器管理器是1.8的alpha 特性在未来发布的版本中将 Kubernetes 与任何其他云集成的最佳方式, 它主要用于特定于云平台的控制回路可以想做它与 kube-controller-manager 类似;
    • kube-scheduler : 调度器负责任务调度选择合适的节点进行分配任务
    • Etcd : 它是一个可信赖(自身支持集群化)的分布式(扩容缩方便)键值对存储服务数据库, 它能够为整个K8S分布式集群存储某些关键性数据, 并协助分布式集群的正常运转;
  • Kubernetst Nodes
    • Kubelet : 通过CRI(Cinatiner/Runtime/Interface)直接跟容器引擎(Docker)交互实现容器的生命周期管理
    • Kube-proxy : 负责写入规则至 IPTABLES、IPVS 实现服务映射访问的
    • Container Runtime : 容器运行环境是负责运行容器的软件Kubernetes 支持多个容器运行环境: docker、 containerd、CRI-O 以及任何实现 Kubernetes CRI 容器运行环境接口
  • Cloud :共有云、私有云


PS : 不管是K8S的master节点还是Nodes节点都需要依赖容器引擎但不限于docker(主流默认)或者其它的一些容器引擎(podman)

参考地址:https://kubernetes.io/zh/docs/concepts/overview/components/


补充记录时间:[2020年4月22日 14:51:04]

PS : etcd Storage 有 v3 与 v2 版本, 先K8S集群中使用的是etcd v3版本, v2版本已在K8s v1.11中弃用, 更多信息请参考官网或者博客中<Etcd基础学习之架构及工作原理.md>;

  • v3 : Database 存储在磁盘便于数据的持久化从而保证数据不会在误操作的情况下丢失
  • v2 : Memory 存储在内存存储数据随着机器重启而导致数据丢失
WeiyiGeek.etcd实现架构

WeiyiGeek.etcd实现架构

组件说明:

  • HTTP SERVER : 与K8S一样也是采用HTTP协议进行服务请求提交入口
  • Raft : 实时读写的信息
  • WAL : 预写日志
  • Entry : 实体信息
  • Snapshot : 快照信息(按照一定的时间将某个时间节点的大版本与其后的增量子版本进行整合备份便于后期数据恢复)
  • Store : 将数据存入到本地存储中进行数据的持久化
    etcd 官方地址:https://etcd.io/docs/v3.4.0/

0x01 组件浅析

通过上面的简单的K8s组件说明,下面详述了 Kubernetes 的主要组件(该章节非常的重要了解其组件是了解其K8s架构的基础)

WeiyiGeek.K8s主要组件

WeiyiGeek.K8s主要组件

1.Kubernetes-Master

Q:Control Plane Components控制平面组件的作用说明

答:它是集群的控制平台组件(Control Plane Components),主要负责集群中的全局决策(例如调度)和探测并响应集群事件(例如: 当 Deployment 的实际 Pod 副本数未达到 replicas 字段的规定时,启动一个新的 Pod);
控制平面组件可以运行于集群中的任何机器上,但是为了简洁性该组件通常是在运行在一台无其业务容器下的机器上;

Master节点下组件的介绍:

  • 1.kube-apiserver : 主要用于提供 Kubernetes API用来控制平台的前端可以进行水平扩展(k8S中资源的增删改查操作入口),比如我们上面提到的 kubectl / kubernetes dashboard / kuboard 等k8s管理工具基于此实现对 Kubernetes 集群的管理
  • 2.etcd : 支持一致性和高可用的键值对存储组件,Kubernetes集群的所有配置信息都存储在 etcd 中,所以etcd 数据库通常需要有个备份计划;
  • 3.kube-scheduler : 主要用于任务调度,此组件监控所有新创建尚未分配到节点上的 Pod,并且自动选择为 Pod 选择一个合适的节点去运行。
    • 影响调度的因素有:单个或多个 Pod 的资源需求、硬件、软件、策略的限制、亲和与反亲和(affinity and anti-affinity)的约定、数据本地化要求、工作负载间的干扰和最后时限;
  • 4.kube-controller-manager: 在主节点上运行控制器的组件(资源对象的自动化控制中心),从Logic上来说每一个控制器是一个独立的进程,但是为了降低复杂度,这些控制器都被编译到同一个可执行文件并运行在一个进程里,该模块包含的控制器有:
    • 节点控制器(Node Controller):负责监听节点停机的事件并作出对应响应;
    • 副本控制器(Replication Controller) :负责为集群中每一个副本控制器对象(Replication Controller Object)维护期望的 Pod 副本数;
    • 端点控制器(Endpoints Controller):负责为端点对象(Endpoints Object,连接 Service 和 Pod)赋值;
    • 服务帐户和令牌控制器(Service Account & Token Controllers): 负责为新的名称空间创建 default Service Account 以及 API Access Token;
  • 5.cloud-controller-manager: 云控制器管理器是 1.8 的 alpha 特性,这是将 Kubernetes 与任何其他云集成的最佳方式。 云控制器管理器允许您将集群链接到云提供商的API,并将与云平台交互的组件与仅与集群交互的组件分离开来即用于特定于云平台的控制回路。与 kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的 控制回路组合到同一个可执行文件中,供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。

    • ccm(简称)使得云供应商的代码和 Kubernetes 的代码可以各自独立的演化,使得K8核心代码不在高度依赖于云供应商的代码的; ccm(简称)与kcm(简称)一样将几个逻辑上独立的控制循环组合成一个二进制文件作为一个进程运行
    • 注意在进行K8s集群安装时候可能默认不会安装cloud-controller-manager,通过cloud-controller-manager,Kubernetes可以更好地与云供应商结合,例如在阿里云的 Kubernetes 服务里,您可以在云控制台界面上轻松点击鼠标,即可完成 Kubernetes 集群的创建和管理。在私有化部署环境时,您必须自行处理更多的内容。

    以下控制器可以有云提供商依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (1) 节点 (Node) 控制器(Node Controller):当某一个节点停止响应时,调用云供应商的接口,以检查该节点的虚拟机是否已经被云供应商删除 
    #译者注:私有化部署Kubernetes时,我们不知道节点的操作系统是否删除,所以在移除节点后,要自行通过 kubectl delete node 将节点对象从 Kubernetes 中删除

    (2) 路由 (Router) 控制器 (Route Controller):在云供应商的基础设施中设定网络路由(`即用于在底层云基础架构中设置路由`)
    #译者注:私有化部署Kubernetes时,需要自行规划Kubernetes的拓扑结构,并做好路由配置,例如 安装Kubernetes单Master节点 中所作的

    (3) 服务(Service) 控制器 (Service Controller):`创建、更新、删除`云供应商提供的负载均衡器
    #译者注:私有化部署Kubernetes时,不支持 LoadBalancer 类型的 Service,如需要此特性,需要创建 NodePort 类型的 Service,并自行配置负载均衡器

    (4) 数据卷 (Volume) 控制器:`创建、绑定、挂载`数据卷,并协调云供应商编排数据卷
    #译者注:私有化部署Kubernetes时,需要自行创建和管理存储资源,并通过Kubernetes的存储类、存储卷、数据卷等与之关联

补充说明:
Q:什么是alpha阶段?
答:即开发内部测试阶段;


2.Kubernetes-Node

描述:Node 组件运行在每一个节点上(包括 worker 节点或者 master 节点),负责维护运行中的 Pod 并提供 Kubernetes 运行时环境

Node下组件的介绍:

  • 1.kubelet: 此组件是运行在每一个集群节点上的代理程序 确保 Pod 中的容器处于运行状态,负责对容器的生命周期进行管理并且与Master节点密切卸载实现集群的基本管理工作;
    • 它通过多种途径获得 PodSpec 定义,并确保 PodSpec 定义中所描述的容器处于运行和健康的状态。
    • 注意:Kubelet它是不管理不是通过 Kubernetes 创建的容器
  • 2.kube-proxy: 此组件是一个网络代理程序,运行在集群中的每一个节点上,是实现Kubernetes Service概念的重要部分。
    • 它维护节点上的网络规则使得您可以在集群内、集群外正确地与 Pod 进行网络通信, 同时它也是负载均衡中最重要的点;
    • 如果有可用的操作系统包过滤层kube-proxy将使用它,否则kube-proxy将转发流量本身。
  • 3.容器引擎: 负责运行容器Kubernetes支持多种容器引擎:Docker containerd cri-o rktlet 以及任何实现了 Kubernetes CRI (容器运行环境接口) 的容器引擎

补充说明:[2020年4月22日 16:41:04]

Q:什么是引擎?
答:创建和管理容器的工具,通过读取镜像来生成容器,并负责从仓库拉取镜像或提交镜像到仓库中;

Q:多种容器引擎介绍

  • (1) Docker Engine : 是一种开源容器化技术,用于构建和容器化应用程序(C/S架构应用),包含以下组件守护进程dockerd,与 Docker 守护进程进行对话和指导的接口的 API,命令行接口 (CLI) 客户端使用Docker API通过脚本或直接命令控制与 Dockerd 守护进程交互;
    WeiyiGeek.

    WeiyiGeek.

  • (2) Containerd Engine : 是容器运行环境的核心引擎(容器编排/调度技术的基础),可以实现对容器的各种操作(启动,停止等)和网络和存储配置(提供定制化),它提供了标准化的接口方便各种平台集成,并且还可以将运行环境(Runtime)做成可插拔(Plugable)。

前面我们说过在Node节点中Kubelet主要负责Pod的创建、启动、监控、重启、销毁;但它并不是直接面向最终用户, 主要是用于集成到更上层的系统里, 比如 Docker Swarm, Kubernetes, Mesos等容器编排系统。

WeiyiGeek.CRI

WeiyiGeek.CRI

PS : 例如 Docker

  • Docker 是 Kubernetes 社区支持或生态系统中用来在本地计算机上设置 Kubernetes 集群的一种工具。


3.Kubernetes-插件

描述:插件使用 Kubernetes 资源(DaemonSet、 Deployment等)实现集群功能。 因为这些插件提供集群级别的功能,插件中命名空间域的资源属于 kube-system 命名空间
下面描述了一些经常用到的 addons 更多插件请参考K8s的 Addons List

  • 1.CoreDNS: 可以为集群中的SVC创建一个域名IP的对应关系解析,它实际上就是一个 DNS 服务器和环境中的其他 DNS 服务器一起工作,它是实现负载均衡最重要的一环,所有 K8s 集群都应该有 Cluster DNS; 在容器启动时为 Kubernetes 服务提供 DNS 记录,即自动将该 DNS 服务器加入到容器的 DNS 搜索列表中;
  • 2.Web UI(Dashboard):是一个Kubernetes集群的 Web (B/S 结构访问体系)管理界面。它使用户通过该界面管理集群中运行的应用程序以及集群本身并进行故障排除。。
  • 3.Kuboard:是一款基于Kubernetes的微服务管理界面,相较于 Dashboard 来说Kuboard的特点 :无需手工编写 YAML 文件 、微服务参考架构、上下文相关的监控、场景化的设计(导出配置、导入配置)
  • 4.Container Resource Monitoring(容器资源监控): 将容器的度量指标(metrics)记录在时间序列数据库中,并提供了 UI 界面查看这些数据;
  • 5.Cluster-level Logging(集群级别的日志记录): 机制负责将容器的日志存储到一个统一存储中,并提供搜索浏览的界面;
  • 6.Prometheus: 提供K8S集群的监控能力,将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中,并提供用于浏览这些数据的界面。
  • 7.ELK / EFK : 提供 K8S 集群日志统一分析接入平台,负责将容器的日志数据 保存到一个集中的日志存储中,该存储能够提供搜索和浏览接口。
  • 8.Federation :提供一个可以跨集群中心多K8S统一管理功能
  • 9.Ingress: 官方只能实现四层代理,但是他可以实现七层代理,例如Ingress-Nginx 、 Ingress-traefik等前端代理;

Q:什么是Cluster DNS
答:Cluster DNS(英 /ˈklʌstə(r)/) 是一个 DNS 服务器,是对您已有环境中其他 DNS 服务器的一个补充,存放了 Kubernetes Service 的 DNS 记录。


4.本章小结

描述: 前面我们说了k8s能够对容器化软件进行部署管理,在不停机的前提下提供简单快速的发布和更新方式, Kubernetes是自动化部署,缩放,以及集装箱应用管理一个开放源码的容器业务流程引擎;

简单的说: 如果项目需要多机器节点的微服务架构,并且采用Docker image(镜像)进行容器化部署,那么k8s可以帮助我们屏蔽掉集群的复杂性,自动选择最优资源分配方式进行部署;


下图描述的是拥有一个Master(主)节点和六个Worker(工作)节点的k8s集群, 可以通平面化查看其K8s组件展示;

  • Master 节点: 负责管理集群以及协调集群中的所有活动

    • 运行着集群管理的一组进程:kube-apiserver , kube-controller-manager 和 Kube-scheduler,其负责Pod调度,弹性收缩,以及应用程序安全控制,维护应用程序的状态,扩展和更新应用程序。
  • Worker 节点: 即图中的Node是VM(虚拟机)或物理计算机,作为集群中的工作节点运行着真正的应用程序,简单的说它就是充当k8s集群中的工作计算机。

    • 每个Worker节点都运行着一组进程: Kubelet / Kubelet-proxy,他们负责Pod创建、启动监控、重启、销毁以及实现应用的负载均衡;
    • 每个Worker节点还安装了用于处理容器操作的工具: 例如Docker或者Container.io;
    • 工作负载是在 Kubernetes 上运行的应用程序。
      WeiyiGeek.简单集群

      WeiyiGeek.简单集群


0x02 基础概念

0.工作负载

描述: 工作负载是在 Kubernetes 上运行的应用程序。


1.Pods

描述: Pod 是学习Kubernetes的最重要也是最基本的概念,所以对于我们初学者来说它是必须了解的;

Q: Pod 的定义?

答: Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元, 简单的说它是K8s系统node节点中的最小组成单位, K8s设计Pod对象是为了将服务进程包装到相应的Pod中使其成为Pod中运行的容器(Conatiner);
Pod (就像在鲸鱼荚或者豌豆荚中)通常运行在Node节点上, 在 Kubernetes 中,Pod 代表的是集群上处于运行状态的一组容器。
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。并且在上下文中,每个独立的应用可能会进一步实施隔离。
Pod 是特定于应用的”逻辑主机”,其中包含一个或多个应用容器, 这些容器是相对紧密的耦合在一起的。

Q: 什么是 Pod?
答: Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker 容器。

PS : 除了 Docker 之外,Kubernetes 支持很多其他容器运行时, Docker 是最有名的容器引擎使用 Docker 的术语来描述 Pod 会很有帮助。


实现原理

描述: 在每个Pod运行之前会首先启动一个特殊Pause容器或者叫Pod的根容器(只要Pod建立都有它), 而其它容器则为业务容器共享该Pod的Pause容器的网络栈(Locahost)以及Volume挂载卷(共享存储),即 Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口;在同一个 Pod 内,所有容器共享一个 IP 地址和端口空间,并且可以通过 localhost 发现对方。 他们也能通过如 SystemV 信号量或 POSIX 共享内存这类标准的进程间通信方式互相通信。

简单: 您可以想象指定的应用(容器)都运行在同一台主机(Pod)之中;

Q: Pause 容器作用不言而喻?

  • (1) 引入业务无开关并且不易死亡的Pause容器作为Pod的根容器,解决整体检测及判断行动有效和无效的问题,其状态代表了整个容器组的状态;
  • (2) 共享网络栈和存储栈;

Q: 容器的特权模式?

  • Pod 中的任何容器都可以使用容器规约中的安全性上下文中的 privileged 参数启用特权模式。 这对于想要使用使用操作系统管理权能(Capabilities,如操纵网络堆栈和访问设备) 的容器很有用。 容器内的进程几乎可以获得与容器外的进程相同的特权。
    说明:你的容器运行时必须支持 特权容器的概念才能使用这一配置。

Q: Pod 异常处理调度机制?

  • (1) 默认情况下,当Pod里的某个容器停止时 Kubernetes 会自动检测到这个问题并重新启动该Pod(动作是:重启Pod里的所有容器);
  • (2) 工作节点宕机的情况下,则会将该Node上的所有Pod重新调度到其它节点之上。

补充说明:

  • Pause容器对应镜像属于Kubernetes平台的一部分,除了Pause容器外每个Pod还包括一个或多个紧密相关的用户业务容器;
  • 同一个Pod中的服务端口不可重叠使用, 例如Nginx使用80Port则Tomcat只能使用8080Port, 否则可能导致容器无法启动或者重复启动;
  • Pod中除了Pause容器 、应用容器还可以包含在 Pod 启动期间运行的 Init 容器,其三者关系是Pause容器 > Init 容器。


简单分类

我们可以根据学习使用和功能特征大致分为以下两种Pod类型:

  • 1) 单实例(Singleton) 的 Pod (即不是被控制器管理的Pod) : Pod 一旦死亡便不能自动化的切换或者根据期望值进行创建 Pod;
  • 2) 控制器管理的 Pod : 主要是使用工作负载资源及其控制器以实现应用的扩缩和自动修复。

    • RC (ReplicationController): 用来确保容器应用的副本数始终保持在用户定义的副本数(期望值),即如果有容器异常退出其将会自动创建新的Pod来替代, 而如果异常多出来的容器也会自动回收

    • RS (ReplicaSet) :它与ReplicationController没有本质的不同只是名字不一样,在新版本K8s中建议用ReplocaSet来取代ReplicationCpntroller, 但是ReplicaSet支持集合式的selector(标签)虽然它可以独立使用; 建议采用Deployment来自动管理ReplicaSet,这样做的好处式无需担心跟其他机制的不兼容的问题例如ReplocaSet不支持回滚更新但是Deployment是支持的;

    • Deployment : 它为Pod和ReplicaSet提供了一个声明式的定义(Declaratice)方法,用于替代以前的RC来方便管理应用其典型的应用场景如下: 定义Delployment来创建Pod和RelicaSet、滚动升级与回滚应用、扩容与缩容、暂停与继续Deployment

    • StatefullSet : 为了解决有状态服务的问题(前面所说的Deployments与ReplicaSets是为了无状态服务而设计)其利用场景报包括如下:

      1
      2
      3
      4
      - 1.稳定的持久化存储, 即Pod重新调度后还是能访问到相同的持久化数据基于PVC来实现;
      - 2.稳定的网络标志,即Pod重新调度后其PodName 和 HostName 不变,基于Headless Service即没有Cluster IP的Service来实现;
      - 3.有序部署、有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(`即从0到N-1在下一个Pod运行之前的所有之前的Pod必须是Running 和 Readt状态`)它们是基于Init Containers来实现;
      - 4.有序收缩与有序删除(`即从N-1到0`)
    • DaemonSet : 确保在全部或者一部分Node节点上运行一个Pod的副本,当有Node加入集群时也会为他们新增一个Pod;当有Node从集群移除时这些Pod也将被回收;当删除DaemonSet将会删除它创建的所有Pod,例如下面的一些典型用法:

      1
      2
      3
      - 1.运行集群存储Deamon; 例如在每个Node上运行Glusterd 、Ceph;
      - 2.在每个Node上运行日志收集Daemon; 例如Fluentd、logstash;
      - 3.在每个Node上运行监控Daemon; 例如Prometheus Node Exporter;
    • Job : 负责批处理任务即仅执行一次的任务,它保证批处理任务的在一个或者多个Pod成功结束, 常常用于数据备份;

    • Cronjob : 管理基于时间的Job即在给定的时间点只运行一次,周期性地在给定时间点运行;

    • HPA (Horizontal Pod Autoscaling): 仅仅适用于Deployment 与 ReplicaSet在V1版本中仅支持根据Pod的CPU利用率进行扩容,在V1-Alpha版本中就是仅仅支持根据内存和用户自定义的Metric扩缩容;


F&Q

Q: 什么是Rolling-update?以及什么是rollbacks-update(undo)?

答: 滚动更新(即新版本替换旧版本但是旧版本容器并未被删除而是被暂停)
回滚更新(即线上版本回滚前一个或者某一个版本)

Q: 服务分类(资源清单)?什么是有状态服务?什么又是无状态服务?

有状态服务:DBMS (暂停或者离开某段时间后返回到集群中无法正常工作,由于这段时间内有新的数据产生)
无状态服务:LVS APACHE (暂停或者离开某段时间后返回到集群工仍然可以继续的正常工作,您可以把他比如作流水线的管理人员,其离开一会并会不导致流水线作业停止)
PS : 我们所熟知的Docker其实主要是针对一个无状态的服务;

Q: Deployment 与 RC 间的关系?

答: 在Pod创建并不是由RC直接创建而是由Deployment进行创建并且RS也是由它创建的(Pod与RS都是由Deployment创建);

WeiyiGeek.Deployment 与 RC

WeiyiGeek.Deployment 与 RC

Q: 有序部署扩容与删除缩容注意事项?

答: 在同一个Pod中各项目容器的启动顺序可能有一定的关联,例如Mysql->Tomcat->Nginx当缩容时也需按照相应的反向顺序进行关闭;


2.资源清单

描述: Kubenetes 所有的资源对象的定义和描述采用Yaml或者Json的文件格式, 将其比喻作剧本即Kubernetes按照要求定义进行相应资源的执行增删改查;

以下是K8S资源清单定义中比不可少的四个对象:

apiVersion - 对象资源版本
Kind - 对象资源
metadata - 对象资源原数据
spec - 对象资源详细描述
labels - 资源对象标签

描述: Labels 是 K8s 中另外一个核心概念, 它是一个KV键值对其可以附加在各种资源对象(Node、Pod、RC、RS、Delopyment、Service)之上的定义,并且一个资源对象可以定义多个lable标签(多对多的关系);
作用: 为指定资源对象绑定一个或者多个不同的Label来实现多维度的资源分组管理功能,以便灵活、方便的进行资源分配、调度、配置和部署等, 例如在Node中可以利用标签来设置Pod的亲密性,在RS中利用匹配的标签来检测拥有该标签的数量保证Pod数量满足副本数,在SVC中利用标签可进行选择Pod进行负载均衡;

简单的说: Lable 是用来传递用户自定义属性,标注对象的特殊特点,比如用户可以更加直观从标签中看到某个Node节点中挂载的SSD硬盘或者是说测试环境;


标签示例:

1
2
3
4
5
版本标签:"release":"stable"
环境标签:"environment":"dev"
架构标签:"tire":"backend" # middleware
分区标签:"partition":"customerA"
质量管控标签:"track":"weekly"

补充知识:

  • 1.K8s全部资源对象的 Label 我们都可以随时随地的增加、修改和删除,一个资源对象可以有多个不重复的Label。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 1) 为一个Pod设置Label
    $ kubectl label pods deploy-java-maven-0 role=jave-test
    # pod/deploy-java-maven-0 labeled
    $ kubectl get pods deploy-java-maven-0 --show-labels
    # NAME READY STATUS RESTARTS AGE LABELS
    # deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,role=jave-test,statefulset.kubernetes.io/pod-name=deploy-java-maven-0

    # 2) 为一个node设置Lable
    $ kubectl label nodes work-224 devnode=test

    # 3) 强制更新已经设置的Lable
    $ kubectl label pods deploy-java-maven-0 role=front-overwrite --overwrite
    # pod/deploy-java-maven-0 labeled
    $ kubectl get pods deploy-java-maven-0 --show-labels
    # NAME READY STATUS RESTARTS AGE LABELS
    # deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,role=front-overwrite,statefulset.kubernetes.io/pod-name=deploy-java-maven-0

    # 4) 删除指定lable
    $ kubectl label pods deploy-java-maven-0 role-
    # pod/deploy-java-maven-0 labeled
    $ kubectl get pods deploy-java-maven-0 --show-labels
    # NAME READY STATUS RESTARTS AGE LABELS
    # deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,statefulset.kubernetes.io/pod-name=deploy-java-maven-0


selector - 资源对象标签选择器

描述: 有了标签Label后我们还需要配合标签选择器,来进行标签(Lable)的查询和筛选使之分配给该标签的资源对象相应的资源(或者说绑定相应的资源);该方法类似于SQL对象查询机制;

那如何使用标签以及选择器?

描述: 通过标签选择器Label Selector查询和筛选拥有某些Label的资源对象,而K8s通过类似于SQL的简单又通用的对象(where 条件)查询机制;
通过采用等式类和集合类两种方式进行匹配在Node、Pod、RS、Service中的标签;

例如: Lable 为 name = nginx 附加到一个Pod时,那么对应的Lable Selector表达式类比于SQL语句等同于: SELECT * FROM POD WHERE Pod_name = 'nginx';

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 等式类(Equality-Based)-操作表达式(等于或者不等于):
name = redis-app
env != product

# 集合类(Set-Based)-操作表达式(包含、不包含、存储或者不存在):
name In (redis-cluster, redis-slave) # , 表示分隔其中里面的条件关系是AND
name Notin (redis-slave)
name Exists (redis-slave)
name DoesNotExists (redis-slave)

# 使用说明:在Deloyment、ReplicaSet、DaemonSet或者Job等Pod管理控制器对都可以在Selector使用基于集合的筛选定义
selector:
matchLables: # 用于定义Lables匹配的Pod资源对象
app: nginx
matchExpressions: # 用于定义一组Lable其与直接定义在Selector中作用一样
- {key: name, operator: In, value: [appweb]}
WeiyiGeek.Labels在kubernetes集群中的简单使用

WeiyiGeek.Labels在kubernetes集群中的简单使用


方式1:下面的Deployment控制器创建Pod的资源清单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1	#与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
enviroment: test
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #副本数量(由Deployment控制器创建并且监控)
selector: #标签选择器与Pod模板中的标签需要共同作用
matchLabels: #匹配选择包含标签app=nginx的资源 # 基于等式
app: nginx
matchExpressions: # 基于集合
- {key: name, operator: In, value: [web-app]}
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod副本拥有的标签,上面的selector即选择包含标签app:nginx的Pod(有了它我们的delopyment控制器才知道匹配的标签已经有一个Pod在运行了)
app: nginx
name: web-app
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问

方式2: 通过注解(annotations)的方式也可以进行标签选择匹配(后续有示例的时候补充)

Tips : 如果使用一组集合的筛选条件,基于集合操作的表达式匹配标签。也可以通过多个Lable Selector表达式组合实现更为复杂的条件选择,表达式之间用逗号或者AND进行分割;

Tips : 如果同时设置matchLables 与 matchExpressions 则两者条件为‘与’的关系;

总结: 使用 Label 可以给对象创建多组标签,LabelLable Selector 共同构成了k8s系统中最核心的应用模型,使得被管理对象能够被精细的分组管理,同时实现了整个集群的高可以用性;


annotations - 资源对象注解

描述: 上面我们说过除了使用标签将元数据附加到 Kubernetes 对象,你还可以使用 Kubernetes注解为对象附加任意的非标识的元数据,客户端程序(例如工具和库)能够获取这些元数据信息。

那到底有哪些信息可以使用注解来记录? 通常为如下用途

  • 由声明性配置所管理的字段。 将这些字段附加为注解,能够将它们与客户端或服务端设置的默认值、 自动生成的字段以及通过自动调整大小或自动伸缩系统设置的字段区分开来。
  • 构建、发布或镜像信息(如时间戳、发布 ID、Git 分支、PR 数量、镜像哈希、仓库地址)。
  • 指向日志记录、监控、分析或审计仓库的指针。
  • 可用于调试目的的客户端库或工具信息:例如,名称、版本和构建信息。
  • 用户或者工具/系统的来源信息,例如来自其他生态系统组件的相关对象的 URL。
  • 轻量级上线工具的元数据信息:例如,配置或检查点。
  • 负责人员的电话或呼机号码,或指定在何处可以找到该信息的目录条目,如团队网站。
  • 从用户到最终运行的指令,以修改行为或使用非标准功能。

温馨提示: 注解不用于标识和选择对象.


注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符,请注意注解语法和标签一样都是键/值(KV)对(必须是字符串), 换句话说,你不能使用数字、布尔值、列表或其他类型的键或值。例如:

1
2
3
4
5
6
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}

例如,下面是一个 Pod 的配置文件,其注解中包含 imageregistry: https://hub.docker.com/:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/"
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80


3.Service

Q: 什么是Service (SVC) 服务发现?为啥需要Service?

答:在K8中Services服务是分布式集群架构的核心,一个Service对象主要拥有如下功能特征拥有一个唯一的名称以及拥有一个虚拟IP(ClusterIP/ServiceIP或者VIP)和端口号将Pod中的服务进程服务(容器)进行映射以便客户端访问;
简单的说 Service 通常有多个相关的服务进程来提供服务并且每个服务进程都拥有一个独立的Endpoint(Ip+Port)访问点, K8s能够让我们通过Service(虚拟ClusterIP+ServicePort)连接到指定的Service上, (后续解释)并且Service本身一旦创建将不再变化;
作用: 通过K8s内建的透明负载均衡和故障恢复机制,不管后端有多少服务进程也不管某个服务进程是否会由于发生故障而重新部署到其他Node上,都不会影响到我们对服务的正常调用,就不必再为服务IP地址变化而无法访问的问题头疼;


Q: K8s中如何使用Service 服务发现原理?

答: 为了建立Service与Pod间的关联关系,K8s首先会给每个Pod贴上一个标签(Label)它也是K8s中非常重要,例如app=redis标签, 然后给相应的Service定义标签选择器(Label Selector); 例如Redis Service的标签选择器的选择条件为app=redis意为该Service钥作用于所有包含app=redis的Label的Pod上, 这样将巧妙地解决了Service与Pod的关联问题;
你可以将Label与标签选择器类比为CSS样式,可以通过指定的标签设置页面上所有该标签的CSS样式;


Service 服务发现图示

WeiyiGeek.Services服务发现

WeiyiGeek.Services服务发现


4.Network

描述: 在K8s的网络模型假定了所有的Pod都在一个可以直接联通扁平化(规模小/可直通对方Pod的IP)的网络空间中例如在GCE(Google Compute Engine)里面是现成的网络模型,而在私有云的搭建部署K8s集群时候需要我们自己设置网络通信,将不同节点上的Docker容器之间的互相访问先打通然后再运行Kubernetes这是因为Pod Service间的网络是私有虚拟的网络;

Q: 与Pod间的网络通讯模式?

答:
各Pod之间的通讯是采用Overlay Network 覆盖网络即虚拟网桥Bridge实现
Pod 与 Service 之间的通信是通过iPtables底层一堆的转换机制实现;

Q: 不同情况下的网络通信方式我们以Flannel为例

1.同一个Pod内部通信:前面我们说过同一个Pod共享同一个网络命名空间与共享一个Linux协议栈,简单的说就是同一个Pod内的多个容器之间通过 lo 回环网卡实现访问;

2.不同Pod间通信:

  • 假设Pod1与Pod2不再同一台主机上,Pod的地址是与Docker0在同一个网段的,但Docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同的Node之间的通信只能通过宿主机的物理网卡进行,将Pod的IP与所在的Node的IP关联起来通过它将会让Pod进行互相访问;
  • 假设Pod1与Pod2在同一台机器上由Docker0网桥直接转发至Pod2而无需经过Flannel;

3.Pod 至 Service 网络: 目前全部采用iptables维护和转发, 但是可以利用LVS组件进行替换;

4.Pod到外网: Pod向外网发送请求查找路由表然后转发数据包到宿主机的网卡,宿主机网卡完成路由选择后IPtables执行Masquerade把源IP地址更改为宿主机网卡的IP(NAT转发)然后再向外网服务发送请求;

5.外网访问Pod:通过Service映射的端口

组件通讯示意图如下:

WeiyiGeek.组件通讯示意图

WeiyiGeek.组件通讯示意图

K8S网络解决方案

  • (1) K8s + Flannel (该插件是 CoreOS 团队针对于Kubernetes设计的一个网络规划服务)
  • (2) K8s + Calico (Calico 是一种容器之间互通的网络方案)

PS: 在 K8s 中是通过CNI接口接入第三方的网络解决方案的组件;


0x03 简单Kubernetes安装实践

描述:前面我们说过 Kubernetes 是一个由 Google 发起的开源自动化部署,缩放,以及容器化管理应用程序的容器编排系统。

部署 Kubernetes 曾经是一件相当麻烦的事情,早期版本中,Kubelet、Api-Server、Etcd、Controller-Manager 等每一个组件都需要自己单独去部署,还要创建自签名证书来保证各个组件之间的网络访问。但程序员大概是最爱与麻烦做斗争的群体,随着 Kubernetes 的后续版本不断改进(如提供了自动生成证书、Api-Server 等组件改为默认静态 Pod 部署方式),使得部署和管理 Kubernetes 集群正在变得越来越容易起来。


目前主流安装 Kubernetes 方式大致有:

  • 使用 Kubeadm 部署 Kubernetes 集群
  • 使用 Rancher 部署、管理 Kubernetes 集群(其他如 KubeSphere 等在 Kubernetes 基础上构建的工具均归入此类)
  • 使用 Minikube 在本地单节点部署 Kubernetes 集群(其他如 Microk8s 等本地环境的工具均归入此类)

以上集中部署方式都有很明显的针对性,个人开发环境以 Minikube 最简单,生产环境以 Rancher 最简单,在云原生环境中,自然是使用环境提供的相应工具。不过笔者推荐首次接触 Kubernetes 的同学最好还是选择 Kubeadm 来部署,毕竟这是官方提供的集群管理工具,是相对更底层、基础的方式,充分熟悉了之后再接触其他简化的方式会快速融会贯通。 以上部署方式无需全部阅读,根据自己环境的情况选择其一即可。


安装环境基本需求
1)两台或多台以上的Linux虚拟机或者物理机。
2)每台Linux处理器最小需求为2 CPU 核或更多、内存最小需求 2 GB 或更多的 RAM。
3)每台Linux不可以有重复的主机名、IP地址、MAC 地址或 product_uuid。
4)每台Linux进行网络配置确保网络通畅(建议禁用系统防火墙)即可以正常互联以及访问外部网络。
5)检查每台Linux 的某些端口(API-Server组件默认6443端口)是否被占用,以及时间、时区是否正常.
6)禁用每台Linux 的用交换分区,以保证保证 kubelet 正常工作。


K8s 单控制平面部署流程
  • Step 1.环境配置要求:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # 1.安装Master/Node节点(cpu和磁盘至少1C和2G)
    2台 2核4G 的服务器
    # 注意:内核版本的选择
    CentOS 7.8 kernel version>= 4.19.x
    # docker 版本 至少 1.9 以上
    docker 19.03.8
    # etc 至少2.0版本以上


    # 2.实际测试环境(两台):
    # 系统版本
    CentOS Linux release 7.8.2003 (Core)
    # 内核版本
    CentOS Linux (5.6.10-1.el7.elrepo.x86_64) 7 (Core)

    # 核心数:请使用 lscpu 命令,核对 CPU 信息
    # Architecture: x86_64 本安装文档不支持 arm 架构
    # CPU(s): 2 CPU 内核数量不能低于 2
    cat /proc/cpuinfo | grep -c 'processor'
    2

    # 内存容量(6G)
    cat /proc/meminfo
    MemTotal: 6090864 kB
    MemFree: 5709020 kB
    MemAvailable: 5695728 kB
    Buffers: 2108 kB
    Cached: 193996 kB


  • Step 2.安装准备以及软件版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    * 我的任意节点 centos 版本为 7.6 或 7.7
    * 我的任意节点 CPU 内核数量大于等于 2,且内存大于等于 4G
    * 我的任意节点 hostname 不是 localhost,且不包含下划线、小数点、大写字母
    * 我的任意节点都有固定的内网 IP 地址
    * 我的任意节点都只有一个网卡,如果有特殊目的,我可以在完成 K8S 安装后再增加新的网卡
    * 我的任意节点上 Kubelet使用的 IP 地址 可互通(无需 NAT 映射即可相互访问),且没有防火墙、安全组隔离
    * 我的任意节点不会直接使用 docker run 或 docker-compose 运行容器

    # K8s系统安装所需软件一览
    Kubernetes v1.18.x
    * kubeadm
    * kubectl
    * kubelet
    * kube-apiserver
    * kube-control-manager
    * kube-proxy
    * kube-scheduler
    * calico 3.13.1
    * nginx-ingress 1.5.5
    * coredns
    * etcd

    Docker-ce 19.03.8
    * docker-cli
    * nfs-utils
  • Step 3.安装流程(MaSTER与NODE都要执行)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #0.临时关闭swap和SELinux(这是必须的,置于为什么要这么做在下一讲中进行说明)
    swapoff -a
    setenforce 0
    sed -i 's/^SELINUX=enforcing$/SELINUX= disabled/' /etc/selinux/config


    #1.修改hostname
    hostnamectl set-hostname master-01|node-01
    # 查看修改结果
    hostnamectl status
    # 设置 hostname 解析
    echo "127.0.0.1 $(hostname)" >> /etc/hosts


    #2.检查网络(所有节点上 Kubernetes 所使用的 IP 地址必须可以互通(无需 NAT 映射、无安全组或防火墙隔离)
    ip route show && ip addr show ens192
    # default via 10.10.107.1 dev ens192 proto static metric 100
    # 10.10.107.0/24 dev ens192 proto kernel scope link src 10.10.107.191 metric 100
    # 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    # link/ether 00:50:56:ac:a5:af brd ff:ff:ff:ff:ff:ff
    # inet 10.10.107.191/24 brd 10.10.107.255 scope global noprefixroute ens192
    # valid_lft forever preferred_lft forever
    # inet6 fe80::44ce:84ab:ef25:36cc/64 scope link noprefixroute
    # valid_lft forever preferred_lft forever

    # 3.安装docker及kubelet (在 master 节点和 worker 节点都要执行)
    # 最后一个参数 1.18.2 用于指定 kubenetes 版本,支持所有 1.18.x 版本的安装
    # 腾讯云 docker hub 镜像
    # export REGISTRY_MIRROR="https://mirror.ccs.tencentyun.com"
    # DaoCloud 镜像
    # export REGISTRY_MIRROR="http://f1361db2.m.daocloud.io"
    # 华为云镜像
    # export REGISTRY_MIRROR="https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com"
    # 阿里云 docker hub 镜像
    export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
    curl -sSL https://kuboard.cn/install-script/v1.18.x/install_kubelet.sh | sh -s 1.18.2
    WeiyiGeek.基础环境安装

    WeiyiGeek.基础环境安装

  • Step 4.对于 Master 节点的操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    # 4.初始化 master 节点环境变量说明
    # * APISERVER_NAME 不能是 master 的 hostname
    # * APISERVER_NAME 必须全为小写字母、数字、小数点,不能包含减号
    # * POD_SUBNET 所使用的网段不能与 master节点/worker节点 所在的网段重叠: `export POD_SUBNET=10.100.0.1/16 命令`

    # 只在 master 节点执行替换 x.x.x.x 为 master 节点实际 IP(请使用内网 IP)
    # export 命令只在当前 shell 会话中有效,开启新的 shell 窗口后,如果要继续安装过程,请重新执行此处的 export 命令
    export MASTER_IP=10.10.107.191
    # 替换 apiserver.demo 为 您想要的 dnsName
    export APISERVER_NAME=apiserver.weiyi
    # Kubernetes 容器组所在的网段,该网段安装完成后,由 kubernetes 创建,事先并不存在于您的物理网络中
    export POD_SUBNET=10.100.0.1/16
    echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
    curl -sSL https://kuboard.cn/install-script/v1.18.x/init_master.sh | sh -s 1.18.2

    # 5.检查 master 初始化结果
    # 只在 master 节点执行执行如下命令,等待 3-10 分钟,直到所有的容器组处于 Running 状态
    watch kubectl get pod -n kube-system -o wide
    # NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    # calico-kube-controllers-5b8b769fcd-pv4g2 1/1 Running 0 11m 10.100.77.1 k8s <none> <none>
    # calico-node-ssfqz 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
    # coredns-546565776c-96nnf 1/1 Running 0 11m 10.100.77.3 k8s <none> <none>
    # coredns-546565776c-bnkvl 1/1 Running 0 11m 10.100.77.2 k8s <none> <none>
    # etcd-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
    # kube-apiserver-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
    # kube-controller-manager-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
    # kube-proxy-8s5lv 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
    # kube-scheduler-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>


    # 查看 master 节点初始化结果
    kubectl get nodes -o wide
    # NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
    # k8s Ready master 6m58s v1.18.2 10.10.107.191 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8


    # 6.获得 join命令参数(master节点上运行)
    kubeadm token create --print-join-command
    # W0506 22:22:32.850186 31335 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
    # 将node加入到master节点中命令
    kubeadm join apiserver.weiyi:6443 --token nuv3rj.j58fccxrcpmvabze --discovery-token-ca-cert-hash sha256:c35aafc3b03ff86c50798adb5745c893c4f6e79b3fdf16c24d348511d3100f0c
WeiyiGeek.集群安装部署

WeiyiGeek.集群安装部署


  • Step 5.在Works 节点中的操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 7.只在 worker 节点执行
    # 替换 x.x.x.x 为 master 节点的内网 IP
    export MASTER_IP=10.10.107.191
    # 替换 apiserver.demo 为初始化 master 节点时所使用的 APISERVER_NAME
    export APISERVER_NAME=apiserver.weiyi
    echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts


    # 8.在上面步骤六中kubeadm token create 命令的输出 token
    # 但是注意有效时间为 2 个小时,您可以使用此 token 初始化任意数量的 worker 节点。
    kubeadm join apiserver.weiyi:6443 --token nuv3rj.j58fccxrcpmvabze --discovery-token-ca-cert-hash sha256:c35aafc3b03ff86c50798adb5745c893c4f6e79b3fdf16c24d348511d3100f0c

    # [preflight] Running pre-flight checks
    # [preflight] Reading configuration from the cluster...
    # [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
    # [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace
    # [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
    # [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
    # [kubelet-start] Starting the kubelet
    # [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

    # This node has joined the cluster:
    # * Certificate signing request was sent to apiserver and a response was received.
    # * The Kubelet was informed of the new secure connection details.

    # Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
  • Step 6.安装校验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 9.To start using your cluster, you need to run the following as a regular user(重点)
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    # 10.只在 master 节点执行,可以看到STATUS状态一切正常
    kubectl get nodes -o wide
    # NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
    # k8s Ready master 16h v1.18.2 10.10.107.191 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8
    # node Ready <none> 10h v1.18.2 10.10.107.192 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8


K8s 实践之小试牛刀

描述:在 Kubernetes 上部署第一个应用程序,下图是在上面k8s原理图基础添加上了Deployment、Pod和Container

1.基础复习
正对于前面所学的一些基础知识进行加深学习:
Deployment 资源控制器: 译名为部署, 在k8s中通过发布 Deployment 可以创建应用程序 (docker image) 的实例 (docker container),这个实例会被包含在称为 Pod 的概念中 Pod 是 k8s 中最小可管理单元。它提供了一种完全不同的方式来管理应用程序(持续监控创建应用程序实例), 通过创建应用程序实例并确保它们在集群节点中的运行实例个数, 能够使应用程序从机器故障中恢复(自我修复机制);

Deployment 处于 master 节点上,通过发布 Deployment,master 节点会选择合适的 worker 节点创建 Container(即图中的正方体),Container 会被包含在 Pod (即蓝色圆圈)里。

1
2
3
4
5
6
7
8
9
#K8s Cluster 
Master 节点:
- Deployment 控制器

Worker 节点:
- Node
- pod
- Container App # 工作负载
- Node Processes

WeiyiGeek.K8S-Cluster

WeiyiGeek.K8S-Cluster


2.实践应用部署:
描述:使用 kubectl 方式进行部署 nginx Deployment

Step1.创建Deployement YAML文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1	#与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #副本数量(由Deployment控制器创建并且监控)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod副本拥有的标签,上面的selector即选择包含标签app:nginx的Pod(有了它我们的delopyment控制器才知道匹配的标签已经有一个Pod在运行了)
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问


Step2.应用后可以可分别查看到一个名为 nginx-deployment 的 Deployment 和一个名为 nginx-deployment-xxxxxxx 的 Pod

1
2
$ kubectl apply -f nginx-deployment.yaml
# deployment.apps/nginx-deployment created


Step3.查看部署结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看 Deployment
kubectl get deployments
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 1/1 1 1 36s


# 查看 Pod 与指定
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-674ff86d-btmt4 1/1 Running 0 53s

kubectl get pods -n default -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# nginx-deployment-674ff86d-btmt4 1/1 Running 0 3h2m 10.100.167.129 node <none> <none>

至此你已经成功在k8s上部署了一个实例的nginx应用程序,


3.公布应用程序
描述:在创建Service(定义Pod容器组访问方式以及之间的相互依赖解耦)的时候,通过设置配置文件中的 spec.type字段的值,可以以不同方式向外部暴露应用程序:

方式如下:

  • 1) ClusterIP(默认): 在群集中的内部IP上公布服务,这种方式的 Service(服务)只在集群内部可以访问到
  • 2) NodePort : 使用 NAT 在集群中每个的同一端口上公布服务。这种方式下,可以通过访问集群中任意节点+端口号的方式访问服务 <NodeIP>:<NodePort>(可以端口范围30000-32767),且此时 ClusterIP 的访问方式仍然可用。
  • 3) LoadBalancer: 在云环境中(需要云供应商可以支持)创建一个集群外部的负载均衡器,并为使用该负载均衡器的 IP 地址作为服务的访问地址。此时 ClusterIP 和 NodePort 的访问方式仍然可用


Service 关联的Pod创建一个Replication Control(简称RC) 其RC文件包括以下三个关键信息;

  • Pod定义
  • Pod运行的副本数量(Replicas)-后面讲解Scaling伸缩应用程序
  • Pod的被监控的目标标签(Label)


示例:nginx Deployment 创建一个 Service

  • (1) 上面创建nginx的Deployment中定义了Labels,如下:
    1
    2
    3
    4
    metadata:	#译名为元数据,即Deployment的一些基本属性和信息
    name: nginx-deployment #Deployment的名称
    labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组
    app: nginx #为该Deployment设置key为app,value为nginx的标签
  • (2) 创建编辑文件 nginx-service.yaml 内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $nano nginx-service.yaml
    apiVersion: v1 # k8s集群版本
    kind: Service # Service 资源控制器
    metadata:
    name: nginx-service #Service 的名称
    labels: #Service 自己的标签
    app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签
    spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
    selector: #标签选择器
    app: nginx #选择包含标签 app:nginx 的 Pod
    ports:
    - name: nginx-port #端口的名字
    protocol: TCP #协议类型 TCP/UDP
    port: 80 #集群内的其他容器组可通过 80 端口访问 Service
    nodePort: 30000 #通过任意节点的 30000 端口访问 Service ( The range of valid ports is 30000-32767)
    targetPort: 80 #将请求转发到匹配 Pod 的 80 端口
    type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
  • (3) 执行命令并检查执行结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #构建Deploymenet部署pod中的container,利用services中的Lables来关联已经创建的Container
    kubectl apply -f nginx-service.yaml
    service/nginx-service created

    #查看构建的services可查看到名称为 nginx-service 的服务
    kubectl get services -o wide
    # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    # kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40h <none>
    # nginx-service NodePort 10.96.63.155 <none> 80:30000/TCP 32s app=nginx
  • (4) 访问服务(在master或者worker中执行)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #Master
    [root@K8s ~]# curl http://10.10.107.191:30000/hello.html
    [root@K8s ~]# curl http://10.100.77.0:30000/hello.html #tunl0
    Hello World,Kubernetes!

    #Worker
    [root@K8s ~]# curl http://10.10.107.192:30000/hello.html
    [root@K8s ~]# curl http://10.100.167.128:30000/hello.html #tunl0
    Hello World,Kubernetes!

    #Node
    [root@K8s ~]# curl http://10.100.167.129:80/hello.html
    Hello World,Kubernetes!

    到目前为止,我们已经成功部署好项目,并能够对其进行访问!


4.伸缩应用程序
描述:当流量增加时,我们需要对应用程序进行伸缩操作以满足系统性能需求。而在K8s中伸缩(Scaling)的实现可以通过更改 nginx-deployment.yaml 文件中部署的 replicas(副本数)来完成;

Tips:我们前面创建了一个Deployment然后通过服务(Services)提供访问Pod的方式,下面通过更改部署中的 replicas(副本数)来完成扩展;

1
2
spec:
replicas: 2 #使用该Deployment创建两个应用程序实例

示例:下图中 Service A 只将访问流量转发到 IP 为 10.0.0.5 的Pod上修改了 Deployment 的 replicas 为 4 后,Kubernetes 又为该 Deployment 创建了 3 新的 Pod,这 4 个 Pod 有相同的标签。
因此Service A通过标签选择器与新的 Pod建立了对应关系,将访问流量通过负载均衡在 4 个 Pod 之间进行转发。

WeiyiGeek.Scaling

WeiyiGeek.Scaling

示例:将 nginx Deployment 扩容到 2 个副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1	#与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 2 #使用该Deployment创建一个应用程序实例(动态扩容)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问
ports:
- containerPort: 80

执行命令进行部署扩容

1
kubectl apply -f nginx-deployment.yaml

查看结果

1
watch kubectl get pods -o wide

WeiyiGeek.应用扩容

WeiyiGeek.应用扩容

应用访问:

1
2
3
4
5
6
7
[root@K8s ~]# curl http://10.100.167.132/test.html
<b>Scaling - 10.100.167.132</b>
[root@K8s ~]# curl http://10.100.167.131/test.html
<b>Scaling - 10.100.167.131</b>

#Cluster IP / Worker Node IP
http://10.10.107.191:30000/test.html

WeiyiGeek.应用负载均衡

WeiyiGeek.应用负载均衡

PS : 一旦运行了多个应用程序实例,就可以在不停机的情况下执行滚动更新了;


5.执行滚动更新
描述:在 Kubernetes 中通过 Rolling Update 滚动更新来进行应用版本的迭代部署,滚动更新允许以下操作:;

  • 将应用程序从准上线环境升级到生产环境(通过更新容器镜像)
  • 回滚到以前的版本
  • 持续集成和持续交付应用程序,无需停机

补充说明:

  • 将应用程序 Scale Up(扩容)为多个实例,这是执行更新而不影响应用程序可用性的前提(如果只有一个实例那就没得玩了)
  • k8s更新多副本的 Deployment 的版本时,会逐步的创建新版本的 Pod,逐步的停止旧版本的 Pod,以便使应用一直处于可用状态。(该过程中Service 能够监视 Pod 的状态,将流量始终转发到可用的 Pod 上)
  • 在K8S中更新是版本化的,任何部署更新都可以恢复为以前的(稳定)版本。

示例:

  • 1) 原本 Service A 将流量负载均衡到 4 个旧版本的 Pod (当中的容器为 绿色)上
  • 2) 更新完 Deployment 部署文件中的镜像版本后,master 节点选择了一个 worker 节点,并根据新的镜像版本创建 Pod(紫色容器)。
    • 新 Pod 拥有唯一的新的 IP, 同时 master 节点选择一个旧版本的 Pod 将其移除; 此时 Service A 将新 Pod 纳入到负载均衡中。
      WeiyiGeek.pod

      WeiyiGeek.pod

  • 3) 同步骤2再创建一个新的 Pod 替换一个原有的 Pod
  • 4) 如此 Rolling Update 滚动更新,直到所有旧版本 Pod 均移除,新版本 Pod 也达到 Deployment 部署文件中定义的副本数,则滚动更新完成
    WeiyiGeek.update

    WeiyiGeek.update

实例:更新 nginx Deployment
Step1.修改文件nginx-deployment-update.yaml中 image 镜像的标签,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1	#与k8s集群接口版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment # Deployment 资源控制器
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 2 #使用该Deployment创建一个应用程序实例(动态扩容)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:1.17.9 #使用镜像nginx:1.17.9替换原来的nginx:1.17.10
ports:
- containerPort: 80 #容器开放端口

Step2.执行部署命令与查看过程结果

1
2
3
4
5
6
7
8
9
10
11
12
#部署命令
kubectl apply -f nginx-deployment-update.yaml

#观察到 pod 逐个被替换的过程
watch kubectl get pods -l app=nginx

#替换版本查看
kubectl describe pods -l app=nginx | egrep "^Name:|Image:"
Name: nginx-deployment-b48955944-bz4xr
Image: nginx:1.17.9
Name: nginx-deployment-b48955944-ng6cs
Image: nginx:1.17.9

WeiyiGeek.滚动更新

WeiyiGeek.滚动更新