K8S指北

K8S指北

只要想做,办法总是有的!

文章目录


👉学习指路-kubernetes相关概念@skyflask

前置声明:本文是以@skyflask大佬的博客为学习指导,参考倪朋飞大神的《kubernetes指南》等大量网络资源,按己所需予以进一步扩充!HaveFun~

历史背景

img

统部署时代

​ 早期应用部署在物理机上,没有办法隔离物理资源,就会导致资源分配问题。

虚拟化部署时代

​ 对于传统部署中的问题,虚拟化是一个解决方案。他允许你在一个物理机上运行多个VM。虚拟化允许应用在VM之间进行隔离,并且应用在抢占资源方面也能够做到一定控制;但额外消耗较大

​ 虚拟化允许更好地使用资源:对于应用可以更好的伸缩资源,减少硬件成本。每个虚拟机是一个完整的机器,包括他自己的操作系统。

容器化部署时代

Kubernetes最初源于谷歌内部的Borg,提供了面向应用的容器集群部署和管理系统。
​ Kubernetes 的目标旨在消除编排物理/虚拟计算,网络和存储基础设施的负担,并使应用程序运营商和开发人员完全将重点放在以容器为中心的原语上进行自助运营。Kubernetes 也提供稳定、兼容的基础(平台),用于构建定制化的workflows 和更高级
的自动化任务。
​ Kubernetes 具备完善的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建负载均衡器、故障发现和自我修复能力、服务滚动升级和在线扩容、可扩展的资源自动调度机制、多粒度的资源配额管理能力。
​ Kubernetes 还提供完善的管理工具,涵盖开发、部署测试、运维监控等各个环节。

Borg简介
Borg是谷歌内部的大规模集群管理系统,负责对谷歌内部很多核心服务的调度和管理。
Borg的目的是让用户能够不必操心资源管理的问题,让他们专注于自己的核心业务,并且做到跨多个数据中心的资源利用率最大化。Borg主要由BorgMaster、Borglet、borgcfg和Scheduler组成,如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y7R2wjC8-1614949922741)(Kubernetes.assets/image-20210104101041823.png)]

  • BorgMaster是整个集群的大脑,负责维护整个集群的状态,并将数据持久化到
    Paxos存储中;
  • Scheduer负责任务的调度,根据应用的特点将其调度到具体的机器上去;
  • Borglet负责真正运行任务(在容器中);
  • borgcfg是Borg的命令行工具,用于跟Borg系统交互,一般通过一个配置文件来提
    交任务。

​ 容器和VM和相似,但是,他们已经将应用在不同操作系统之间进行了隔离。因此,容器可以看成是一个轻量级的VM,一个容器有他自己的文件系统、内容、处理空间等。此外,他和底层物理设施完全解耦,他们能够轻易的部署在云上。

容器变得越来越流行,因为他有好多优势。例如以下:

  • 敏捷的应用程序创建和部署: 与使用 VM 映像相比,容器映像创建更加容易和高效
  • 持续开发、集成和部署: 提供了可靠和频繁的容器映像构建和部署,并带有快速和简单的回滚(由于映像不可变)
  • 发和运维关注点分离: 在构建/发布时而不是部署时创建应用程序容器映像,从而将应用程序与基础设施分离
  • 可观测性不仅显示了操作系统级别的信息和指标,还显示了应用程序的健康状况和其他信号
  • 跨开发、测试和生产的环境一致性: 在笔记本电脑上运行和在云中运行一样
  • 云和操作系统发行版可移植性: 运行在 Ubuntu、 RHEL、 CoreOS、 on-prem、 Google Kubernetes Engine 和其他任何地方
  • 以应用程序为中心的管理: 提高了从在虚拟硬件上运行操作系统到使用逻辑资源在操作系统上运行应用程序的抽象级别
  • 松散耦合的、分布式的、弹性的、解放的微服务: 应用程序被分解成更小的、独立的部分,可以动态地部署和管理——而不是在一台大型单用途机器上运行的整体堆栈
  • 资源隔离: 可预测的应用程序性能
  • 资源利用率: 高效率、高密度

作用

  • kubernetes是一个容器编排平台

  • Kubernetes 提供了很多的功能,它可以简化应用程序的工作流,加快开发速度。通常,一个成功的应用编排系统需要有较强的自动化能力,这也是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。

  • 用户可以使用 Label 以自己的方式组织管理资源,还可以使用 Annotation 来自定义资源的描述信息,比如为管理工具提供状态检查等。

  • 此外,Kubernetes 控制器也是构建在跟开发人员和用户使用的统一的 API 之上。用户还可以编写自己的控制器和调度器,也可以通过各种插件机制扩展系统的功能。

    这种设计使得可以方便地在 Kubernetes 之上构建各种应用系统。

1、自我修复
在节点故障时重新启动失败的容器,替换和重新部署, 保证预期的副本数量;杀死健康检查失败的容器,并且在未准备好之前不会处理客户端请求,确保线上服务不中断。
2、弹性伸缩
使用命令、 UI或者基于CPU使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源, 以最小成本运行服务。
3、自动部署和回滚
K8S采用滚动更新策略更新应用,一次更新一个Pod,而不是同时删除所有Pod,如果更新过程中出现问题,将回滚更改, 确保升级不受影响业务。
4、服务发现和负载均衡
K8S为多个容器提供一个统一访问入口(内部IP地址和一个DNS名称),并且负载均衡关联的所有容器,使得用户无需考虑容器IP问题。
5、机密和配置管理
管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在K8S中,方便应用程序使用。
6、存储编排
挂载外部存储系统,无论是来自本地存储,公有云(如AWS),还是网络存储(如NFS、 GlusterFS、 Ceph)都作为集群资源的一部分使用,极大提高存储使用灵活性。
7、批处理
提供一次性任务和定时任务;满足批量数据处理和分析的场景。

核心组件

Kubernetes 主要由以下几个核心组件组成:

  • etcd 保存了整个集群的状态;(DB数据库)
  • api server提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;(API接口
  • controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;(控制资源
  • scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器Node上;(调度资源
  • kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;(容器管理
  • Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);(管理Pod
  • kube-proxy负责为 Service 提供 cluster 内部的**服务发现和负载均衡**(转发请求到内部服务

除了核心组件,还有一些推荐的Add-ons:

  • kube-dns负责为整个集群提供DNS服务

  • Ingress Controller为服务提供外网入口

  • Heapster提供资源监控

  • Dashboard提供GUI

  • Federation提供跨可用区的集群

  • Fluentd-elasticsearch提供集群日志采集、存储与查询

img

kubernetes核心概念

API设计原则

​ 以下几条原则:

  1. 所有API应该是声明式的。层与层之间定义的接口(interface),越接近现实的表达就叫越“声明式”(declarative),越接近计算机的执行过程就叫越“命令式”(imperative)。注意这不是绝对的概念,而是相对的概念。简单的说,接口的表述方式越接近人类语言——词汇的串行连接(一个词汇实际上是一个概念,告诉机器你要什么)——就越“声明式”;越接近计算机语言——“顺序+分支+循环”的操作流程(告诉机器做什么)——就越“命令式”。
  2. API对象是彼此互补而且可组合的。鼓励API对象尽量实现面向对象设计时的要求,即**“高内聚,松耦合”**,对业务相关的概念有一个合适的分解,提高分解出来的对象的可重用性
  3. 高层API以操作意图为基础设计。针对K8s的高层API设计,一定是以K8s的业务为基础出发,也就是以系统调度管理容器的操作意图为基础设计,而不是过早的从技术实现出发。
  4. 低层API根据高层API的控制需要设计。是为了被高层API使用,考虑减少冗余、提高重用性的目的
  5. 尽量避免简单封装不要有在外部API无法显式知道的内部隐藏的机制。例如PetSet和ReplicaSet,本来就是两种Pod集合,那么K8s就用不同API对象来定义它们。
  6. API操作复杂度与对象数量成正比。要保证整个系统随着系统规模的扩大,性能不会迅速变慢到无法使用,那么最低的限定就是API的操作复杂度不能超过O(N),N是对象的数量,否则系统就不具备水平伸缩性了
  7. API对象状态不能依赖于网络连接状态。在分布式环境下,网络连接断开是经常发生的事情。
  8. 尽量避免让操作机制依赖于全局状态。因为在分布式系统中要保证全局状态的同步是非常困难的。

控制机制设计原则

  • 控制逻辑应该只依赖于当前状态。有利于实现RPO和RTO操作(回滚操作)。
  • 假设任何错误的可能,并做容错处理。例如:代码报错,机器宕机等等。
  • 尽量避免复杂状态机,控制逻辑不要依赖无法监控的内部状态。如果两个子系统的控制逻辑如果互相有影响,那么子系统就一定要能互相访问到影响控制逻辑的状态,否则,就等同于系统里存在不确定的控制逻辑。
  • 假设任何操作都可能被任何操作对象拒绝,甚至被错误解析。不同子系统经常来自不同的开发团队。
  • 每个模块都可以在出错后自动恢复。因此每个模块要有自我修复的能力,保证不会因为连接不到其他模块而自我崩溃。
  • 每个模块都可以在必要时优雅地降级服务。要求在设计实现模块时划分清楚基本功能和高级功能,保证基本功能不会依赖高级功能。

API对象

​ API对象是K8s集群中的管理操作单元。3大类属性:

属性意义
metadata元数据元数据是用来标识API对象的,每个对象都至少有3个元数据:namespace,name和uid;除此以外还有各种各样的标签labels用来标识和匹配不同的对象
spec规范规范描述了用户期望K8s集群中的分布式系统达到的理想状态(Desired State)
status状态status描述了系统实际当前达到的状态(Status)
apiVersion: v1
kind: Pod
metadata: 
  name: nginx
  labels: 
    app: nginx
spec: 
  containers: 
  - name: nginx
    image: nginx
    ports: 
    - containerPort: 80

声明式操作在分布式系统中的好处是稳定,不怕丢操作或运行多次,例如设置副本数为3的操作运行多次也还是一个结果,而给副本数加1的操作就不是声明式的,运行多次结果就错了

Pod

​ Pod 是一组紧密关联的容器集合,它们共享 IPC(Inter-Process Communication,进程间通信)、Network 和 UTS namespace(UNIX Time-sharing System namespace,提供了主机名和域名的隔离),是 Kubernetes 调度的基本单位。Pod 的设计理念是支持多个容器在一个 Pod 中共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。

Pod 的特征

  • 包含多个共享 IPC、Network 和 UTC namespace 的容器可直接通过 localhost 通信
  • 所有 Pod 内容器都可以访问共享的 Volume,可以访问共享数据
  • 无容错性:直接创建的 Pod 一旦被调度后就跟 Node 绑定,即使 Node 挂掉也不会被重新调度(而是被自动删除),因此推荐使用 Deployment、Daemonset 等控制器来容错
  • 优雅终止:Pod 删除的时候先给其内的进程发送 SIGTERM,等待一段时间(grace period)后才强制停止依然还在运行的进程
  • 特权容器(通过 SecurityContext 配置)具有改变系统配置的权限(在网络插件中大量应用)
$ kubectl get pod
No resources found in default namespace.
$ kubectl get pod -n kubernetes-dashboard
NAME                                         READY   STATUS    RESTARTS   AGE
dashboard-metrics-scraper-7b59f7d4df-9pn2l   1/1     Running   0          7h26m
kubernetes-dashboard-665f4c5ff-qrk4t         1/1     Running   0          7h26m

Node

​ Node本质上不是Kubernetes来创建的,Kubernetes只是管理Node上的资源。虽然可以通过Manifest创建一个Node对象(如下json所示),但Kubernetes也只是去检查是否真的是有这么一个Node,如果检查失败,也不会往上调度Pod。

Node Controller负责

  • 维护Node状态
  • 与Cloud Provider同步Node
  • 给Node分配容器CIDR
  • 删除带有NoExecute taint的Node上的Pods

默认情况下,kubelet在启动时会向master注册自己,并创建Node资源。

Node的状态

每个Node都包括以下状态信息

  • 地址:包括hostname、外网IP和内网IP
  • 条件(Condition):包括OutOfDisk、Ready、MemoryPressure和DiskPressure
  • 容量(Capacity):Node上的可用资源,包括CPU、内存和Pod总数
  • 基本信息(Info):包括内核版本、容器引擎版本、OS类型等
$ kubectl get node
NAME             STATUS   ROLES    AGE     VERSION
docker-desktop   Ready    master   7h30m   v1.19.3

Namespace

​ Namespace是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的pods, services, replication controllers和deployments等都是属于某一个namespace的(默认是default),而node, persistentVolumes等则不属于任何namespace。

Namespace常用来隔离不同的用户

查询

$ kubectl get namespace
NAME                   STATUS   AGE
default                Active   7h29m
kube-node-lease        Active   7h29m
kube-public            Active   7h29m
kube-system            Active   7h29m
kubernetes-dashboard   Active   7h25m

创建
(1) 命令行直接创建

$ kubectl create namespace new-namespace

(2) 通过文件创建

$ cat my-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: new-namespace
$ kubectl create -f my-namespace.yaml

注意:命名空间名称满足正则表达式 [a-z0-9]([-a-z0-9]*[a-z0-9])? ,最大长度为63位

删除

$ kubectl delete namespaces new-namespace

注意:

  1. 删除一个namespace会自动删除所有属于该namespace的资源
  2. default 和 kube-system 命名空间不可删除
  3. PersistentVolumes和nodes是不属于任何namespace的,但PersistentVolumeClaim是属于
    某个特定namespace的
  4. Events是否属于namespace取决于产生events的对象

Lable

​ 标签其实就一对 key/value ,被关联到对象上,比如Pod,标签的使用我们倾向于能够标示对象的特殊特点,并且对用户而言是有意义的(就是一眼就看出了这个Pod是尼玛数据库),但是标签对内核系统是没有直接意义的。标签可以用来划分特定组的对象(比如,所有ssd设备),标签可以在创建一个对象的时候直接给与,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。

​ 合法的label值必须是63个或者更短的字符。要么是空,要么首位字符必须为字母数字字符,中间必须是横线,下划线,点或者数字字母。

与name和UID不同,label不提供唯一性。通常,我们会看到很多对象有着一样的label。

​ 通过label选择器,客户端/用户能方便辨识出一组对象。label选择器是kubernetes中核心的组织原语。

API目前支持两种选择器:基于相等的和基于集合的。一个label选择器一可以由多个必须条件组成,由逗号分隔。在多个必须条件指定的情况下,所有的条件都必须满足,因而逗号起着AND逻辑运算符的作用。

​ 一个空的label选择器(即有0个必须条件的选择器)会选择集合中的每一个对象。

​ 一个null型label选择器(仅对于可选的选择器字段才可能)不会返回任何对象。

kubernetes核心组件

Etcd

Etcd主要功能
  • 基本的key-value存储
  • 监听机制
  • key的过期及续约机制,用于监控和服务发现
  • 原子CAS和CAD,用于分布式锁和leader选举
Etcd基于RAFT的一致性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eji8UtT7-1614949922743)(Kubernetes.assets/image-20210119135350580.png)]

日志复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMK9rhDk-1614949922744)(Kubernetes.assets/image-20210119135644333.png)]

分布式系统如何保证一致性@新浪云计算

安全行

安全性是用于保证每个节点都执行相同序列的安全机制,如当某个Follower在当前
Leader commit Log时变得不可用了,稍后可能该Follower又会倍选举为Leader(此时自己的任期大),这时新
Leader可能会用新的Log(不含先前以commited log)覆盖先前已committed的Log,这就是导致节点执行不同序列;

Safety就是用于保证==选举出来的Leader一定包含先前 commited Log的机制==;

  • 选举安全性(Election Safety):每个任期(Term)只能选举出一个Leader

  • Leader完整性(Leader Completeness):指Leader日志的完整性,当Log在任期Term1被Commit后,那么以后任期Term2、Term3…等的Leader必须包含该Log;Raft在选举阶段就使用Term的判断用于保证完整性:当请求投票的该Candidate的Term较大或Term相同Index更大则投票,否则拒绝该请求。(为任期大的candidate投票)

失效处理

  1. Leader失效:其他没有收到heartbeat的节点会发起新的选举,而当Leader恢复后由于步进数小会自动成为follower(日志也会被新leader的日志覆盖)
    2)follower节点不可用:follower 节点不可用的情况相对容易解决。因为集群中的日志内容始终是从 leader 节点同步的,只要这一节点再次加入集群时重新从 leader节点处复制日志即可。
    3)多个candidate:冲突后candidate将随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上follower接受的candidate将成为leader
Etcd v2 与 v3
/nodes/1/name node1
/nodes/1/ip 192.168.1.1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnidFO0p-1614949922745)(Kubernetes.assets/image-20210119142558250.png)]

​ Etcd v2 是个纯内存的实现,并未实时将数据写入到磁盘,持久化机制很简单,就是将store整合序列化成json写入文件。数据在内存中是一个简单的树结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqHOhlty-1614949922745)(Kubernetes.assets/image-20210119143551236.png)]

​ Etcd v3 将watch和store拆开实现;

Etcd辅助工具
Confd

配置变更工具Confd:提供一个配置文件模板,通过watch机制监听 Etcd 的变更,然后将数据同步到自己的一个本地存储用户可以通过配置定义自己关注那些key的变更.

Metad

Metad 提供这样一种机制,客户端请求 Metad 的一个固定的接口 /self,由 Metad 告知应用程序其所属的元信息,简化了客户端的服务发现和配置变更逻辑

API Server

集群管理接口,模块交互和通信枢纽

  • 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
  • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改
    数据,只有API Server才直接操作etcd)
访问控制

Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证授权以及准入控制(Admission Control)等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0YNNfgWP-1614949922746)(Kubernetes.assets/image-20210119155633147.png)]

工作原理

kube-apiserver提供了Kubernetes的REST API,实现了认证、授权、准入控制等安全校验功能,同时也==负责集群存储的操作==[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILhxFNkz-1614949922746)(Kubernetes.assets/image-20210119160057230.png)]

kube-scheduler

kube-scheduler负责==分配调度Pod到集群内的节点上==,它监听kube-apiserver(获取集群状态信息),查询还未分配Node的Pod,然后根据调度策略为这些Pod分配节点(更新Pod的 NodeName 字段)

调度器需要充分考虑诸多的因素:

  • 公平调度
  • 资源高效利用
  • QoS
  • affinity 和 anti-affinity根据亲和力选择调度node
  • taints(node)和tolerations(pod)保证pod不被调度到不合适的node
  • 数据本地化(data locality)
  • 内部负载干扰(inter-workload interference)
  • deadlines

Controller Manager

Kubernetes的大脑,它==通过apiserver监控整个集群的状态,并确保集群处于预期的工作==
状态。

kube-controller-manager由一系列的控制器组成

  • Replication Controller

  • Node Controller

  • CronJob Controller

  • Daemon Controller

  • Deployment Controller

  • Endpoint Controller

  • Garbage Collector

  • Namespace Controller

  • Job Controller

  • Pod AutoScaler

  • RelicaSet

  • Service Controller

  • ServiceAccount Controller

  • StatefulSet Controller

  • Volume Controller

  • Resource quota Controller

cloud-controller-manager在Kubernetes启用Cloud Provider的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如

  • Node Controller
  • Route Controller
  • Service Controlle
如何保证高可用

在启动时设置 --leader-elect=true 后,controller manager会使用多节点选主的方式
选择主节点。只有主节点才会调用 StartControllers() 启动所有控制器,而其他从
节点则仅执行选主算法。

如何保证高性能

从Kubernetes 1.7开始,所有需要监控资源变化情况的调用均推荐使用Informer。
Informer提供了基于事件通知的只读缓存机制,可以注册资源变化的回调函数,并可以
极大减少API的调用。

Kubelet

每个节点上都运行一个kubelet服务进程,默认监听10250端口,接收并执行master发来的指令,管理Node的Pod及Pod中的容器每kubelet进程会在API Server上注册节点自身信息(自注册),定期向master节点汇报节点的资源使用情况,API Server在接收到新消息后,将信息写入etcd;kubelet通过cAdvisor监控节点和容器的资源

Kubelet通过API Server Client(Kubelet启动时创建)使用Watch加List的方式监听"/registry/nodes/$当前节点名"和“/registry/pods”目录,将获取的信息同步到本地缓存中。Kubelet监听etcd,所有针对Pod的操作都将会被Kubelet监听到。

Kubelet定期调用容器中的LivenessProbe探针来诊断容器的健康状况。LivenessProbe
包含如下三种实现方式:

  • ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为0,则表明容器健康;
  • TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果端口能被访问,则表明容器健康;
  • HTTPGetAction:通过容器的IP地址和端口号及路径调用HTTP GET方法,如果响应的状态码大于等于200且小于400,则认为容器状态健康。LivenessProbe探针包含在Pod定义的spec.containers.{某个容器}中。
kubelet工作原理

img

如下kubelet内部组件结构图所示,Kubelet由许多内部组件构成

  • Kubelet API,包括10250端口的认证API、4194端口的cAdvisor API、10255端口的只读API以及10248端口的健康检查API
  • syncLoop:从API或者manifest目录接收Pod更新,发送到podWorkers处理,大量使用channel处理来处理异步请求
  • 辅助的manager,如cAdvisor、PLEG、Volume Manager等,处理syncLoop以外的其他工作
  • CRI:容器执行引擎接口,负责与container runtime shim通信
  • 容器执行引擎,如dockershim、rkt等(注:rkt暂未完成CRI的迁移)
  • 网络插件,目前支持CNI和kubenet [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ed6W7yZF-1614949922748)(Kubernetes.assets/image-20210120123029563.png)]

容器运行时

容器运行时(Container Runtime)是Kubernetes最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet通过Container Runtime Interface (CRI)与容器运行时交互,以管理镜像和容器。

CRI

Container Runtime Interface (CRI)是Kubelet 1.5/1.6中主要负责的一块项目,它重新定义了Kubelet Container Runtime API,将原来完全面向Pod级别的API拆分成面向Sandbox和Container的API,并分离镜像管理和容器引擎到不同的服务。

kube-proxy

每台机器上都运行一个kube-proxy服务,它监听API server中service和endpoint的变化情况,并通过iptables(DNAT)等来为服务配置负载均衡(仅支持TCP和UDP)

kube-proxy可以直接运行在物理机上,也可以以static pod或者daemonset的方式运行。img

kube-dns

kube-dns为Kubernetes集群提供命名服务,一般通过addon(kube-system的svc工作)的方式部署,从v1.3版本开始,成为了一个内建的自启动服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqQLwUIK-1614949922748)(Kubernetes.assets/image-20210120124258256.png)]

以环境变量的形式注入每一个pod:/etc/resolv.conf[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xum5eAYa-1614949922749)(Kubernetes.assets/image-20210120124454237.png)]

支持配置私有DNS服务器和上游DNS服务器
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {“acme.local”: [“1.2.3.4”]}
  upstreamNameservers: |
    [“8.8.8.8”, “8.8.4.4”]

使用上述特定配置,查询请求首先会被发送到kube-dns的DNS缓存层(Dnsmasq 服务器)。Dnsmasq服务器会先检查请求的后缀,带有集群后缀(例如:”.cluster.local”)的请求会被发往kube-dns(dnsPolicy=ClusterFirst),拥有存根域后缀的名称(例如:”.acme.local”)将会被发送到配置的私有DNS服务器[“1.2.3.4”]。最后,不满足任何这些后缀的请求将会被发送到上游DNS [“8.8.8.8”, “8.8.4.4”]里。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDbpEPvK-1614949922749)(Kubernetes.assets/image-20210120124747411.png)]

工作原理[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BkDvdSez-1614949922749)(Kubernetes.assets/image-20210120124809870.png)]

Federation

​ 在云计算环境中,服务的作用距离范围从近到远一般可以有:同主机(Host,Node)、跨主机同可用区(Available Zone)、跨可用区同地区(Region)、跨地区同服务商(Cloud Service Provider)、跨云平台。K8s的设计定位是单一集群在同一个地域内,因为同一个地区的网络性能才能满足K8s的调度和计算存储连接要求。而集群联邦(Federation)就是为提供跨Region跨服务商K8s集群服务而设计的。每个Federation有自己的分布式存储Etcd、API Server和Controller Manager。用户可以通过Federation的API Server注册该Federation的成员K8s Cluster。当用户通过Federation的API Server创建、更改API对象时,Federation API Server会在自己所有注册的子K8sCluster都创建一份对应的API对象。在提供业务请求服务时,K8s Federation会先在自己的各个子Cluster之间做负载均衡,而对于发送到某个具体K8s Cluster的业务请求,会依照这个K8s Cluster独立提供服务时一样的调度模式去做K8s Cluster内部的负载均衡。而Cluster之间的负载均衡是通过域名服务的负载均衡来实现的。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UX61UinV-1614949922750)(Kubernetes.assets/image-20210120134510330.png)]

kubernetes资源控制

HPA

Horizontal Pod Autoscaling (HPA) 可以根据 CPU 使用率应用自定义 metrics 自动扩展 Pod 数量

(支持 replication controller、deployment 和 replica set )。

# 命令行设置
$ kubectl autoscale deploy nginx-app --cpu-percent=80 --min=1 --max=3
# 查看
$ kubectl get hpa
NAME        REFERENCE              TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
nginx-app   Deployment/nginx-app   <unknown>/80%   1         3         1          4d18h
# 修改
$ kubectl edit hpa/nginx-app
horizontalpodautoscaler.autoscaling/nginx-app edited
自定义metric度量值

使用方法

  • 控制管理器开启 --horizontal-pod-autoscaler-use-rest-clients

  • 控制管理器的 --apiserver 指向API Server Aggregator

  • 在API Server Aggregator中注册自定义的metrics API

    注:可以参考k8s.io/metics开发自定义的metrics API server。
    比如HorizontalPodAutoscaler保证每个Pod占用50% CPU、1000pps以及10000请求/s:

HPA示例 :

apiVersion: autoscaling/v2alpha1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-app
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-app
  minReplicas: 1
  maxReplicas: 3
  # 定义多个度量值
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 50
  - type: Pods
    pods:
      metricName: packets-per-second
      targetAverageValue: 1k
  - type: Object
    object:
      metricName: requests-per-second
      target:
        apiVersion: extensions/v1beta1
        kind: Ingress
        name: main-route
      targetValue: 10k
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      currentAverageUtilization: 0
      currentAverageValue: 0        

Replication Controller(RC)

Replication Controller 保证了在所有时间内,都有特定数量的Pod副本正在运行!replication controller的任务永远都只会是单一的。它自身不会进行是否可读和是否可用的检测,相比与自动进行缩放和放大,replication controller更倾向与使用外部的自动平衡工具,这些外部工具要作的仅仅是修改replicas的值来实现Pod数量的变化,我们不会增加replication controller的调度策率,也不会让replication controller来验证受控的Pod是否符合特定的模版,因为这些都会阻碍自动调整和其它的自动的进程。类似的,完成时限,需求依赖,配置扩展,等等都属于其它的部分。

Taints和tolerations

​ Taints和tolerations用于保证Pod不被调度到不合适的Node上Taint应用于Node上,而toleration则应用于Pod上(Toleration是可选的)。

​ 比如,可以使用taint命令给node1添加taints:

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value2:NoExecute

Taints和tolerations的具体使用方法请参考调度器章节

Node维护模式

标志Node不可调度但不影响其上正在运行的Pod,这种维护Node时是非常有用的

kubectl cordon $NODENAM

ReplicaSet(RS)

​ ReplicaSet可确保指定数量的pod“replicas”在任何设定的时间运行。然而,Deployments是一个更高层次的概念,它管理ReplicaSets,并提供对pod的声明性更新以及许多其他的功能。因此,我们建议您使用Deployments而不是直接使用ReplicaSets,除非您需要自定义更新编排或根本不需要更新。

Services

​ Kubernetes Pod是平凡的,它门会被创建,也会死掉,并且他们是不可复活的。 ReplicationControllers动态的创建和销毁Pods(比如规模扩大或者缩小,或者执行动态更新)。每个pod都由自己的ip,这些IP也随着时间的变化也不能持续依赖。这样就引发了一个问题:如果一些Pods(让我们叫它作后台,后端)提供了一些功能供其它的Pod使用(让我们叫作前台),在kubernete集群中是如何实现让这些前台能够持续的追踪到这些后台的?

答案是:Service

Service提供cluster内部的负载均衡,要借助cloud provider提供的LB提供外部访问

[pod]$ cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
$ kubectl get svc -n kube-system -o wide
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE    SELECTOR
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   3d7h   k8s-app=kube-dns

​ Kubernete Service 是一个定义了一组Pod的策略的抽象,我们也有时候叫做宏观服务。这些被服务标记的Pod都是(一般)通过*label Selector*决定的(下面我们会讲到我们为什么需要一个没有label selector的服务)

​ 举个例子,我们假设后台是一个图形处理的后台,并且由3个副本。这些副本是可以相互替代的,并且前台并需要关心使用的哪一个后台Pod,当这个承载前台请求的pod发生变化时,前台并不需要知道这些变化,或者追踪后台的这些副本,服务解耦.

对于Kubernete原生的应用,Kubernete提供了一个*简单的Endpoints API,这个Endpoints api的作用就是当一个服务中的pod发生变化时,Endpoints API随之变化,对于哪些不是原生的程序,Kubernetes提供了一个基于虚拟IP的网桥的服务*,这个服务会将请求转发到对应的后台pod。

Service有四种类型:
  • ClusterIP:默认类型,自动分配一个仅cluster内部可以访问的虚拟IP
  • NodePort:在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以
    通过 :NodePort 来访问该服务
  • LoadBalancer:在NodePort的基础上,借助cloud provider创建一个外部的负载均
    衡器,并将请求转发到 :NodePort
  • ExternalName:将服务通过DNS CNAME记录方式转发到指定的域名(通
    过 spec.externlName 设定)。需要kube-dns版本在1.7以上。
  • 另外,也可以将已有的服务以Service的形式加入到Kubernetes集群中来,只需要在创建
    Service的时候不指定Label selector,而是在Service创建好后手动为其添加endpoint。

Deployment

​ deployment负责控制Pod的生命周期、保证服务有一定数量的Pod在运行。Deployment定义了Pod内容,包括Pod数量、更新方式、使用的镜像,资源限制等等

● deployment调度replicaset,pod由replicaset调度
● deployment管理多个replicaset版本,可用于回滚
replicaset控制pod的行为,包括新增pod、删除pod

​ 当我们更新这个Deployment的时候,它会创建一个新的Replica Set(当我们更新这个Deployment的时候,它会创建一个新的Replica Set(如果没有已存在的,合适的));最终,将会在新的Replica Set中有原来个可用的replica,旧的Replica Set的replica数目变成0。修改更新配置可具体化更新过程!

img

扩容
$ kubectl scale deployment nginx-deployment --replicas 10
horizontal pod autoscaling

如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展:

$ kubectl autoscale deployment nginx-app --min=10 --max=15 --cpu-percent=80
horizontalpodautoscaler.autoscaling/nginx-app autoscaled
更新镜像

rollout可以对Deployment、DaemonSet和StatefulSet的rollout进行控制

子命令功能说明
history查看rollout操作历史
pause将提供的资源设定为暂停状态
restart重启某资源
resume将某资源从暂停状态恢复正常
status查看rollout操作状态
undo回滚前一rollout
Manage the rollout of a resource.

 Valid resource types include:

  *  deployments
  *  daemonsets
  *  statefulsets
 Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc

  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo

Available Commands:
  history     View rollout history
  pause       Mark the provided resource as paused
  restart     Restart a resource
  resume      Resume a paused resource
  status      Show the status of the rollout
  undo        Undo a previous rollout

Usage:
  kubectl rollout SUBCOMMAND [options]

$ kubectl set image deployment/nginx-app nginx=nginx:1.18
deployment.apps/nginx-app image updated
# rollout状态监控
$ kubectl rollout status deployments nginx-app
deployment "nginx-app" successfully rolled out
回滚
$ kubectl rollout undo deployment/nginx-app
deployment.apps/nginx-app rolled back
$ kubectl rollout undo deployment/nginx-app --to-revision=1
清理Policy

​ 你可以通过设置.spec.revisonHistoryLimit项来指定deployment最多保留多少
revison历史记录。默认的会保留所有的revision;如果将该项设置为0,Deployment就
不允许回退了。

比例扩容

​ 当你或者autoscaler扩容一个正在**rollout中(进行中或者已经暂停)**的 RollingUpdate Deployment的时候,为了降低风险,Deployment controller将会平衡已存在的active的ReplicaSets(有Pod的ReplicaSets)和新加入的replicas。这被称为比例扩容。

更新deployment

​ .spec.strategy 指定新的Pod替换旧的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 “RollingUpdate”。"RollingUpdate"是默认值。

  • Recreate Deployment
    .spec.strategy.type==Recreate 时,在创建出新的Pod之前会先杀掉所有已存在的Pod

  • Rolling Update Deployment

    .spec.strategy.type==RollingUpdate 时,Deployment使用rolling update 的方式更新Pod(创建一批新的,再删除一批旧的) 。你可以指定 maxUnavailable 和 maxSurge 来控制 rolling update 进程。

    • Max Unavailable

      .spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指定在升级过程中不可用Pod的最大数量。该值可以是一个绝对值(例如5),也可以是期望Pod数量的百分比(例如10%)。

    • Max Surge
      .spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期望的Pod数量的最大个数。

  • Progress Deadline Seconds
    .spec.progressDeadlineSeconds 是可选配置项,用来指定在系统报告Deployment的failed progressing ——表现为resource的状态
    中 type=Progressing 、 Status=False 、Reason=ProgressDeadlineExceeded 前可以等待的Deployment进行的秒数。Deployment controller会继续重试该Deployment。未来,在实现了自动回滚后,deployment controller在观察到这种状态时就会自动回滚。如果设置该参数,该值必须大于 .spec.minReadySeconds 。

  • Min Ready Seconds
    .spec.minReadySeconds 是一个可选配置项,用来指定没有任何容器crash的Pod并被认为是可用状态的最小秒数。默认0(Pod在ready后就会被认为是可用状态)。进一步了解什么时候Pod会被认为是ready状态,参阅 Container Probes。

  • Rollback To
    .spec.rollbackTo 是一个可以选配置项,用来配置Deployment回退的配置。设置该参数将触发回退操作,每次回退完成后,该值就会被清除。

  • Revision
    .spec.rollbackTo.revision 是一个可选配置项,用来指定回退到的revision。默认
    是0,意味着回退到历史中最老的revision。

  • Revision History Limit
    Deployment revision history存储在它控制的ReplicaSets中。.spec.revisionHistoryLimit 是一个可选配置项,用来指定可以保留的旧的

  • Paused
    .spec.paused 是可以可选配置项,boolean值。用来指定暂停和恢复Deployment。Paused和非paused的Deployment之间的唯一区别就是,所有对paused deployment中的PodTemplateSpec的修改都不会触发新的rollout**。Deployment被创建之后默认非paused。

暂停和恢复Deployment

​ Deployment暂停前的初始状态将继续它的功能,而不会对Deployment的更新产生任何影响,只要Deployment是暂停的。

因为它只是暂停了去更新!resume后将创建新的RS去更新。

$ kubectl rollout pause deployment/nginx-app
$ kubectl set image deploy/nginx nginx=nginx:1.19
$ kubectl set resources deployment nginx-app -c=nginx --limits=cpu=250m,memory=128Mi
$ kubectl rollout history deploy/nginx-app
$ kubectl rollout resume deploy nginx-app

StatefullSet

​ 使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个来保证可用性,但是由于是无状态的,Pod挂了的时候与之前的Volume的关系就已经断开了,新起来的Pod无法找到之前的Pod。但是对于用户而言,他们对底层的Pod挂了没有感知,但是当Pod挂了之后就无法再使用之前挂载的磁盘了。

解决方案?

​ 使用K8s v1.5版本推出的StatefulSet可以保留Pod的状态。

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称、启停顺序;在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
以redis cluster为例,由于各redis container 的角色不一定相同(有master、slave之分),所以每个redis container被重建之后必须保持原有的hostname,必须挂载原有的volume,这样才能保证每个shard内是正常的。而且每个redis shard 所管理的slot不同,存储的数据不同,所以要求每个redis shard 所连接的存储不同,保证数据不会被覆盖或混乱。(注:在Deployment中 Pod template里定义的存储卷,所有副本集共用一个存储卷,数据是相同的,因为Pod创建时基于同一模板生成)
为了保证container所挂载的volume不会出错,k8s引入了volumeClaimTemplate。
所以具有以下特性的应用使用statefullSet

使用场景
  • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC
    来实现
  • 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless
    Service(即没有Cluster IP的Service)来实现
  • 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺
    序依次依序进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是
  • Running和Ready状态),基于init containers来实现
    有序收缩,有序删除(即从N-1到0)

对于一个完整的StatefulSet应用由三个部分组成: headless service、StatefulSet controller、volumeClaimTemplate

部分组成

StatefulSet由以下几个部分组成:

  • 用于定义网络标志(DNS domain)的Headless Service
  • 用于创建PersistentVolumes的volumeClaimTemplates
  • 定义具体应用的StatefulSet

StatefulSet中每个Pod的DNS格式为 statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local

更新StatefulSet

v1.7+支持StatefulSet的自动更新,通过 spec.updateStrategy 设置更新策略。目前支持两种策略

  • OnDelete:当 .spec.template 更新时,并不立即删除旧的Pod,而是等待用户手动删除这些旧Pod后自动创建新Pod。这是默认的更新策略,兼容v1.6版本的行为
  • RollingUpdate:当 .spec.template 更新时,自动删除旧的Pod并创建新Pod替换。在更新时,这些Pod是按逆序的方式进行,依次删除、创建并等待Pod变成StatefulSetReady状态才进行下一个Pod的更新
    • 支持Partitions,通过 .spec.updateStrategy.rollingUpdate.partition 来设置。当partition设置后,只有序号大于或等partition的Pod会在 .spec.template 更新的时候滚动更新(默认0),而其余的Pod则保持不变(即便是删除后也是用以前的版本重新创建)。
管理pod策略

v1.7+可以通过.spec.podManagementPolicy 设置Pod管理策略,支持两种方式

  • OrderedReady:默认的策略,按照Pod的次序依次创建每个Pod并等待Ready之后
    才创建后面的Pod
  • Parallel:并行创建或删除Pod(不等待前面的Pod Ready就开始创建所有的Pod)

DaemonSet

DaemonSet 可以保证集群中所有的或者部分的节点都能够运行同一份 Pod 副本,每当有新的节点被加入到集群时,Pod 就会在目标的节点上启动,如果节点被从集群中剔除,节点上的 Pod 也会被垃圾收集器清除;

DaemonSet 的作用就像是计算机中的守护进程,它能够运行集群存储、日志收集和监控等『守护进程』,这些服务一般是集群中必备的基础服务

Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能运行好几个副本。

DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本

DaemonSet 的典型应用场景有:

  1. 在集群的每个节点上运行存储 Daemon,比如 glusterd 或 ceph。
  2. 在每个节点上运行日志收集 Daemon,比如 flunentd 或 logstash。
  3. 在每个节点上运行监控 Daemon,比如 Prometheus Node Exporter 或 collectd。
滚动更新
  • OnDelete:默认策略,更新模板后,只有手动删除了旧的Pod后才会创建新的Pod
  • RollingUpdate:更新DaemonSet模版后,自动删除旧的Pod并创建新的Pod
指定Node节点

DaemonSet会忽略Node的unschedulable状态,有两种方式来指定Pod只运行在指定的
Node节点上:

  • nodeSelector:只调度到匹配指定label的Node上
  • nodeAffinity:功能更丰富的Node选择器,比如支持集合操作
  • podAffinity:调度到满足条件的Pod所在的Node上
spec:
  nodeSelector:
    disktype: ssd
spec:
    affinity:
      nodeAffinity:
      	# 必须满足的条件
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
        # 优选条件
    	preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
            - key: another-node-label-key
              operator: In
              values:
            - another-node-label-value
spec:
    affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - S1
        	topologyKey: failure-domain.beta.kubernetes.io/zone
        podAntiAffinity:
    		preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
            	labelSelector:
                  matchExpressions:
                  - key: security
                    operator: In
                    values:
                    - S2
        	    topologyKey: kubernetes.io/hostname
静态Pod

​ 除了DaemonSet,还可以使用静态Pod来在每台机器上运行指定的Pod,这需要kubelet
在启动的时候指定manifest目录:

kubelet --pod-manifest-path=/etc/kubernetes/manifests

然后将所需要的Pod定义文件放到指定的manifest目录中。
注意:静态Pod不能通过API Server来删除,但可以通过删除manifest文件来自动删除对
应的Pod

ReplicationController和ReplicaSet

​ ReplicationController(也简称为rc)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而异常多出来的容器也会自动回收。ReplicationController的典型应用场景包括确保健康Pod的数量、弹性伸缩、滚动升级以及应用多版本发布跟踪等。

  • ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector(ReplicationController仅支持等式)。

    • replicaController
     selector:
         app: nginx
    
    • replicaSet
     selector:
         matchLabels:
           tier: frontend
         matchExpressions:
           - {key: tier, operator: In, values: [frontend]}
    

CrontJob

CronJob即定时任务,就类似于Linux系统的crontab,在指定的时间周期运行指定的任务。在Kubernetes 1.5,使用CronJob需要开启batch/v2alpha1 API,即–runtime-config=batch/v2alpha1。

CronJob Spec

  • .spec.schedule指定任务运行周期,格式同Cron,schedule格式说明
  • .spec.jobTemplate指定需要运行的任务,格式同Job
  • .spec.startingDeadlineSeconds指定任务开始的截止期限
  • .spec.concurrencyPolicy指定任务的并发策略,支持Allow、Forbid和Replace三个选项
apiVersion: batch/v2alpha1
kind: CronJob
metadata:
  name: cronjob-demo
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: hello
            image: busybox
            args:
            - "bin/sh"
            - "-c"
            - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

Job

​ Kubernetes 中的 Job 可以创建并且保证一定数量 Pod 的成功停止,当 Job 持有的一个 Pod 对象成功完成任务之后,Job 就会记录这一次 Pod 的成功运行;当一定数量的Pod 的任务执行结束之后,当前的 Job 就会将它自己的状态标记成结束。

  • .spec.completions 标志job结束需要成功运行的pod个数
  • .spec.parallelism 标志并行运行pod的个数
apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  completions: 3
  parallelism: 1
  template:
    metadata:
      name: job-demo
    spec:
      restartPolicy: Never
      containers:
      - name: pi
        image: perl
        command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
$ kubectl logs job-demo-5pqh6
3.141592653589793238462643383279502884197169399375105820974944...
Bare Pods

​ 所谓Bare Pods是指直接用PodSpec来创建的Pod(即不在ReplicaSets或者ReplicationCtroller的管理之下的Pods)。这些Pod在Node重启后不会自动重启,但Job则会创建新的Pod继续任务。所以,推荐使用Job来替代Bare Pods,即便是应用只需要一个Pod。

Resource Quotas

资源配额(Resource Quotas)是用来限制namespace用户资源用量的一种机制

它的工作原理为

  • 资源配额应用在Namespace上,并且每个Namespace最多只能有一个ResourceQuota对象
  • 开启计算资源配额后,创建容器时必须配置计算资源请求或限制(也可以用LimitRange设置默认值)
  • 用户超额后禁止创建新的资源

资源配额的启用

首先,在API Server启动时配置ResourceQuota adminssion control;然后在namespace中创建ResourceQuota对象即可。

资源配额的类型

  • 计算资源,包括cpu和memory
    • cpu, limits.cpu, requests.cpu
    • memory, limits.memory, requests.memory
  • 存储资源,包括存储资源的总量以及指定storage class的总量
    • requests.storage:存储资源总量,如500Gi
    • persistentvolumeclaims:pvc的个数
    • .storageclass.storage.k8s.io/requests.storage
    • .storageclass.storage.k8s.io/persistentvolumeclaims
  • 对象数,即可创建的对象的个数
    • pods, replicationcontrollers, configmaps, secrets
    • resourcequotas, persistentvolumeclaims
    • services, services.loadbalancers, services.nodeports

LimitRange

​ 默认情况下,Kubernetes中所有容器都没有任何CPU和内存限制。LimitRange用来给Namespace增加一个资源限制,包括最小、最大和默认资源。比如

NetWork Policy

​ Network Policy提供了基于策略的网络控制,用于隔离应用并减少攻击面。它使用标签选择器模拟传统的分段网络,并通过策略控制它们之间的流量以及来自外部的流量。

在使用Network Policy之前,需要注意

  • apiserver开启extensions/v1beta1/networkpolicies
  • 网络插件要支持Network Policy,如Calico、Romana、Weave Net和trireme等

策略

1、Namespace隔离

​ 默认情况下,所有Pod之间是全通的。每个Namespace可以配置独立的网络策略,来隔离Pod之间的流量。比如隔离namespace的所有Pod之间的流量(包括从外部到该namespace中所有Pod的流量以及namespace内部Pod相互之间的流量):

注:目前,Network Policy支持Ingress,egress流量控制。

namespace scoped(名字空间范围)

# 默认pod网络模式
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector:
  ingress:
  - {}
  egress:
  - {}

2、Pod隔离

​ 通过使用标签选择器(包括namespaceSelector和podSelector)来控制Pod之间的流量。比如下面的Network Policy

  • 允许default namespace中带有run=busybox标签的Pod访问default namespace中带有app=nginx标签Pod的80端口
  • 允许带有project=alifys标签的namespace中所有Pod访问default namespace中带有app=nginx标签Pod的80端口

详细配置

apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: nginx
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: alifys
    - podSelector:
        matchLabels:
          run: busybox
    ports:
    - protocol: tcp
      port: 80
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978
实现机制
  1. 对networkpolicy进行全namespace范围的list & watch;
  2. 对规则原语的解析和定制。(如何将namespace、label等概念具象到iptables中?我的想法比较笨拙:使用正则表达式表述pod name的规则,同时list-watch pod并维护pod name 到pod ip的关系)
  3. 维护这些规则在本地的实现和记录(如iptables表)

安全组的规则记录在上层网关,而不是每一个节点上在安全组规则上,可能需要list watch networkPolicy、namespace、pod等资源,因此实现namespace级别的策略可能会影响其性能

Ingress

什么是Ingress?

​ “智能路由”或者集群入口的角色。

​ 通常情况下,service和pod的IP仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到service在Node上暴露的NodePort上,然后再由kube-proxy将其转发给相关的Pod。

而Ingress就是为进入集群的请求提供路由规则的集合。

Ingress 为 Kubernetes 集群中的服务提供了外部入口以及路由,而 Ingress Controller 监测 Ingress 和 Service 资源的变更并根据规则配置负载均衡、路由规则和 DNS 等并提供访问入口。

​ Ingress Controller 实质上可以理解为是个监视器,Ingress Controller 通过不断地跟kubernetes API 打交道,实时的感知后端 service、pod 等变化,比如新增和减少 pod,service 增加与减少等;当得到这些变化信息后,Ingress Controller 再结合下文的Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用。

注意Ingress本身并不会自动创建负载均衡器,cluster中需要运行一个ingress controller
来根据Ingress的定义来管理负载均衡器。

​ GKE 上的默认 ingress 控制器是启动一个 HTTP(S) Load Balancer。它允许你基于路径或者子域名来路由流量到后端服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vFbmmGOk-1614949922751)(Kubernetes.assets/image-20210105170117852.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KPVFhnT5-1614949922752)(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimgedu.lagou.com%2Fup-2dde69beb3adc141160003a1f9d4033ccad.png&refer=http%3A%2F%2Fimgedu.lagou.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1612429360&t=2027b163d9544df6ec0003dae779e2ff)]

TLS Ingress

​ 如果Ingress中的TLS配置部分指定了不同的主机,则它们将根据通过SNI TLS扩展指定的主机名(假如Ingress controller支持SNI)在多个相同端口上进行复用。

apiVersion: v1
kind: Secret
metadata:
  name: tls-secret
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: Opaque
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  tls:
  - hosts:
    - a.example.com
    - b.example.com
    secretName: tls-secret
  rules:
  - host: '*.example.com'
    http:
      paths: 
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80

ConfigMap

为了把配置文件从image中解耦,增强应用的可移植性、可复用性,k8s提供了configmap和seret。

configmap就是一系列配置数据的集合。而这些数据将来可以注入到pod中的container中

注入方式
  1. 把configmap做存存储卷,然后挂载;

  2. 使用ENV的valueFrom方式去引用configmap中所保存的数据。

  3. configmap中保存着k:v格式的数据。value长度没有限制。pod启动时可以到configmap中获取相关的配置项

创建方式
从key-value字符串创建
$ kubectl create configmap special-config --from-literal=special.how=
very
configmap "special-config" created
$ kubectl get configmap special-config -o go-template='{{.data}}'
map[special.how:very]
从env文件创建
$ echo -e "a=b\nc=d" | tee config.env
a=b
c=d
$ kubectl create configmap special-config --from-env-file=config.env
configmap "special-config" created
$ kubectl get configmap special-config -o go-template='{{.data}}'
map[a:b c:d]
从目录创建
$ mkdir config
$ echo a>config/a
$ echo b>config/b
$ kubectl create configmap special-config --from-file=config/
configmap "special-config" created
$ kubectl get configmap special-config -o go-template='{{.data}}'
map[a:a
b:b
]
从文件Yaml/Json文件创建
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
$ kubectl create -f config.yaml
configmap "special-config" created

Secret

​ Secret是用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。

​ Secret可以以Volume或者环境变量的方式使用。

Secret三种类型
  • Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动
    挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中,以提供pod访问资源权限;
  • Opaque:base64编码格式的Secret,用来存储密码、密钥等;
  • kubernetes.io/dockerconfigjson :用来存储私有docker registry的认证信息。
$ kubectl create secret -h
`Create a secret using specified subcommand.

Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic         Create a secret from a local file, directory or literal value
  tls             Create a TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
$ kubectl create secret generic -h
`Create a secret based on a file, directory, or specified literal value.

 A single secret may package one or more key/value pairs.

 When creating a secret based on a file, the key will default to the basename of the file, and the value will default to the file content. If the basename is an invalid key or you wish to chose your own, you may specify an alternate key.

 When creating a secret based on a directory, each file whose basename is a valid key in the directory will be packaged into the secret. Any directory entries except regular files are ignored (e.g. subdirectories, symlinks, devices, pipes, etc).

Examples:
  # Create a new secret named my-secret with keys for each file in folder bar
  kubectl create secret generic my-secret --from-file=path/to/bar

  # Create a new secret named my-secret with specified keys instead of names on disk
  kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-file=ssh-publickey=path/to/id_rsa.pub

  # Create a new secret named my-secret with key1=supersecret and key2=topsecret
  kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret

  # Create a new secret named my-secret using a combination of a file and a literal
  kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-literal=passphrase=topsecret

  # Create a new secret named my-secret from an env file
  kubectl create secret generic my-secret --from-env-file=path/to/bar.env

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.
      --append-hash=false: Append a hash of the secret to its name.
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
      --from-env-file='': Specify the path to a file to read lines of key=val pairs to create a secret (i.e. a Docker .env file).
      --from-file=[]: Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used.  Specifying a directory will iterate each named file in the directory that is a valid secret key.
      --from-literal=[]: Specify a key and literal value to insert in secret (i.e. mykey=somevalue)
  -o, --output='': Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --type='': The type of secret to create
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create secret generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none] [options]
$ kubectl create secret tls -h
`Create a TLS secret from the given public/private key pair.

 The public/private key pair must exist before hand. The public key certificate must be .PEM encoded and match the given private key.

Examples:
  # Create a new TLS secret named tls-secret with the given key pair:
  kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.
      --append-hash=false: Append a hash of the secret to its name.
      --cert='': Path to PEM encoded public key certificate.
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
      --key='': Path to private key associated with given certificate.
  -o, --output='': Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none] [options]
$ kubectl create secret docker-registry -h
`Create a new secret for use with Docker registries.

  Dockercfg secrets are used to authenticate against Docker registries.

  When using the Docker command line to push images, you can authenticate to a given registry by running:
      '$ docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'.

 That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to authenticate to the registry. The email address is optional.

  When creating applications, you may have a Docker registry that requires authentication.  In order for the
  nodes to pull images on your behalf, they have to have the credentials.  You can provide this information
  by creating a dockercfg secret and attaching it to your service account.

Examples:
  # If you don't already have a .dockercfg file, you can create a dockercfg secret directly by using:
  kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.
      --append-hash=false: Append a hash of the secret to its name.
      --docker-email='': Email for Docker registry
      --docker-password='': Password for Docker registry authentication
      --docker-server='https://index.docker.io/v1/': Server location for Docker registry
      --docker-username='': Username for Docker registry authentication
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
      --from-file=[]: Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used.  Specifying a directory will iterate each named file in the directory that is a valid secret key.
  -o, --output='': Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create secret docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run=server|client|none] [options]

secret引用
提供volume
containers:
  - image: mysql:5.7
    name: mysql-app
    ports:
    - name: cp
      containerPort: 3306
      hostPort: 3306
    volumeMounts:
    - name: secrets
      mountPath: "/etc/secrets"
      readOnly: true
  Volumes: 
  - name: secrets
    Secret:
      SecretName: mysecret
环境变量
containers:
      - name: "wordpress"
        image: "wordpress"
        ports:
        - name: serverOn
          containerPort: 80
        env:
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyPef:
              name: mysecret
              key: username
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyPef:
              name: mysecret
              key: password
docker-registry
  • 可以直接用kubectl命令来创建用于docker registry认证的secret:
$ kubectl create secret docker-registry myregistrykey --docker-server
=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-passwo
rd=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret "myregistrykey" created.
  • 也可以直接读取 ~/.dockercfg 的内容来创建:
$ kubectl create secret docker-registry myregistrykey \
--from-file="~/.dockercfg"

在创建Pod的时候,通过 imagePullSecrets 来引用刚创建的 myregistrykey :

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: foo
    image: janedoe/awesomeapp:v1
  imagePullSecrets:
  - name: myregistrykey
存储加密

v1.7+版本支持将Secret数据加密存储到etcd中,只需要在apiserver启动时配置 --experimental-encryption-provider-config 。加密配置格式为

apiVersion: v1
kind: EncryptionConfig
resources:
  - resources:
    - secrets
    # 加密方式
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: c2VjcmV0IGlzIHNlY3VyZQ==
        - name: key2
          secret: dGhpcyBpcyBwYXNzd29yZA==
    - identity: {}
    - aesgcm:
        keys:
        - name: key1
          secret: c2VjcmV0IGlzIHNlY3VyZQ==
        - name: key2
          secret: dGhpcyBpcyBwYXNzd29yZA==
    - secretbox:
        keys:
        - name: key1
          secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=

其中
resources.resources是Kubernetes的资源名
resources.providers是加密方法,支持以下几种

  • identity:不加密

  • aescbc:AES-CBC加密

  • secretbox:XSalsa20和Poly1305加密

  • aesgcm:AES-GCM加密

Secret是在写存储的时候加密,因而可以对已有的secret执行update操作来保证所有的secrets都加密

kubectl get secrets -o json | kubectl update -f -

如果想取消secret加密的话,只需要把 identity 放到providers的第一个位置即可
(aescbc还要留着以便访问已存储的secret)

PodPreset

PodPreset用来给指定标签的Pod注入额外的信息,如环境变量、存储卷等。这样,Pod
模板就不需要为每个Pod都显式设置重复的信息。

​ Kubernetes为Preset提供了一个允许控制器(admission controller),当创建创建pod的请求到达时,通过这个允入控制器将label selector选中的Preset应用到pod中,

具体流程如下
  1. 检索系统中所有可用的Presets。
  2. 检查所有Preset的label selector是否与当前pod的标签匹配。
  3. 尝试将匹配Preset中的各种资源合并进正在创建的pod。
  4. 如果发生错误,为pod抛出合并Preset失败的异常事件,然后在不合并Preset所提供资源的情况下创建pod(合并失败并没有阻挡pod的创建)。
  5. 如果合并成功,向合并后的结果spec加入到pod的注解中,表示pod被Preset修改了,注册格式如下:
    podpreset.admission.kubernetes.io/podpreset-: “”

每个pod可以被0到多个Preset匹配每个Preset可以应用到0到多个pod。当Preset被应用到pod时,kubernetes会修改pod的spec。当注入Env、EnvFrom、VolumeMounts时,kubernetes会修改pod中除init container以外的其它所有container的spec,当注入volume时,修改pod的spec

ThirdPartyResources

(TPR)是v1.7-一种无需改变代码就可以扩展Kubernetes API的机制,可以用来管理自定义对象。

CustomResourceDefinition

(CRD)是v1.7+新增的无需改变代码就可以扩展Kubernetes API的机制,用来管理自定义对象。

详解CRD

配置CRD

kubernetes存储控制

Volumes

​ 容器中的磁盘的生命周期是短暂的,这就带来了一系列的问题,第一,当一个容器损坏之后,kubelet 会重启这个容器,但是文件会丢失-这个容器会是一个全新的状态,第二,当很多容器在同一Pod中运行的时候,很多时候需要数据文件的共享。Kubernete Volume解决了这个问题

​ Docker有一个Volumes的概念,虽然这个Volume有点宽松和管理性比较小。在Docker中,一个 Volume 是一个简单的所在主机的一个目录或者其它容器中的。生命周期是没有办法管理,直到最近才有 local-disk-backed 磁盘。Docker现在提供了磁盘驱动,但是功能非常有限(例如Docker1.7只能挂在一个磁盘每个容器,并且无法传递参数)

​ **从另外一个方面讲,一个Kubernetes volume,拥有明确的生命周期,与所在的Pod的生命周期相同。**因此,Kubernetes volume独立与任何容器,与Pod相关,所以数据在重启的过程中还会保留,当然,如果这个Pod被删除了,那么这些数据也会被删除。更重要的是,Kubernetes volume 支持多种类型,任何容器都可以使用多个Kubernetes volume。

pod删除时,Volume才会清理。数据是否丢失取决于具体的Volume类型,比如
emptyDir的数据会丢失,而PV的数据则不会丢

​ 它的核心,一个 volume 就是一个目录,可能包含一些数据,这些数据对pod中的所有容器都是可用的,这个目录怎么使用,什么类型,由什么组成都是由特殊的volume 类型决定的

​ 想要使用一个volume,Pod必须指明Pod提供了那些磁盘,并且说明如何挂在到容器中

Kubernete 支持如下类型的volume:

emptyDir

随pod消亡:如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: data
    emptyDir:
      # 限额
      sizeLimit: 64Mi
gitRepo

volume将git代码下拉到指定的容器路径中

volumes:
- name: git-volume
  gitRepo:
    repository: "git@somewhere:me/my-git-repository.git"
    revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
本地存储限额
apiVersion: v1
kind: Pod
metadata:
  name: ls1
spec:
  restartPolicy: Never
  containers:
  - name: hello
    image: busybox
    command: ["df"]
    resources:
      requests:
        # /var/lib/docker 的大小,调整容器存储大小
        storage.kubernetes.io/overlay: 64Mi
        #  /var/lib/kubelet  的大小,调整本地存储大小
        storage.kubernetes.io/scratch: 128Mi
secret
hostPath

允许挂载Node上的文件系统到Pod里面去

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /data
gcePersistentDisk

可以挂载GCE上的永久磁盘到容器,需要Kubernetes运行在GCE的VM中

volumes:
- name: test-volume
  # This GCE PD must already exist.
  gcePersistentDisk:
    pdName: my-data-disk
    fsType: ext4
awsElasticBlockStore
nfs

网络文件系统

volumes:
- name: nfs
  nfs:
    # FIXME: use the right hostname
    server: 10.254.234.223
    path: "/"
subPath

Pod的多个容器使用同一个Volume时,subPath非常有用

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
  containers:
  - name: mysql
    image: mysql
    volumeMounts:
      - mountPath: /var/lib/mysql
        name: site-data
        subPath: mysql
  - name: php
    image: php
    volumeMounts:
      - mountPath: /var/www/html
        name: site-data
        subPath: html
 volumes:
 - name: site-data
   persistentVolumeClaim:
     claimName: my-lamp-site-data
FlexVolume(add-on)

如果内置的这些Volume不满足要求,则可以使用FlexVolume实现自己的Volume插件。

Projected Volume

将多个Volume源映射到同一个目录中,支持secret、downwardAPI和configMap

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/my-username
      - downwardAPI:
          items:
            - path: "labels"
              fieldRef:
                fieldPath: metadata.labels
            - path: "cpu_limit"
        	  resourceFieldRef:
        	    containerName: container-test
        	    resource: limits.cpu
    - configMap:
        name: myconfigmap
        items:
          - key: config
            path: my-group/my-config
iscsi
glusterfs
rbd
persistentVolumeClaim
local-volume

​ 代表一个本地存储设备,比如磁盘、分区或者目录等。主要的应用场景包括分布式存储和数据库等需要高性能和高可靠性的环境里。**本地PVC只能使用静态已经创建的PV,若匹配不到则一直处于未绑定状态。**相对于HostPath,本地数据卷可以直接以持久化的方式使用(它总是通过NodeAffinity调度在某个指定的节点上)

PV/PVC

​ PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 提供了方便的持久化卷:PV 提供网络存储资源,而 PVC 请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷、最后创建 PVC 来将 Pod 跟数据卷关联起来。PV 和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。

**PersistentVolume(PV)特指集群之中的一块网络存储,它是集群中的资源。**PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。

Volume 生命周期

Volume 的生命周期包括 5 个阶段

  1. Provisioning,即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建
  2. Binding,将 PV 分配给 PVC
  3. Using,Pod 通过 PVC 使用该 Volume,并可以通过准入控制 StorageObjectInUseProtection(1.9 及以前版本为 PVCProtection)阻止删除正在使用的 PVC
  4. Releasing,Pod 释放 Volume 并删除 PVC
  5. Reclaiming,回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除
  6. Deleting,删除 PV 并从云存储中删除后段存储
根据这 5 个阶段,Volume 的状态有以下 4 种
  • Available:可用
  • Bound:已经分配给 PVC
  • Released:PVC 解绑但还未执行回收策略
  • Failed:发生错误
PV的访问模式(accessModes)有三种:
  • ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个Pod挂
    载。
  • ReadOnlyMany(ROX):可以以只读的方式被多个Pod挂载。
  • ReadWriteMany(RWX):这种存储可以以读写的方式被多个Pod共享。不是每一
    种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是
    NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是
    访问模式。
三种PV的回收策略(persistentVolumeReclaimPolicy)
  • Retain,不清理保留Volume(需要手动清理)
  • Recycle,删除数据,即 rm -rf /thevolume/* (只有NFS和HostPath支持)
  • Delete,删除存储资源,比如删除AWS EBS卷(只有AWS EBS, GCE PD, Azure
    Disk和Cinder支持)
2.1 供应(Provisioning)

参考Kubernetes-持久化存储卷PersistentVolume@菲宇

​ 供应是为集群提供可用的存储卷,在Kubernetes中有两种持久化存储卷的提供方式:静态或者动态。

2.1.1 静态(Static)

​ PV是由Kubernetes的集群管理员创建的,PV代表真实的存储,PV提供的这些存储对于集群中所有的用户都是可用的。它们存在于Kubernetes API中,并可被Pod作为真实存储使用。**在静态供应的情况下,由集群管理员预先创建PV,开发者创建PVC和Pod,Pod通过PVC使用PV提供的存储。**静态供应方式的过程如下图所示:

img

2.1.2 动态(Dynamic)

​ 对于动态的提供方式,当管理员创建的静态PV都不能够匹配用户的PVC时,集群会尝试自动为PVC提供一个存储卷,这种提供方式基于StorageClass。在动态提供方向,PVC需要请求一个存储类,但此存储类必须有管理员预先创建和配置。集群管理员需要在API Server中启用DefaultStorageClass的接入控制器。动态供应过程如下图所示:

img

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LeuA6uDo-1614949922753)(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg2020.cnblogs.com%2Fblog%2F711773%2F202006%2F711773-20200606111557348-1778227999.png&refer=http%3A%2F%2Fimg2020.cnblogs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1612580796&t=f8ae0251ab99e19dcab582b8f40ef80c)]

2.2 绑定

​ 在Kubernetes中,会动态的将PVC与可用的PV的进行绑定。在kubernetes的Master中有一个控制回路,它将监控新的PVC,并为其查找匹配的PV(如果有),并把PVC和PV绑定在一起。如果一个PV曾经动态供给到了一个新的PVC,那么这个回路会一直绑定这个PV和PVC。另外,用户总是能得到它们所要求的存储,但是volume可能超过它们的请求。一旦绑定了,PVC绑定就是专属的,无论它们的绑定模式是什么。

​ 如果没有匹配的PV,那么PVC会无限期的处于未绑定状态,一旦存在匹配的PV,PVC绑定此PV。比如,就算集群中存在很多的50G的PV,需要100G容量的PVC也不会匹配满足需求的PV。直到集群中有100G的PV时,PVC才会被绑定。PVC基于下面的条件绑定PV,如果下面的条件同时存在,则选择符合所有要求的PV进行绑定:

​ 1)如果PVC指定了存储类,则只会绑定指定了同样存储类的PV;

​ 2)如果PVC设置了选择器,则选择器去匹配符合的PV;

​ 3)如果没有指定存储类和设置选取器,PVC会根据存储空间容量大小和访问模式匹配符合的PV。

kubernetes安全管理

Security Context

​ 在运行一个容器时,有时候需要使用sysctl修改内核参数,比如net.vm.kernel等,sysctl需要容器拥有超级权限,容器启动时加上--privileged参数即可。那么,在kubernetes中是如何使用的呢

​ kubernetes中有个字段叫securityContext,即安全上下文,它用于定义Pod或Container的权限和访问控制设置。其设置包括:

  • Discretionary Access Control: 根据用户ID(UID)和组ID(GID)来限制其访问资源(如:文件)的权限
  • Security Enhanced Linux (SELinux): 给容器指定SELinux labels
  • Running as privileged or unprivileged:以privilegedunprivileged权限运行
  • Linux Capabilities: 给某个特定的进程privileged权限,而不用给root用户所有的privileged权限
三种配置方法
  • Container-level Security Context:仅应用到指定的容器
  • Pod-level Security Context:应用到Pod内所有容器以及Volume
  • Pod Security Policies(PSP):应用到集群内部所有Pod以及Volume
# container-level security context
apiVersion: v1
kind: Pod
metadata:
  name: hello-world1
spec:
  containers:
  - name: hello-world-container
    image: hello-world
    # ...
    securityContext:
      privileged: true
---
# pod-level security context
apiVersion: v1
kind: Pod
metadata:
  name: hello-world2
spec:
  containers:
  - name: hello-world-container
    image: hello-world
    # ...
  securityContext:
    fsGroup: 1234
    supplementGroups: [5678]
    seLinuxOptions:
      level: "s0:c123,c456"
---
# pod security policy(cluster-level)
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
  name: permissive
spec:
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  hostPorts:
  - min: 8000
    max: 8080
  volumes:
  - '*'

Service Account

​ Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同

  • User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
  • User account是跨namespace的,而service account(Role)则是仅局限它所在的namespace,ClusterRole全部namespace
  • 每个namespace都会自动创建一个default service account
  • Token controller检测service account的创建,并为它们创建secret
  • 开启ServiceAccount Admission Controller后
    • 每个Pod在创建后都会自动设置spec.serviceAccount为default除非指定了其他ServiceAccoutName
    • 验证Pod引用的service account已经存在,否则拒绝创建
    • 如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中
    • 每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/

架构和组件

img

​ Kubernetes属于主从分布式架构,主要由Master Node和Worker Node组成,以及包括客户端命令行工具kubectl和其它附加项。

Master Node作为控制节点,对集群进行调度管理;Master Node由API Server、Scheduler、Cluster State Store和Controller-Manger Server所组成;

Worker Node作为真正的工作节点,运行业务应用的容器;Worker Node包含kubelet、kube proxy和Container Runtime;kubectl:用于通过命令行与API Server进行交互,而对Kubernetes进行操作,实现在集群中进行各种资源的增删改查等操作;

Add-on:是对Kubernetes核心功能的扩展,例如增加网络和网络策略等能力。

Master Node(控制节点)

2.1 API Server(API)

​ API Server主要用来处理REST的操作,确保它们生效,并执行相关业务逻辑,以及更新etcd(或者其他存储)中的相关对象。API Server是所有REST命令的入口,它的相关结果状态将被保存在etcd(或其他存储)中

API Server的基本功能包括:

  • REST语义,监控,持久化和一致性保证,API 版本控制,放弃和生效内置准入控制语义,同步准入控制钩子,以及异步资源初始化

  • API注册和发现

  • 另外,API Server也作为集群的网关。默认情况,客户端通过API Server对集群进行访问,客户端需要通过认证,并使用API Server作为访问Node和Pod(以及service)的==堡垒和代理/通道==。

2.2 Cluster state store(集群状态存储)

​ Kubernetes默认使用etcd作为集群整体存储,当然也可以使用其它的技术。etcd是一个简单的、分布式的、一致的key-value存储,主要被用来共享配置和服务发现

​ etcd提供了一个CRUD操作的REST API,以及提供了作为注册的接口,以监控指定的Node。

集群的所有状态都存储在etcd实例中,并具有监控的能力,因此当etcd中的信息发生变化时,就能够快速的通知集群中相关的组件。

2.3 Controller-Manager Server(控制管理)

一个资源对应一个控制器,而ControllerManager就是负责管理这些控制器的

​ Controller-Manager Serve用于==执行大部分的集群层次的功能==,它既执行生命周期功能(例如:命名空间创建和生命周期、事件垃圾收集、已终止垃圾收集、级联删除垃圾收集、node垃圾收集),也执行API业务逻辑(例如:pod的弹性扩容)。

​ 控制管理提供自愈能力、扩容、应用生命周期管理、服务发现、路由、服务绑定和提供。

​ Kubernetes默认提供Replication Controller、Node Controller、Namespace Controller、Service Controller、Endpoints Controller、Persistent Controller、DaemonSet Controller等控制器。

2.4 Scheduler(调度器)

​ scheduler组件==为容器自动选择运行的主机==。依据请求资源的可用性,服务请求的质量等约束条件,scheduler监控未绑定的pod,并将其绑定至特定的node节点。

​ Kubernetes也支持用户自己提供的调度器,Scheduler负责根据调度策略自动将Pod部署到合适Node中,调度策略分为预选策略和优选策略,Pod的整个调度过程分为两步:

(1) 预选Node:遍历集群中所有的Node,按照具体的预选策略筛选出符合要求的Node列表。如没有Node符合预选策略规则,该Pod就会被挂起,直到集群中出现符合要求的Node。

(2) 优选Node:预选Node列表的基础上,按照优选策略为待选的Node进行打分和排序,从中获取最优Node。

Worker Node(工作节点)

3.1 Kubelet

​ Kubelet是Kubernetes中最主要的控制器,它是==Pod和Node API的主要实现者,Kubelet负责驱动容器执行层==。在Kubernetes中,应用容器彼此是隔离的,并且与运行其的主机也是隔离的,这是对应用进行独立解耦管理的关键点。

​ 在Kubernets中,Pod作为基本的执行单,它可以拥有多个容器和存储数据卷,能够方便在每个容器中打包一个单一的应用,从而解耦了应用构建时和部署时的所关心的事项,已经能够方便在物理机/虚拟机之间进行迁移。

API准入控制可以拒绝或者接收Pod,或者为Pod添加额外的调度约束,但是Kubelet才是Pod是否能够运行在特定Node上的最终裁决者,而不是scheduler或者DaemonSet

kubelet默认情况使用cAdvisor进行资源监控。负责管理Pod、容器、镜像、数据卷等,实现集群对节点的管理,并将容器的运行状态汇报给Kubernetes API Server。

3.2 Container Runtime(容器运行时:docker/rkt)

img

img

​ 每一个Node都会运行一个Container Runtime,其负责下载镜像和运行容器。Kubernetes本身并不提供容器运行时环境,但提供了接口,可以插入所选择的容器运行时环境。kubelet使用Unix socket之上的gRPC框架与容器运行时进行通信kubelet作为客户端,而CRI shim作为服务器

​ protocol buffers API提供两个gRPC服务,ImageService和RuntimeService。

​ ImageService提供拉取、查看、和移除镜像的RPC。

​ RuntimeSerivce则提供管理Pods和容器生命周期管理的RPC,以及与容器进行交互(exec/attach/port-forward)。容器运行时能够同时管理镜像和容器(例如:Docker和Rkt),并且可以通过同一个套接字提供这两种服务。

​ 在Kubelet中,这个套接字通过–container-runtime-endpoint和–image-service-endpoint字段进行设置。

​ Kubernetes CRI支持的容器运行时包括docker、rkt、cri-o、frankti、kata-containers和clear-containers等。

3.3 kube proxy

​ 基于一种公共访问策略(例如:负载均衡),服务提供了一种访问一群pod的途径。此方式通过创建一个虚拟的IP来实现,客户端能够访问此IP,并能够将服务透明的代理至Pod

​ 每一个Node都会运行一个kube-proxy,,kube proxy通过iptables规则引导访问至服务IP(DNAT),并将重定向至正确的后端应用,通过这种方式kube-proxy提供了一个高可用的负载均衡解决方案。从k8s的1.8版本开始,kube-proxy引入了IPVS模式,IPVS模式与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。

👍参照原文-核心组件kube-proxy

​ 当创建一个 service 后,kubernetes 会在每个节点上创建一个网卡,同时帮你将 Service IP(VIP) 绑定上

​ 每一个kube-proxy都会从etcd中学习到全量的service信息,并使用内核iptables建立VIP转发规则!

iptables mode: 并不在本地节点开启反向代理服务,而是全部交给 iptables DNAT来实现;即 iptables 直接将对 VIP 的请求转发给后端 Pod,通过 iptables 设置转发策略

img

IPVS mode:

img

​ 访问Service的请求,不论是Cluster IP+TargetPort的方式;还是用Node节点IP+NodePort的方式,都被Node节点的Iptables规则重定向到Kube-proxy监听Service服务代理端口。kube-proxy接收到Service的访问请求后,根据负载策略,转发到后端的Pod。

服务发现方式:

​ 1) 环境变量: 当你创建一个Pod的时候,kubelet会在该Pod中注入集群内所有Service的相关环境变量需要注意: 要想一个Pod中注入某个Service的环境变量,则必须Service要先比该Pod创建

$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP        3d18h
nginx-app    NodePort    10.99.8.93   <none>        80:30445/TCP   40h
[pod] $ env
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
NGINX_APP_PORT_80_TCP_ADDR=10.99.8.93
HOSTNAME=nginx-app-569649fc56-tmzlc
NGINX_APP_PORT_80_TCP_PORT=80
HOME=/root
NGINX_APP_PORT_80_TCP_PROTO=tcp
PKG_RELEASE=1~buster
NGINX_APP_PORT_80_TCP=tcp://10.99.8.93:80
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
NGINX_VERSION=1.17.10
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
NJS_VERSION=0.3.9
KUBERNETES_PORT_443_TCP_PROTO=tcp
NGINX_APP_SERVICE_HOST=10.99.8.93
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
NGINX_APP_PORT=tcp://10.99.8.93:80
NGINX_APP_SERVICE_PORT=80

​ 2) DNS:这是k8s官方强烈推荐的方式!!! 解决了上述因创建先后顺序造成后续pod服务不可用问题!可以通过cluster add-on方式轻松的创建KubeDNS来对集群内的Service进行服务发现。

[pod]$ cat /etc/resolv.conf
nameserver 10.96.0.10 #kube-dns
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

在Kubernetes中,kube proxy负责为Pod创建代理服务;引到访问至服务;并实现服务到Pod的路由和转发,以及通过应用的负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTOum0oe-1614949922757)(Kubernetes.assets/image-20210104231826273.png)]

kubectl(管理工具)

​ kubectl是Kubernetes==集群的命令行接口==。运行kubectl命令的语法如下所示

$ kubectl [command] [TYPE] [NAME] [flags]

这里的command,TYPE、NAME和flags为:

​ comand:指定要对资源执行的操作,例如create、get、describe和delete
​ TYPE:指定资源类型,资源类型是大小写敏感的,开发者能够以单数、复数和缩略的形式。例如:

$ kubectl get pod pod1 
$ kubectl get pods pod1 
$ kubectl get po pod1

​ NAME:指定资源的名称,名称也大小写敏感的。如果省略名称,则会显示所有的资源,例如:

$ kubectl get pods

​ flags:指定可选的参数。例如,可以使用-s或者–server参数指定Kubernetes API server的地址和端口。
另外,可以通过运行kubectl help命令获取更多的信息。

Add-on(扩展插件)

​ 在Kunbernetes中可以以附加项的方式扩展Kubernetes的功能,目前主要有网络、服务发现和可视化这三大类的附加项,下面是可用的一些附加项:

5.4.1 网络和网络策略
ACI 通过与Cisco ACI集成的容器网络和网络安全。
Calico 是一个安全的3层网络和网络策略提供者。
Canal 联合Fannel和Calico,通过网络和网络侧。
Cilium 是一个3层网络和网络侧插件,它能够透明的加强HTTP/API/L7 策略。其即支持路由,也支持overlay/encapsultion模式。
Flannel 是一个overlay的网络提供者。

5.4.2 服务发现
CoreDNS 是一个灵活的,可扩展的DNS服务器,它能够作为Pod集群内的DNS进行安装。
Ingress 提供基于Http协议的路由转发机制。

5.4.3 可视化&控制
Dashboard是Kubernetes的web用户界面。

单Master集群

img

多Master集群

img

kubernetes集群部署

基于kubeadm快速部署

  • **
    minikube**

Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,仅用于尝试Kubernetes或日常开发的用户使用。部署地址:https://kubernetes.io/docs/setup/minikube/

  • kubeadm

Kubeadm也是一个工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。部署地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

  • 二进制包

推荐,从官方下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。下载地址:https://github.com/kubernetes/kubernetes/releases

2.2 安装kubeadm环境准备

以下操作,在三台节点都执行

2.2.1 环境需求

环境:centos 7.4 +

硬件需求:CPU>=2c ,内存>=4G

2.2.2 环境角色
IP角色安装软件
192.168.241.113k8s-Masterkube-apiserver kube-schduler kube-controller-manager docker flannel kubelet
192.168.241.115k8s-node01kubelet kube-proxy docker flannel
192.168.241.114k8s-node01kubelet kube-proxy docker flannel
2.2.3 环境初始化

PS : 以下所有操作,在三台节点全部执行

1、关闭防火墙及selinux

systemctl stop firewalld && systemctl disable firewalld

sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config  && setenforce 0

2、关闭 swap 分区
swapoff -a # 临时

sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab #永久

3、分别在上设置主机名及配置hosts,设置各主机名
hostnamectl set-hostname k8s-master #(仅在192.168.241.113主机打命令)
hostnamectl set-hostname k8s-node01 #(仅在192.168.241.115主机打命令)
hostnamectl set-hostname k8s-node02 #(仅在192.168.241.114主机打命令)

4、在所有主机上上添加如下命令,用于主机名解析
cat >> /etc/hosts << EOF
192.168.241.113 k8s-master
192.168.241.115 k8s-node01
192.168.241.114 k8s-node02

EOF
5、内核调整,将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

EOF

sysctl --system

6、设置系统时区并同步时间服务器

yum install -y ntpdate

ntpdate time.windows.com
2.2.4 docker 安装
#替换yum的docker镜像源

# step 1: 安装必要的一些系统工具 
 
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
 
# Step 2: 添加软件源信息 
 
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io 	
systemctl enable docker && systemctl start docker

$ docker --version
Docker version 20.10.1, build 831ebea
2.2.4.1修改docker镜像仓库配置
国内Docker镜像仓库名称链接
Docker 官方中国区https://registry.docker-cn.com
网易http://hub-mirror.c.163.com
中国科学技术大学https://docker.mirrors.ustc.edu.cn
阿里云https://<你的ID>.mirror.aliyuncs.com //内网加速

修改/etc/docker/daemon.json文件,如果没有先建一个即可

2.2.4.2修改配置文件
sudo mkdir -p /etc/docker
sudo cat > /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://abe2v8fb.mirror.aliyuncs.com"]
}
EOF
2.2.4.3使配置文件生效
sudo systemctl daemon-reload && sudo systemctl restart docker
2.2.5 添加kubernetes YUM软件源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
2.2.6 安装kubeadm,kubelet和kubectl

2.2.6上所有主机都需要操作,由于版本更新频繁,这里指定版本号部署

yum install -y kubelet-1.19.3 kubeadm-1.19.3 kubectl-1.19.3
systemctl enable kubelet && systemctl start kubelet

2.3 部署Kubernetes Master

只需要在Master 节点执行,这里的apiserve需要修改成自己的master地址

[root@k8s-master ~]# kubeadm init \
--apiserver-advertise-address=192.168.241.113  \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.19.3 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16

由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。

输出结果

Your Kubernetes control-plane has initialized successfully!

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

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.240.213:6443 --token 3yqiws.7k5th9ws1fyk54g9 \
    --discovery-token-ca-cert-hash sha256:fad5a46dce45aaf7552aa3c7c2156f73a22a0aea2b982418a450210da1036fd4

根据输出提示操作:

[root@k8s-master ~]# mkdir -p $HOME/.kube
[root@k8s-master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
默认token的有效期为24小时,当过期之后,该token就不可用了,

`如果后续有nodes节点加入,解决方法如下:`````

重新生成新的token

[root@k8s-master ~]# kubeadm token create
0w3a92.ijgba9ia0e3scicg
[root@k8s-master ~]# kubeadm token list
TOKEN                     TTL       EXPIRES                     USAGES                   DESCRIPTION                                                EXTRA GROUPS
0w3a92.ijgba9ia0e3scicg   23h       2019-09-08T22:02:40+08:00   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token
t0ehj8.k4ef3gq0icr3etl0   22h       2019-09-08T20:58:34+08:00   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token
[root@k8s-master ~]#

获取ca证书sha256编码hash值

[root@k8s-master ~]# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
ce07a7f5b259961884c55e3ff8784b1eda6f8b5931e6fa2ab0b30b6a4234c09a

节点加入集群

[root@k8s-node01 ~]# kubeadm join 192.168.240.213:6443 --token 3yqiws.7k5th9ws1fyk54g9 \
    --discovery-token-ca-cert-hash sha256:fad5a46dce45aaf7552aa3c7c2156f73a22a0aea2b982418a450210da1036fd4
2.4 加入Kubernetes Node

在两个 Node 节点执行

使用kubeadm join 注册Node节点到Matser

kubeadm join 的内容,在上面kubeadm init 已经生成好了

[root@k8s-node01 ~]# kubeadm join 192.168.240.213:6443 --token 3yqiws.7k5th9ws1fyk54g9 \
    --discovery-token-ca-cert-hash sha256:fad5a46dce45aaf7552aa3c7c2156f73a22a0aea2b982418a450210da1036fd4
[preflight] Running pre-flight checks
        [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
        [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 20.10.1. Latest validated version: 19.03
[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] 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.
2.5 安装网络插件

只需要在Master 节点执行
已修改

[root@k8s-master ~]# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
修改镜像地址:(有可能默认不能拉取,确保能够访问到quay.io这个registery,否则修改如下内容)
[root@k8s-master ~]# vim kube-flannel.yml
进入编辑,把106行,120行的内容,替换如下image,替换之后查看如下为正确
[root@k8s-master ~]# cat -n  kube-flannel.yml|grep lizhenliang/flannel:v0.11.0-amd64
   106            image: lizhenliang/flannel:v0.11.0-amd64
   120            image: lizhenliang/flannel:v0.11.0-amd64
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml
[root@iZwz9dv39buxio49wlqem0Z ~]# ps -ef|grep flannel
root     25780  1639  0 11:46 pts/0    00:00:00 grep --color=auto flannel
查看集群的node状态,安装完网络工具之后,只有显示如下状态,所有节点全部都Ready好了之后才能继续后面的操作
[root@iZwz9dv39buxio49wlqem0Z ~]# kubectl get nodes
NAME         STATUS   ROLES    AGE     VERSION
k8s-master   Ready    master   11m     v1.19.3
k8s-node01   Ready    <none>   5m11s   v1.19.3
k8s-node02   Ready    <none>   5m2s    v1.19.3
[root@iZwz9dv39buxio49wlqem0Z ~]# kubectl get pod -n kube-system
NAME                                 READY   STATUS    RESTARTS   AGE
coredns-6d56c8448f-cwz55             1/1     Running   0          11m
coredns-6d56c8448f-hmvk8             1/1     Running   0          11m
etcd-k8s-master                      1/1     Running   0          11m
kube-apiserver-k8s-master            1/1     Running   0          11m
kube-controller-manager-k8s-master   1/1     Running   0          11m
kube-flannel-ds-2vc5j                1/1     Running   0          57s
kube-flannel-ds-kbpvc                1/1     Running   0          57s
kube-flannel-ds-zkj4w                1/1     Running   0          57s
kube-proxy-gvqkn                     1/1     Running   0          5m19s
kube-proxy-nwr9r                     1/1     Running   0          5m28s
kube-proxy-rjqqv                     1/1     Running   0          11m
kube-scheduler-k8s-master            1/1     Running   0          11m

只有全部都为1/1则可以成功执行后续步骤,如果flannel需检查网络情况,重新进行如下操作
kubectl delete -f kube-flannel.yml
然后重新wget,然后修改镜像地址,然后
kubectl apply -f kube-flannel.yml
2.7 测试Kubernetes集群

在Kubernetes集群中创建一个pod,然后暴露端口,验证是否正常访问:

[root@iZwz9dv39buxio49wlqem0Z ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
[root@iZwz9dv39buxio49wlqem0Z ~]#  kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed

[root@iZwz9dv39buxio49wlqem0Z ~]# kubectl get pods,svc
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6799fc88d8-mdcj2   1/1     Running   0          41s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1       <none>        443/TCP        13m
service/nginx        NodePort    10.1.205.152   <none>        80:31366/TCP   19s

访问地址:http://NodeIP:Port ,此例就是:http://10.1.205.152

NodePort:这种方式是常用的,用来对集群外暴露Service,你可以通过访问集群内的每个NodeIP:NodePort的方式,访问到对应Service后端的Endpoint

[root@iZwz9dv39buxio49wlqem0Z ~]# curl 10.1.205.152:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

2.8 部署 Dashboard
[root@k8s-master ~]# 
$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.1.0/aio/deploy/recommended.yaml

[root@k8s-master ~]# 
$ vi kubernetes-dashboard.yaml
修改内容:
157 spec:
158   type: NodePort     # 增加此行
159   ports:
160     - port: 443
161       targetPort: 8443
162       nodePort: 30001   # 增加此行
163   selector:
164     k8s-app: kubernetes-dashboard
#或者使用下列命令
$ kubectl  patch svc kubernetes-dashboard -n kubernetes-dashboard \
-p '{"spec":{"type":"NodePort","ports":[{"port":443,"targetPort":8443,"nodePort":30443}]}}'

[root@k8s-master ~]
$ kubectl apply -f kubernetes-dashboard.yaml

[root@k8s-master ~]# 
$ kubectl -n kubernetes-dashboard get pods
NAME                                         READY   STATUS    RESTARTS   AGE
dashboard-metrics-scraper-79c5968bdc-8ffsl   1/1     Running   0          3m20s
kubernetes-dashboard-7448ffc97b-46k8t        1/1     Running   0          3m21s
[root@k8s-master ~]# 
$ kubectl -n kubernetes-dashboard get svc
NAME                        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
dashboard-metrics-scraper   ClusterIP   10.1.224.132   <none>        8000/TCP        3m22s
kubernetes-dashboard        NodePort    10.1.53.16     <none>        443:30001/TCP   3m23s

在火狐浏览器访问(google受信任问题不能访问)地址: https://NodeIP:30001

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QGxLoX4X-1614949922758)(Kubernetes.assets/image-20210103121130929.png)]

创建service account并绑定默认cluster-admin管理员集群角色:

[root@k8s-master ~]# 
$ kubectl create serviceaccount dashboard-admin -n kube-system

[root@k8s-master ~]# 
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin

[root@k8s-master ~]# 
$ kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

serviceaccount/dashboard-admin created

Name:         dashboard-admin-token-9dnd8
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: dashboard-admin
              kubernetes.io/service-account.uid: 3b2066c4-c75e-47eb-ad71-b0d34f961d5a

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ilh3TTZrR3I4d1J1OXZFeEtKNXM3b256U1hQSjFySUtYRzRlYVpUTEJXU2MifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tOWRuZDgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiM2IyMDY2YzQtYzc1ZS00N2ViLWFkNzEtYjBkMzRmOTYxZDVhIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.H44m3anLJj4rWgK6yo7w_QP0zXVv9tOyV8bHgQjrqN11ibVOk1siIe2htXXofanMxr0k07rglDfWtZHnQCmL_UtHqhrs2NiPp94T6w6dwfWhmdL9CUmZHJ6oimyVYG6bjwUbKprsNQxt_qQ2t1jIh3Tft7vO1YluKxVg57PJdcQ2GKzq3ZPxFdz7weh20cQe-NIOKGElDkgROEZgQgI1m5QVcO_jQEYBC4kjepKxe5yxtyzJe2BnQuCR5-_B2NHeGLJNIwVZDWQvkQHTS76mkUWwaFp-R1o0Jw6WVjGkmHw1dkKCS2ifTX6JDtUrYRGIdSzclZprsT9T8q-x18m1pA

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eHgVN65c-1614949922759)(Kubernetes.assets/image-20210103122011424.png)]

解决其他浏览器不能访问的问题(未测试)

[root@k8s-master ~]# cd /etc/kubernetes/pki/
[root@k8s-master pki]# mkdir ui
[root@k8s-master pki]# cp apiserver.crt  ui/
[root@k8s-master pki]# cp apiserver.key  ui/
[root@k8s-master pki]# cd ui/
[root@k8s-master ui]# mv apiserver.crt dashboard.pem
[root@k8s-master ui]# mv  apiserver.key   dashboard-key.pem
[root@k8s-master ui]# kubectl delete secret kubernetes-dashboard-certs -n kube-system
[root@k8s-master ui]# kubectl create secret generic kubernetes-dashboard-certs --from-file=./ -n kube-system
[root@k8s-master]# vim kubernetes-dashboard.yaml #回到这个yaml的路径下修改
修改 dashboard-controller.yaml 文件,在args下面增加证书两行
          - --tls-key-file=dashboard-key.pem
          - --tls-cert-file=dashboard.pem
[root@k8s-master ~]kubectl apply -f kubernetes-dashboard.yaml
[root@k8s-master ~]# kubectl create serviceaccount dashboard-admin -n kube-system
serviceaccount/dashboard-admin created
[root@k8s-master ~]# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin
--serviceaccount=kube-system:dashboard-admin
[root@k8s-master ~]# kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
Name:         dashboard-admin-token-zbn9f
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: dashboard-admin
              kubernetes.io/service-account.uid: 40259d83-3b4f-4acc-a4fb-43018de7fc19

Type:  kubernetes.io/service-account-token

Data
====
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4temJuOWYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNDAyNTlkODMtM2I0Zi00YWNjLWE0ZmItNDMwMThkZTdmYzE5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.E0hGAkeQxd6K-YpPgJmNTv7Sn_P_nzhgCnYXGc9AeXd9k9qAcO97vBeOV-pH518YbjrOAx_D6CKIyP07aCi_3NoPlbbyHtcpRKFl-lWDPdg8wpcIefcpbtS6uCOrpaJdCJjWFcAEHdvcfmiFpdVVT7tUZ2-eHpRTUQ5MDPF-c2IOa9_FC9V3bf6XW6MSCZ_7-fOF4MnfYRa8ucltEIhIhCAeDyxlopSaA5oEbopjaNiVeJUGrKBll8Edatc7-wauUIJXAN-dZRD0xTULPNJ1BsBthGQLyFe8OpL5n_oiHM40tISJYU_uQRlMP83SfkOpbiOpzuDT59BBJB57OQtl3w
ca.crt:     1025 bytes

基于二进制文件-单Master集群部署–环境准备(1)

基于二进制文件-单Master集群部署–Etcd集群部署(2)

基于二进制文件-单Master集群部署–Node节点安装Docker(3)

基于二进制文件-单Master集群部署–部署flannel网络(4)

基于二进制文件-单Master集群部署–Master节点部署组件(5)

基于二进制文件-单Master集群部署–Node节点部署组件(6)

基于二进制文件-单Master集群部署–Dashboard部署(7)

基于二进制文件-Master集群部署(8)

四、kubernetes集群管理

kubernetes管理工具–kubectl

kubectl controls the Kubernetes cluster manager.

Find more information at: https://kubernetes.io/docs/reference/kubectl/overview/

Basic Commands (Beginner):
 create        Create a resource from a file or from stdin.
 expose        Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
 run           Create a spec pod and Run a particular image on this Pod
 set           Set specific features on objects

Basic Commands (Intermediate):
 explain       Documentation of resources
 get           Display one or many resources
 edit          Edit a resource on the server
 delete        Delete resources by filenames, stdin, resources and names, or by resources and label selector

Deploy Commands:
 rollout       Manage the rollout of a resource
 scale         Set a new size for a Deployment, ReplicaSet or Replication Controller
 autoscale     Auto-scale a Deployment, ReplicaSet, or ReplicationController

Cluster Management Commands:
 certificate   Modify certificate resources.
 cluster-info  Display cluster info
 top           Display Resource (CPU/Memory/Storage) usage.
 cordon        Mark node as unschedulable
 uncordon      Mark node as schedulable
 drain         Drain node in preparation for maintenance
 taint         Update the taints on one or more nodes

Troubleshooting and Debugging Commands:
 describe      Show details of a specific resource or group of resources
 logs          Print the logs for a container in a pod
 attach        Attach to a running container
 exec          Execute a command in a container
 port-forward  Forward one or more local ports to a pod
 proxy         Run a proxy to the Kubernetes API server
 cp            Copy files and directories to and from containers.
 auth          Inspect authorization

Advanced Commands:
 diff          Diff live version against would-be applied version
 apply         Apply a configuration to a resource by filename or stdin
 patch         Update field(s) of a resource using strategic merge patch
 replace       Replace a resource by filename or stdin
 wait          Experimental: Wait for a specific condition on one or many resources.
 convert       Convert config files between different API versions
 kustomize     Build a kustomization target from a directory or a remote url.

Settings Commands:
 label         Update the labels on a resource
 annotate      Update the annotations on a resource
 completion    Output shell completion code for the specified shell (bash or zsh)

Other Commands:
 alpha         Commands for features in alpha
 api-resources Print the supported API resources on the server
 api-versions  Print the supported API versions on the server, in the form of "group/version"
 config        Modify kubeconfig files
 plugin        Provides utilities for interacting with plugins.
 version       Print the client and server version information

五、kubernetes网络管理

六、kubernetes存储管理

七、kubernetes监控管理

kubernetes监控方案–cAdvisor+Heapster+InfluxDB+Grafana

kubernetes监控方案–kube-Prometheus(终极方案)

Prometheus监控神技–自动发现

kube-promethues监控告警详解(邮件、钉钉、微信、第三方平台)

八、kubernetes日志管理

九、插件安装

安装traefik ingress

介绍traefik
Traefik是一款开源的反向代理与负载均衡工具。它最大的优点是能够与常见的微服务系统直接整合,可以实现自动化动态配置。目前支持Docker, Swarm, Mesos/Marathon,Mesos, Kubernetes, Consul, Etcd, Zookeeper, BoltDB, Rest API等等后端模型。
以下配置文件可以在kubernetes-handbookGitHub仓库中的manifests/traefik-ingress/目录下找到。

  1. 创建ingress-rbac.yaml,将用于service account验证。
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller
  namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
  name: traefik-ingress-controller
  namespace: kube-system
  1. 创建名为 traefik-ingress 的ingress,文件名traefik-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-ingress
  # 安装好插件后,可以在任何namespace定义Ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: nginx-app
          servicePort: 80
  1. 创建Ingress Deploymen, 文件名traefik-ingrees-lb.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik-ingress-controller
  namespace: kube-system
  labels:
    k8s-app: traefik-ingress-lb
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: traefik-ingress-lb
  template:
    metadata:
      labels:
        k8s-app: traefik-ingress-lb
        name: traefik-ingress-lb
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 60
      hostNetwork: true
      # tolerations:
      # - operator: "Exists"
      # nodeSelector:
      #   kubernetes.io/hostname: master
      containers:
      - image: traefik:v1.7.17
        name: traefik-ingress-lb
        ports:
        - name: http
          # traefik默认端口,可在args添加--web --web.address=:8787改变
          containerPort: 80
          hostPort: 80
        - name: admin
          # traefik默认端口
          containerPort: 8080
          hostPort: 8080
        args:
        - --api
        - --kubernetes
        - --logLevel=INFO
---
kind: Service
apiVersion: v1
metadata:
  name: traefik-ingress-service
  namespace: kube-system
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
    - protocol: TCP
      name: web
      port: 80
      targetPort: 80
    - protocol: TCP
      name: admin
      port: 8080
      targetPort: 8080
  # 使得外部可以访问服务
  type: NodePort
  1. 创建名为 traefik-ui 的ingress,文件名traefik-ui.yaml
# 使用下列指定header访问traefik的pods工作地址即可实现“智能路由”
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-web-ui
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: traefik.alifys.com
    http:
      paths:
      - backend:
          serviceName: traefik-ingress-service
          servicePort: 8080
  1. 实验结果:因为我在win10上使用k8s做实验,这里存在一个无法连通node节点的问题;所以,以下使用了NodePort外部访问和用pod内部访问测试Ingress
# 访问traefix的pods的指定端口后,匹配Ingress路由规则,转发至nginx-app svc
[pod]$ wget http://10.107.207.188:80/ # 10.107.207.188为traefik服务VIP,traefik本身就是一个部署
Connecting to 10.107.207.188:80 (10.107.207.188:80)
saving to 'index.html'
index.html           100% |********************************|   612  0:00:00 ETA
'index.html' saved
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 访问traefix的traefik-ingress-service指定端口后,匹配Ingress路由规则,转发至pod
[pod]$ wget --header="Host:traefik.alifys.com" http://10.107.207.188/
Connecting to 10.107.207.188 (10.107.207.188:80)
saving to 'index.html'
index.html           100% |********************************|   716  0:00:00 ETA
'index.html' saved
cat index.html
<!doctype html><html class="has-navbar-fixed-top"><head><meta charset="utf-8"><title>Traefik</title><base href="./"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/x-icon" href="./assets/images/traefik.icon.png"><link href="styles.e21e21d47be645f690e6.bundle.css" rel="stylesheet"/></head><body><app-root></app-root><script type="text/javascript" src="inline.318b50c57b4eba3d437b.bundle.js"></script><script type="text/javascript" src="polyfills.1457c99db4b6dba06e8d.bundle.js"></script><script type="text/javascript" src="scripts.ef668c5c0d42ec4c5e83.bundle.js"></script><script type="text/javascript" src="main.843538bd56865ee9b7e2.bundle.js"></script></body></html>

[win10]$ curl -H Host:traefik.alifys.com 127.0.0.1:30090
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    34  100    34    0     0  11333      0 --:--:-- --:--:-- --:--:-- 17000<a href="/dashboard/">Found</a>.

protocol: TCP
name: admin
port: 8080
targetPort: 8080

使得外部可以访问服务

type: NodePort


4. **创建名为 traefik-ui  的ingress**,文件名traefik-ui.yaml

```yaml
# 使用下列指定header访问traefik的pods工作地址即可实现“智能路由”
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-web-ui
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: traefik.alifys.com
    http:
      paths:
      - backend:
          serviceName: traefik-ingress-service
          servicePort: 8080
  1. 实验结果:因为我在win10上使用k8s做实验,这里存在一个无法连通node节点的问题;所以,以下使用了NodePort外部访问和用pod内部访问测试Ingress
# 访问traefix的pods的指定端口后,匹配Ingress路由规则,转发至nginx-app svc
[pod]$ wget http://10.107.207.188:80/ # 10.107.207.188为traefik服务VIP,traefik本身就是一个部署
Connecting to 10.107.207.188:80 (10.107.207.188:80)
saving to 'index.html'
index.html           100% |********************************|   612  0:00:00 ETA
'index.html' saved
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 访问traefix的traefik-ingress-service指定端口后,匹配Ingress路由规则,转发至pod
[pod]$ wget --header="Host:traefik.alifys.com" http://10.107.207.188/
Connecting to 10.107.207.188 (10.107.207.188:80)
saving to 'index.html'
index.html           100% |********************************|   716  0:00:00 ETA
'index.html' saved
cat index.html
<!doctype html><html class="has-navbar-fixed-top"><head><meta charset="utf-8"><title>Traefik</title><base href="./"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/x-icon" href="./assets/images/traefik.icon.png"><link href="styles.e21e21d47be645f690e6.bundle.css" rel="stylesheet"/></head><body><app-root></app-root><script type="text/javascript" src="inline.318b50c57b4eba3d437b.bundle.js"></script><script type="text/javascript" src="polyfills.1457c99db4b6dba06e8d.bundle.js"></script><script type="text/javascript" src="scripts.ef668c5c0d42ec4c5e83.bundle.js"></script><script type="text/javascript" src="main.843538bd56865ee9b7e2.bundle.js"></script></body></html>

[win10]$ curl -H Host:traefik.alifys.com 127.0.0.1:30090
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    34  100    34    0     0  11333      0 --:--:-- --:--:-- --:--:-- 17000<a href="/dashboard/">Found</a>.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UnjvYB4Q-1614949922760)(Kubernetes.assets/image-20210106122803107.png)]

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风音素

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

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

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

打赏作者

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

抵扣说明:

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

余额充值