Kubernetes 基础概念与原理解析 ☸
K8s 本质上是应用服务和服务器之间的中间层,通过暴露一系列 API 能力,简化了服务的部署运维流程
整体架构
K8s 整体上遵循 C/S 架构,左侧是一个官方提供的名为 kubectl 的 CLI (Command Line Interface)工具,用于使用 K8s 开放的 API 来管理集群和操作对象等,右侧则是 K8s 集群的后端服务及开放出的 API 等。
1 | +-------------+ |
Node 是用于工作的机器,Master 是一种角色(Role),表示在这个 Node 上包含着管理集群的一些必要组件,生产环境中,为了保障集群的高可用,通常会部署多个 Master。
Master
Master 是整个 K8s 集群的“大脑”,与大脑类似,它有几个重要的功能:
- 接收:外部的请求和集群内部的通知反馈
- 发布:对集群整体的调度和管理
- 存储:负责集群状态的存储
这些功能,也通过一些组件来共同完成,将其称为 control plane
1 | +----------------------------------------------------------+ |
Cluster state store
存储集群所有需持久化的状态,并且提供 watch 的功能支持,可以快速的通知各组件的变更等操作,目前 Kubernetes 的存储层选择是 etcd,一般情况下直接以 etcd 来代表集群状态存储服务,即将所有状态存储到 etcd 实例中。
得益于 etcd 的开发团队较为活跃,而且根据 K8s 社区的反馈做了相当大的改进,并且当时 K8s 团队主要的关注点也不在此,所以直到现在 etcd 仍不是一个可选项,后续也许将此处插件化也不是不可能
API Server
整个集群的入口,接收外部的信号和请求,并将一些信息写入到 etcd 中,它提供了认证相关的功能,用于判断是否有权限进行操作,API Server 支持多种认证方法,一般情况下都使用 X.509 证书进行认证。
X.509 是一种公钥基础设施(PKI)中使用的 数字证书标准,用于验证实体(例如用户、设备或服务器)的 身份。X.509 证书广泛应用于互联网安全、加密通信等领域,包括 HTTPS、电子邮件加密等。X.509 证书由一个可信任的证书颁发机构(CA)签名,用于证明证书中包含的公钥与持有证书的实体是可信的。
API Server 的目标是成为一个极简的 server,只提供 REST 操作,更新 etcd ,并充当着集群的网关,至于其他的业务逻辑之类的,通过插件或者在其他组件中完成。
Controller Manager
是 K8s 集群中最繁忙的部分,它在后台运行着许多不同的控制器进程,用来调节集群的状态,当集群的配置发生变更,控制器就会朝着预期的状态开始工作。
Scheduler
集群的调度器,它会持续的关注集群中未被调度的 Pod ,并根据各种条件,比如资源的可用性,节点的亲和性或者其他的一些限制条件,通过绑定的 API 将 Pod 调度/绑定到 Node 上。
节点亲和性 (Node Affinity) 是一种控制 Pod 调度位置的机制,可以指定 Pod 必须或优先调度到具有特定标签的节点上。节点亲和性比节点选择器 (Node Selector) 更为灵活,可以实现更复杂的调度规则,在资源优化、工作负载隔离、可用性提升等场景中有广泛应用,是 K8s 重要的 调度策略 之一。
Node
(Worker) Node 是加入集群中的机器,Node 加入集群并接受调度、运行服务,归功于运行在 Node 上的几个核心组件。
1 | +--------------------------------------------------------+ |
Kubelet
Kubelet 实现了集群中最重要的关于 Node 和 Pod 的控制功能,如果没有 Kubelet 的存在,那 K8s 很可能是一个纯粹的通过 API Server CRUD 的应用程序。
K8s 原生的执行模式是 操作应用程序的容器,而不像传统模式那样,直接操作某个包或者是操作某个进程。基于这种模式,可以让应用程序之间相互隔离,和主机也是相互隔离的,毕竟它不依赖于主机,在任何的容器运行时(比如 Docker)上都可以部署和运行。
Pod 可以是一组容器(也可以包含存储卷),K8s 将 Pod 作为可调度的基本单位, 分离开了构建时和部署时的关注点:
- 构建时,重点关注某个容器是否能正确构建,如何快速构建
- 部署时,关心某个应用程序的服务是否可用,是否符合预期,依赖的相关资源是否都能访问到
这种隔离的模式,可以很方便的将应用程序与底层的基础设施解耦,极大的提高集群扩/缩容,迁移的灵活性。
Master 节点的 Scheduler
组件,它会调度未绑定的 Pod 到符合条件的 Node 上,而至于最终该 Pod 是否能运行于 Node 上,则是由 Kubelet
来裁定的。
Container runtime
容器运行时最主要的功能是下载镜像和运行容器,最常见的实现是 Docker , 目前还有其他的一些实现,比如 rkt, cri-o。
K8s 提供了一套通用的容器运行时接口 CRI (Container Runtime Interface), 凡是符合这套标准的容器运行时实现,均可在 K8ss 上使用。
Kube Proxy
想要访问某个服务,那要么通过域名,要么通过 IP。每个 Pod 在创建后都会有一个虚拟 IP,K8s 中有一个抽象的概念,叫做 Service
,kube-proxy
便是提供一种代理的服务,可以通过 Service
访问到 Pod。
实际的工作原理是在每个 Node 上启动一个 kube-proxy
的进程,通过编排 iptables
规则来达到此效果。
基本概念
Pod 是 K8s 中最小的可部署单元,中文可以翻译为“容器组”它是用于承载和管理容器的抽象层。一个 Pod 可以包含一个或多个紧密关联的容器,它们共享相同的网络命名空间、IP 地址和存储卷,并在同一个宿主机上运行。
ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。通常不直接使用 ReplicaSet,而是在 Deployment 中声明。
Deployment 是对 ReplicaSet 和 Pod 更高级的抽象,它可以指挥 Kubernetes 如何创建和更新部署的应用实例,创建 Deployment 后,Kubernetes master 会将应用程序调度到集群中的各个节点上,一般用来部署无状态应用。
自愈、缩放
滚动更新、版本回滚
Service 是将运行在一个或一组 Pod 上的网络应用程序公开为网络服务的抽象方法。Service 为一组 Pod 提供相同的 DNS 名,并且在它们之间进行负载均衡。Kubernetes 为 Pod 提供分配了 IP 地址,但 IP 地址可能会发生变化,集群内的容器可以通过 service 名称访问服务,而不需要担心 Pod 的 IP 发生变化。
ClusterIP:将服务公开在 集群内部。kubernetes 会给服务分配一个集群内部的 IP,集群内的所有主机都可以通过这个 Cluster-IP 访问服务。集群内部的 Pod 可以通过 service 名称访问服务。
NodePort:通过每个节点的主机 IP 和静态端口(NodePort)暴露服务。 集群外部 的主机可以使用节点 IP 和 NodePort 访问服务。
ExternalName:将集群外部的网络引入集群内部。
LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。可以通过 Ingress 资源来配置不同的转发规则,从而达到根据不同的规则设置访问集群内不同的 Service 所对应的后端 Pod。当集群位于公有云或私有云上时,要从互联网进行访问,需要使用公网 IP 或者域名,公网 IP 是相对稀缺的资源,不可能给所有主机都分配公网 IP,并且随着公开的服务变多,众多的端口也变得难以管理。面对这种情况,可以使用 Ingress。
Kubectl 是 K8s 提供的命令行工具。
Namespace 是一种资源隔离机制,将同一集群中的资源划分为相互隔离的组。命名空间作用域仅针对带有名字空间的对象,例如 Deployment、Service 等。Kubernetes 会创建四个初始命名空间:
- default 默认的命名空间,不可删除,未指定命名空间的对象都会被分配到 default 中。
- kube-system Kubernetes 系统对象(控制平面和 Node 组件)所使用的命名空间。
- kube-public 自动创建的公共命名空间,所有用户(包括未经过身份验证的用户)都可以读取它。通常我们约定,将整个集群中公用的可见和可读的资源放在这个空间中。
- kube-node-lease 租约(Lease)对象使用的命名空间。每个节点都有一个关联的 lease 对象,lease 是一种轻量级资源。lease 对象通过发送心跳,检测集群中的每个节点是否发生故障。
管理对象的方式
- 命令行指令,使用 kubectl 命令来创建和管理 Kubernetes 对象。命令行就好比口头传达,简单、快速、高效。但它功能有限,不适合复杂场景,操作不容易追溯,多用于开发和调试。
- 声明式配置,kubernetes 使用 yaml 文件来描述 Kubernetes 对象。声明式配置就好比申请表,学习难度大且配置麻烦。好处是操作留痕,适合操作复杂的对象,多用于生产。
- 可视化界面,如云平台容器服务
服务部署流程,
YAML 文件 → kubectl → [API Server → etcd → Scheduler → Controller Mgr] → [Kubelet → Container runtime → Pod]
服务调用流程,
request → Ingress 控制器 → [Kube Proxy → Pod]
kubectl
K8s 遵循 C/S 架构,官方也提供了 CLI 工具 kubectl
用于完成大多数集群管理相关的功能。
基础配置
- 使用
kubectl options
可以看到所有全局可用的配置项 $HOME/.kube/config
中主要包含着:- K8s 集群的 API 地址
- 用于认证的证书地址
- 也可以使用
--kubeconfig
或者环境变量KUBECONFIG
来传递配置文件 - 也可以直接传递相关参数来使用,
kubectl -client-key='xxx' --client-certificate='xxx'
- 使用
get(读取数据类)
- **
kubectl cluster-info
**:查看集群控制平面的信息,包括 API server 和 DNS 服务的访问地址 - **
kubectl get nodes
**:获取集群节点的详细信息,可以通过-o
参数选择输出格式 - **
kubectl api-resources
**:列出集群中支持的所有 API 资源,帮助了解 Kubernetes 中可用的资源 - **
kubectl explain node
**:查看Node
资源的详细字段说明,帮助理解各字段的作用
- **
kubectl run
,运行容器,NAME
和--image
是必需项,分别代表此次部署的名字及所使用的镜像- 实际使用时,推荐编写配置文件并通过
kubectl create
进行部署
- 实际使用时,推荐编写配置文件并通过
kubectl get all
,列出当前命名空间中核心资源类型,比如 Pod、Service、ReplicaSet、Deployment、DaemonSet 等
部署一个 Redis 实例
1 | ➜ ~ kubectl run redis --image='redis:alpine' |
1 | ➜ ~ kubectl get all |
使用 kubectl get all
输出内容的格式 /
前代表类型,/
后是名称
Deployment
是一种高级别的抽象,允许进行扩容,滚动更新及降级等操作利用
Deployment
也能很方便的进行金丝雀发布(Canary deployments),这主要也依赖Label
和Selector
Deployment
的创建更推荐的方式便是使用yaml
格式的配置文件Deployment
主要是声明一种预期的状态,并且会将Pod
托管给ReplicaSet
ReplicaSet
会检查当前的Pod
数量及状态是否符合预期,并尽量满足这一预期
Service
是为了能有个稳定的入口访问应用服务或者是一组Pod
- 通过
Service
可以很方便的实现 服务发现和负载均衡 Service
目前有 4 种类型:ClusterIP
: 是 K8s 当前默认的Service
类型,将 service 暴露于一个 仅集群内 可访问的虚拟 IP 上- 集群内主机 通过
ClusterIP:port
访问服务 - 集群内容器 通过
service name:port
访问服务
- 集群内主机 通过
NodePort
: 是通过在集群内所有Node
上都绑定固定端口的方式将服务暴露出来- 集群外主机 通过
<NodeIP>:<NodePort>
访问服务
- 集群外主机 通过
LoadBalancer
: 是通过Cloud Provider
创建一个外部的负载均衡器,将服务暴露出来,并且会自动创建外部负载均衡器路由请求所需的Nodeport
或ClusterIP
ExternalName
: 是通过将服务由 DNS CNAME 的方式转发到指定的域名上将服务暴露出来
- 通过
1 | ➜ ~ kubectl expose deploy/redis --port=6379 --protocol=TCP --target-port=6379 --name=redis-server |
通过 kubectl expose
命令将 redis server 这个 Service
暴露出来
port
: 是Service
暴露出来的端口,可通过此端口访问Service
protocol
: 是所用协议,当前 K8s 支持 TCP/UDP 协议,默认是 TCP 协议target-port
: 是实际服务所在的目标端口,请求由port
进入通过上述指定protocol
最终流向这里配置的端口name
:Service
的名字,它的用处主要在 dns 方面type
: 是前面提到的类型,如果没指定默认是ClusterIP
redis 是使用的默认类型 ClusterIP
,所以并不能直接通过外部进行访,使用 port-forward
的方式让它可在集群外部访问
1 | ➜ ~ kubectl port-forward svc/redis-server 6379:6379 |
也可以使用 NodePort
的方式对外暴露服务,可以通过任意 Node
上的 NodePort
端口连接 redis 服务,这个端口范围其实是可以通过 kube-apiserver
的 service-node-port-range
进行配置的,默认是 30000-32767
1 | ➜ ~ kubectl expose deploy/redis --port=6379 --protocol=TCP --target-port=6379 --name=redis-server-nodeport --type=NodePort |
认证和授权
K8s 中几乎所有的操作都需要经过 kube-apiserver
处理,所以为了安全起见,K8s 为它提供了三类安全访问的措施:
- 用于识别用户身份的 认证(Authentication)
- 用于控制用户对资源访问的 授权(Authorization)
- 用于资源管理方面的 准入控制(Admission Control)
来自客户端的请求分别经过认证,授权,准入控制之后,才能真正执行
1 | +-----------------------------------------------------------------------------------------------------------+ |
认证(Authentication)
认证是判断当前发起请求的用户身份是否正确。例如,通常登录服务器时候需要输入用户名和密码,或者 SSH Keys 之类的。K8S 支持以下认证机制,可选择同时开启多个认证机制:
- X509 客户端证书
- 引导 Token
- 静态 Token 文件
- 静态密码文件
- Service Account Token
- OpenID
- 认证代理
- Webhook
授权(Authorization)
授权就是在验证当前发起请求的用户是否有相关的权限。例如,在 Linux 系统中常见的文件夹权限之类的。授权是以认证的结果为基础的,授权机制检查用户通过认证后的请求中所包含的属性来进行判断。K8S 支持以下授权机制:
- ABAC(Attribute-Based Access Control)基于属性的访问控制
- RBAC(Role-based access control)基于角色的访问控制
- Node:这是一种特殊用途的授权机制,专门用于对
kubelet
发出的 API 请求做授权验证 - Webhook:使用外部的 Server 通过 API 进行授权校验
- AlwaysAllow:默认配置,允许全部
- AlwaysDeny:通常用于测试,禁止全部
Helm
Helm 是构建于 K8S 之上的包管理器,可与平时接触到的 Yum,APT,Homebrew 或者 Pip 等包管理器相类比。使用 Helm 可简化包分发,安装,版本管理等操作流程。同时它也是 CNCF 孵化项目。
Helm 是 C/S 架构,主要分为客户端 helm
和服务端 Tiller
。helm
通过 gRPC
将 chart
发送至 Tiller
,Tiller
则通过内置的 kubernetes
客户端库与 K8S 的 API server 进行交流,将 chart
进行部署,并生成 Release
用于管理。
原理解析
kube-apiserver
1 | +----------------------------------------------------------+ |
kube-apiserver
作为集群的统一入口,接收来自外部的信号和请求,并将一些信息存储至 etcd 中
- REST API Server
- 对外提供接口,可处理来自客户端(无论
kubeclt
或者curl
或者其他语言实现的客户端)的请求,并作出响应 kube-apiserver
有个--secure-port
的参数,通过这个参数来配置它将要监听在哪个端口,默认情况下是6443
- 对外提供接口,可处理来自客户端(无论
- 认证(Authentication)
kubectl version -v 8
- 获取集群版本号的时候,其实也是向
kube-apiserver
发送了一个请求进行查询的,可以通过传递-v
参数来改变 log level - 首先会加载
$HOME/.kube/config
下的配置,获的集群地址,进而请求/version
接口,最后格式化输出
- 获取集群版本号的时候,其实也是向
curl -k https://172.17.0.99:6443/version
- 使用
curl -k
相当于忽略认证的过程,忽略掉认证过程的curl
被判定为system:anonymous
用户
- 使用
- 授权(Authorization)
- K8S 支持多种授权机制,现在多数都在使用
RBAC
- K8S 支持多种授权机制,现在多数都在使用
- 准入控制(Admission Control)
- 在请求进来时,会先经过认证、授权接下来会进入准入控制环节
- 准入控制和前两项内容不同,它不只是关注用户和行为,它还会处理请求的内容,不过它对读操作无效
- 准入控制与认证、授权插件类似,支持同时开启多个,几个比较常见的插件:
- NamespaceLifecycle:它可以保证正在终止的
Namespace
不允许创建对象,不允许请求不存在的Namespace
以及保证默认的default
,kube-system
之类的命名空间不被删除 - LimitRanger:为
Pod
设置默认请求资源的限制 - ServiceAccount:可按照预设规则创建
Serviceaccount
,比如都有统一的前缀:system:serviceaccount:
- DefaultStorageClass:为
PVC
设置默认StorageClass
- DefaultTolerationSeconds:设置
Pod
的默认 forgiveness toleration 为 5 分钟 - MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook:这两个都是通过 Webhook 验证或者修改请求,唯一的区别是一个是顺序进行,一个是并行进行的
- ResourceQuota:限制
Pod
请求配额 - AlwaysPullImages:总是拉取镜像
- AlwaysAdmit:总是接受所有请求
- NamespaceLifecycle:它可以保证正在终止的
- 处理请求
- 一个请求依次会经过认证,授权,准入控制等环节,当这些环节都已经通过后,该请求便到了
kube-apiserver
的实际处理逻辑中了 - 和普通的 Web server 类似,
kube-apiserver
提供了restful
的接口,增删改查等基本功能都基本类似
- 一个请求依次会经过认证,授权,准入控制等环节,当这些环节都已经通过后,该请求便到了
kube-apiserver
包含的东西有很多,除了认证,授权,准入控制相关功能外,还有审计,证书,存储等配置
etcd
etcd is a consistent distributed key-value store. Mainly used as a separate coordination service, in distributed systems. And designed to hold small amounts of data that can fit entirely in memory.
etcd
是由 CoreOS 团队发起的一个分布式,强一致的键值存储。它用 Go 语言编写,使用 Raft
协议作为一致性算法。多数情况下会用于分布式系统中的服务注册发现,或是用于存储系统的关键数据。etcd
在 K8S 中,最主要的作用便是其 高可用,强一致 的键值存储以及 监听机制
- 在
kube-apiserver
收到对应请求经过一系列的处理后,最终如果是集群所需要存储的数据,便会存储至etcd
中,主部分主要是 集群状态信息 和 元信息 - 默认集群中的 etcd 会放到 kube-system Namespace 中,
kubectl -n kube-system get pods | grep etcd
- etcd2 使用 HTTP/JSON 作为默认的 API 通信协议,允许客户端通过 HTTP API 与 etcd 集群进行交互
- etcd3 引入了 gRPC 作为主要的通信协议,虽然 etcd3 仍支持 HTTP API,但推荐使用 gRPC 进行高效通信,因为 gRPC 比传统的 HTTP API 更高效、更加支持双向流和更好的负载均衡
- etcd3 中,HTTP API 一般仅用于兼容性和简单操作,在 K8s 1.13 发布时,etcd 2 的相关代码已经移除
- 由于 etcd 集群使用 Raft 一致性算法,通常情况下 etcd 集群需要部署奇数个节点,如 3,5,7 等,etcd 集群维护也相对容易,很容易可以做成高可用集群
controller-manager
Controller Manager 实际由 kube-controller-manager 和 cloud-controller-manager 两部分组成,cloud-controller-manager 则是为各家云厂商提供了一个抽象的封装,便于让各厂商使用各自的 provide
kube-controller-manager 是一个 嵌入 了 K8s 核心 控制循环 的 守护进程,负责在集群中运行核心控制循环,以确保集群的状态达到并维持在用户期望的状态
kube-controller-manager
运行多个控制器(例如节点控制器、资源配额控制器等),每个控制器都嵌入了特定的逻辑来管理和协调集群资源的状态控制:
kube-controller-manager
的任务是维护集群的目标状态。例如,当资源发生变化时,它会通过调用 API Server 将实际状态调整为目标状态循环:每个控制器都在一个循环中运行,反复检查资源的状态,并采取必要的操作以确保资源达到预期的状态。循环的执行间隔是可以通过参数配置的,例如
--sync-period
参数,控制各控制器的检查频率kube-controller-manager
是独立部署的一个 守护进程,可以在 Kubernetes 集群的控制平面节点上以独立的进程或容器形式运行, 持续监视并管理资源的状态。守护进程的特点是持久运行,不间断地执行控制循环,确保集群资源的一致性和健康状态
kube-controller-manager
在10252
端口上不仅暴露出来了一个/healthz
接口,还暴露出了一个/metrics
的接口,可用于进行监控之类的
通过 kubectl -n kube-system describe pods -l component=kube-controller-manager
命令可以查看 kube-controller-manager
的 Pod 详细信息
kube-scheduler
The Kubernetes scheduler is a policy-rich, topology-aware, workload-specific function that significantly impacts availability, performance, and capacity.
kube-scheduler
是一个策略丰富,拓扑感知的调度程序,会显著影响可用性,性能和容量。
资源调度本就是 K8s 这类系统中的一个很复杂的事情,既要能满足系统对资源利用率的需要,同样还需要避免资源竞争,比如说端口冲突之类的,为了能完成这样的需求,kube-scheduler
便在不断的迭代和发展,通过支持多种策略满足各类需求,通过感知拓扑避免资源竞争和保障系统的可用性及容量等。
从上层的角度来看,kube-scheduler
的作用就是将待调度的 Pod
调度至最佳的 Node
上,而这个过程中则需要根据不同的策略,考虑到 Node
的资源使用情况,比如端口,内存,存储等。
kube-scheduler
将处理阶段主要分为三个阶段 Computing predicates
,Prioritizing
和 Selecting host
:
Computing predicates
:主要解决的问题是Pod
能否调度到集群的Node
上- 过一个名为
podFitsOnNode
的函数进行实现,在检查的过程中也会先去检查下是否已经有已缓存的判断结果 - 当然也会检查
Pod
是否是可调度的,以防有Pod Affinity
(亲合性) 之类的存在
- 过一个名为
Prioritizing
:主要解决的问题是在上个阶段通过findNodesThatFit
得到了filteredNodes
的基础之上解决哪些Node
是最优的,得到一个优先级列表priorityList
- 给每个经过第一步筛选出来的
Node
一个Score
,再按照各种条件进行打分,最终得到一个优先级列表
- 给每个经过第一步筛选出来的
Selecting host
:则是最终选择Node
调度到哪台机器上
当实际进行部署操作的时候:
- 通过
kubectl
之类的客户端工具与kube-apiserver
进行交互 - 在经过一系列的处理后,数据将持久化到
etcd
中 kube-controller-manager
通过持续的观察,开始按照配置,将集群的状态调整至预期状态kube-scheduler
也在发挥作用,决定Pod
应该调度至哪个或者哪些Node
上- 之后则通过其他组件的协作,最总将该
Pod
在相应的Node
上部署启动
kubelet
1 | +--------------------------------------------------------+ |
按照一般架构设计上的习惯,kubelet
所承担的角色一般会被叫做 agent
,这里叫做 kubelet
很大程度上受 Borg
的命名影响,Borg
里面也有一个 Borglet
的组件存在,kubelet
便是 K8s 中的 agent
,负责 Node
和 Pod
相关的管理任务
kubelet
的作用
- 节点管理
- 当执行
kubelet --help
的时候,会看到它所支持的可配置参数,其中有一个--register-node
参数便是用于控制是否向kube-apiserver
注册节点 的,默认是开启的 kubelet
不仅将自己注册给了kube-apiserver
,同时它所在机器的信息也都进行了上报,包括 CPU,内存,IP 信息等- 向
kube-apiserver
发送心跳包等
- 当执行
- Pod 管理
kube-scheduler
处理了Pod
应该调度至哪个Node
,而kubelet
则是保障该Pod
能按照预期,在对应Node
上启动并保持工作(kubelet
的作用之一就是负责镜像拉取)kubelet
在保障Pod
能按预期工作,主要是做了两方面的事情- 健康检查:通过
LivenessProbe
和ReadinessProbe
探针进行检查,判断是否健康及是否已经准备好接受请求 - 资源监控:通过
cAdvisor
进行资源监控
- 健康检查:通过
kubelet
还承担着清理Node
上一些由 K8s 调度Pod
所造成的磁盘占用之类的工作
kube-proxy
kube-proxy
是 K8s 运行于每个 Node
上的 网络代理组件,提供了 TCP 和 UDP 的连接转发支持,当 Pod
在创建和销毁的过程中,IP 可能会发生变化,而这就容易造成对其有依赖的服务的异常,所以通常情况下,我们都会使用 Service
将后端 Pod
暴露出来,而 Service
则较为稳定
kube-proxy
对于服务注册发现和代理访问等起到了很大的作用,在 Linux 系统上当前支持三种模式,可通过 --proxy-mode
配置:
userspace
:这是很早期的一种方案,但效率上显著不足,不推荐使用iptables
:当前的默认模式,比userspace
要快,但问题是会给机器上产生很多iptables
规则ipvs
:为了解决iptables
的性能问题而引入,采用增量的方式进行更新
默认情况下使用 iptables
的代理模式,当创建新的 Service
,或者 Pod
进行变化时,kube-proxy
便会去维护 iptables
规则,以确保请求可以正确的到达后端服务、
kube-proxy
和Ingress
都是 Kubernetes 中用于网络管理的组件,两者都可以实现流量的负载均衡和分发,kube-proxy
更底层、面向内部流量,而Ingress
更高层、面向外部流量,比如负载均衡层级:
- kube-proxy:在四层(传输层)工作,只支持基于 IP 的负载均衡
- Ingress:工作在七层(应用层),支持基于 HTTP/HTTPS 的请求路由
Container Runtime
kube-scheduler
决定了 Pod
将被调度到哪个 Node
上,而 kubelet
则负责 Pod
在此 Node
上可按预期工作,如果没有 Container Runtime
,那 Pod
中的 container
在该 Node
上也便无法正常启动运行
Container Runtime
(容器运行时)这一概念的产生也是由于容器化技术和 K8s 的大力发展,为了统一工业标准,也为了避免 K8s 绑定于特定的容器运行时,所以便成立了 OCI (Open Container Initiative)组织,致力于将容器运行时标准化和容器镜像标准化
自 K8s 1.5 (2016 年 11 月)开始,新增了一个容器运行时的插件 API,并称之为 CRI
(Container Runtime Interface),通过 CRI
可以支持 kubelet
使用不同的容器运行时,而不需要重新编译
当前使用最为广泛的是
Docker
,当前还支持的主要有runc
,Containerd
,runV
以及rkt
等
Troubleshoot
- 使用
describe
排查问题,kubectl -n work describe pod/xxx
- 使用
events
排查问题,kubectl -n work get events
- 通过详细内容排查错误,比如
kubectl -n work get endpoints
扩展增强
Dashboard - Web 端操作界面
- Dashboard 并不能完全取代 kubectl,两者应该是相辅相成的
- 后端使用 Kubernetes 的
client-go
库来与 API Server 通信,前端基于 Angular 框架开发
CoreDNS - K8s 集群中的 DNS 和服务发现插件
- CoreDNS 是一个独立项目,它不仅可支持在 K8s 中使用,也可以在任何需要 DNS 服务的时候使用它
- 自 K8s1.13 版本起,CoreDNS 成为了集群中的默认 DNS 服务器,替代了以前的 kube-dns 插件
- 提供域名解析和服务发现功能,使 Pod 之间能通过服务名称直接访问
Ingress - K8s 中的流量管理资源
- Ingress 是 Kubernetes 中的流量管理资源,主要用于集群外部的 HTTP/HTTPS 负载均衡、路由和SSL 终止等
- 允许定义基于路径、主机名等的路由规则,引导流量到集群内的正确服务,需要一个 Ingress Controller 实现,常用的有 NGINX Ingress Controller 和 Traefik 等
集群监控,K8s 是一个典型的分布式系统,组件很多,监控的目标就变的很重要了
- 节点情况、K8s 集群自身状态、部署在 K8s 内的应用的状态
- 用于实时收集和监测 Kubernetes 集群的性能和资源使用情况,帮助管理员发现潜在问题和优化集群资源
- rometheus、Grafana 等工具常用于 Kubernetes 的集群监控,帮助展示 CPU、内存、存储等资源的使用情况,还能设置报警和警报管理
部署前后端应用
使用云平台的容器服务
Code → App → Docker Image → Hub → K8s
Golang
构建 Docker 镜像
交叉编译
1 | Windows → Linux |
编写 Dockerfile
1 | 基础镜像 |
打包镜像
1 | 构建 |
启动服务
1 | docker run --rm -it -p 8888:8888 wechatpay:v0.0.1 |
推送到远程仓库
1 | 登录腾讯云容器镜像服务 Docker Registry |
CI/CD
Jenkinsfile
- Check Workspace
- Go Mod Tidy
- Build Go Application
- Build Docker Image
- Push Docker Image
React
Dockerfile
1 | 使用较新的 Node.js 镜像作为构建环境 |