k8s

K8S学习笔记

K8S : 自动化运维管理docker程序

主从架构模型:Master 负责核心调度、管理、运维,Worker(上图的minions)节点则是执行用户程序 所有的Master Node 和Worker Node组成了K8S集群

Master Node

  • API Server : k8s的请求入口服务
  • Scheduler : k8s所有的Worker Node的调度器
  • Controller Manager : k8s所有Worker Node的监控器。有很多具体的controller , 例如Node Controller、Service Controller、Volume Controller 等。 Controller负责监控和调整worker node上部署的服务状态。
  • Etcd : k8s的存储服务。存储关键配置和用户配置,只能通过API Server才能读写数据。其他组件需要通过APIServer 才能读写数据

Worker Node

  • Kubelet: Worker Node的监视器和Master Node的通讯器。定期向master汇报自己node上运行服务的状态,并接受来自master的指示
  • Kube-Proxy : 网络代理,负责Node在k8s里面的网络通讯和对外部网络流量的负载均衡
  • Container Runtime: Worker Node的运行环境(就是装好的docker运行环境)
  • Logging Layer : k8s的监控状态收集器(CPU、内存、磁盘、网络等)
  • Add-Ons : 管理插件的组件

概念

Pod

Pod 是可以在K8s中创建和管理的、最小的可部署的计算单元。就是Pod是K8s中一个服务的闭包,也就是一群可以共享网络、存储和计算资源的容器化服务的集合

举个例子: 同一个Pod之间的Container可以通过localhost来进行访问,并且可以挂载Pod内所有的数据卷,但是不同的Pod之间不行

img

k8s中的所有对象都通过yaml来表示。如下:

apiVersion: v1kind: Pod #记录yaml的对象metadata: #记录pod自身的元数据name: memory-demonamespace: mem-examplespec: #记录了pod内部所有资源的详细信息containers: #记录了pod内的容器信息- name: memory-demo-ctr  image: polinux/stress  resources:    limits:      memory: "200Mi"    requests:      memory: "100Mi"  command: ["stress"] #容器入口命令  args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"] #入口参数  volumeMounts: #pod内的数据卷信息  - name: redis-storage    mountPath: /data/redisvolumes:- name: redis-storage  emptyDir: {}

Volume数据卷

数据卷Volume是Pod内部的磁盘资源,对应一个实体的数据卷,VolumeMounts只是Container的挂载点,对应的是Container的其中一个参数。但是,VolumeMounts依赖于Volume,只有当Pod内有Volume资源的时候,该Pod内部的container才可能有VolumeMount。

Container容器

一个Pod内可以有多个Container 容器分类有:

  • 标准容器 Application Container
  • 初始化容器 Init Container
  • 边车容器 Sidecar Container
  • 临时容器 Ephemeral Container

Deployment和ReplicaSet

Deployment的作用就是管理和控制Pod和ReplicaSet,管控他们运行在用户期望的状态下。也就是如果用户对Pod如果进行了更新,那么Deployment会先起一个ReplicaSet然后等到内部的Pod都处在Ready状态时,再把原本的ReplicaSet停掉,转移到新版本的ReplicaSet上。

ReplicaSet的作用就是管理和控制Pod

img

主要的区别可以看:https://blog.csdn.net/qq_41999455/article/details/104220882

Service

Service是K8s服务的核心,屏蔽了服务的细节,统一对外暴露服务接口。可以理解为是一个简单的服务注册发现组件。 Service类型:

  • ClusterIP:最基本的类型,用作本集群内部的互相通信,也就是起一个转发的作用,避免一个服务宕机了可以保证访问到其他同级的服务
  • NodePort : 集群每个节点上开发一个端口,对外提供服务,同时集群内的节点也可以通过这个内网节点IP 连接到这个端口。外部的话需要通过连接到对外IP的这个端口上。
  • Loadbalancer:这个是建立在NodePort服务之上的, 就是负载均衡器,需要有一个单独的IP地址,它会将请求通过这个IP地址分配给所有的外部节点IP,例如说通过round robin策略

ExternalName

最后是 ExternalName 服务,这个服务和前面的几种类型的服务有点分离。它创建一个内部服务,其端点指向一个 DNS 名。

举个例子, 我们在集群内部需要访问到一个python API这样的外部服务,一般而言我们直接通过对应的url 连接到外部服务商。 但是考虑到以后某个时候如果想把外部服务集成到集群中,还不希望去更改连接的地址(因为修改了url),这时候可以用ExternalName类型的服务了, 只要修改serviceType并设置正确标签就可以了。具体如下:

我们假设 pod-nginx 运行在 Kubernetes 集群中,但是 python api 服务在集群外部。

对应的 YAML 资源清单文件如下所示:

kind: ServiceapiVersion: v1metadata:  name: service-pythonspec:  ports:  - port: 3000    protocol: TCP    targetPort: 443  type: ExternalName  externalName: remote.server.url.com

现在 pod-nginx 就可以很方便地通过 http://service-python:3000 进行通信了,就像使用 ClusterIP 服务一样,当我们决定将 python api 这个服务也迁移到我们 Kubernetes 集群中时,我们只需要将服务改为 ClusterIP 服务,并设置正确的标签即可,其他都不需要更改了。

Python api 仍然可以通过 http://service-python 访问

当我们创建一个 NodePort 的 Service 时,它也会创建一个 ClusterIP,而如果你创建一个 LoadBalancer,它就会创建一个 NodePort,然后创建一个 ClusterIP

此外我们还需要明白 Service 是指向 pods 的,Service 不是直接指向 Deployments 或 ReplicaSets,而是直接使用 labels 标签指向 Pod,这种方式就提供了极大的灵活性,因为通过什么方式创建的 Pod 其实并不重要。接下来我们通过一个简单的例子开始,我们用不同的 Service 类型来逐步扩展,看看这些 Service 是如何建立的。

Service主要负责K8sS集群内部的网络拓扑,Ingress则是负责集群外部访问集群内部的组件,是整个K8S集群的接入层,复杂集群内外通讯。

Ingress

Kubernetes Ingress 只是 Kubernetes 中的一个普通资源对象,需要一个对应的 Ingress Controller 来解析 Ingress 的规则,暴露服务到外部,比如 ingress-nginx,本质上来说它只是一个 Nginx Pod,然后将请求重定向到其他内部(ClusterIP)服务去,这个 Pod 本身也是通过 Kubernetes 服务暴露出去,最常见的方式是通过 LoadBalancer 来实现的。和Nginx相比它已经为我们做了所有的代理重定向工作,这为我们节省了大量的手动配置工作了。

Istio

Kubernetes Services

我们可以用简短地说明下如何实现 Kubernetes Services,这这有助于理解 Istio 如何工作的。

img

图1: Kubernetes native service request

上图的 Kubernetes 集群中一共有两个节点和 4 个 pod,每个 pod 都有一个容器。服务 service-nginx 指向 nginx pods,服务 service-python 指向 python pods。红线显示了从 pod1-nginx 中的 nginx 容器向 service-python 服务发出的请求,该服务将请求重定向到 pod2-python。

默认情况下,ClusterIP 服务进行简单的随机或轮询转发请求,Kubernetes 中的 Services 并不存在于特定的节点上,而是存在于整个集群中。我们可以在下图 中看到更多细节:

img

图2: Kubernetes native service request with kube-proxy

上图要更详细点,Kubernetes 中的服务是由运行在每个节点上的 kube-proxy 组件实现的,该组件创建 iptables 规则,并将请求重定向到 Pod。因此,服务就是 iptables 规则。(还有其他不使用 iptables 的代理模式,但过程是相同的。)

现在我们来看一个配置了 Istio 的相同示例:

图3: Istio Control Plane programs istio-proxy

上图中可以看到集群中安装了 Istio,每个 pod 都有第二个称为 istio-proxy 的 sidecar 容器,该容器在创建期间会自动将其注入到 pods 中。

Istio 最常见的代理是 Envoy,当然也可以使用其他代理(如 Nginx),所以我们将代理称为 istio-proxy。

我们可以看到不再显示 kube-proxy 组件,这样做是为了保持图像的整洁,这些组件仍然存在,但是拥有 istio-proxy 的 pods 将不再使用 kube-proxy 组件了。

每当配置或服务发生变化时,Istio 控制平面就会对所有 istio-proxy sidecars 进行处理,类似于图 2 中 Kubernetes API 处理所有 kube-proxy 组件的方式。Istio 控制平面使用现有的 Kubernetes 服务来接收每个服务点所指向的所有 pods ,通过使用 pod IP 地址,Istio 实现了自己的路由。

在 Istio 控制平面对所有 istio-proxy sidecars 处理之后,它看起来是这样的:

img

图4: Istio Control Plane programmed all istio-proxys

在图 4 中,我们看到 Istio 控制平面如何将当前配置应用到集群中的所有 istio-proxy 容器,Istio 将把 Kubernetes 服务声明转换成它自己的路由声明。

让我们看看如何使用 Istio 发出请求:

图5: Request made with Istio

在上图中,所有的 istio-proxy 容器已经被 Istio 控制平面所管控,并包含所有必要的路由信息,如图 3/4 所示,来自 pod1-nginx 的 nginx 容器向 service-python 发出请求。

请求被 pod1-nginx 的 istio-proxy 容器拦截,并被重定向到一个 python pod 的 istio-proxy 容器,该容器随后将请求重定向到 python 容器。

发生了什么?

图 1-5 显示了使用 nginx 和 python pod 的 Kubernetes 应用程序的相同示例,我们已经看到了使用默认的 Kubernetes 服务和使用 Istio 是如何发生请求的。

重要的是:无论使用什么方法,结果都是相同的,并且不需要更改应用程序本身,只需要更改基础结构代码。

为什么要使用 Istio?

如果在使用 Istio 的时候没有什么变化(nginx pod 仍然可以像以前一样连接到 python pod),那么我们为什么还要使用 Istio 呢?

其惊人的优势是,现在所有流量都通过每个 Pod 中的 istio-proxy 容器进行路由,每当 istio-proxy 接收并重定向一个请求时,它还会将有关该请求的信息提交给 Istio 控制平面。因此 Istio 控制平面可以准确地知道该请求来自哪个 pod、存在哪些 HTTP 头、从一个istio-proxy 到另一个 istio-proxy 的请求需要多长时间等等。在具有彼此通信的服务的集群中,这可以提高可观察性并更好地控制所有流量。

先进的路由,Kubernetes 内部 Services 只能对 pods 执行轮询或随机分发请求,使用 Istio 可以实现更复杂的方式。比如,如果发生错误,根据请求头进行重定向,或者重定向到最少使用的服务。

部署,它允许将一定比例的流量路由到特定的服务版本,因此允许绿色/蓝色和金丝雀部署。

加密,可以对 pods 之间从 istio-proxy 到 istio-proxy 的集群内部通信进行加密。

监控/图形,Istio 可以连接到 Prometheus 等监控工具,也可以与 Kiali 一起展示所有的服务和他们的流量。

img

追踪,因为 Istio 控制平面拥有大量关于请求的数据,所以可以使用 Jaeger 等工具跟踪和检查这些数据。

img

多集群 mesh,Istio 有一个内部服务注册中心,它可以使用现有的 Kubernetes 服务,但是也可以从集群外部添加资源,甚至将不同的集群连接到一个网格中。

img

Sidecar 注入,为了使 Istio 工作,每一个作为网状结构一部分的 pod 都需要注入一个 istio-proxy sidecar,这可以在 pod 创建期间为整个命名空间自动完成(也可以手动完成)。

Istio 会取代 Kubernetes 的服务吗?

当然不会,当我开始使用 Istio 时,我问自己的一个问题是它是否会取代现有的 Kubernetes 服务,答案是否定的,因为 Istio 会使用现有的 Kubernetes 服务获取它们的所有 endpoints/pod IP 地址。

Istio 取代了 Kubernetes 的 Ingress 吗?

是的,Istio 提供了新的 CRD 资源,比如 Gateway 和 VirtualService,甚至还附带了 ingress 转换器 istioctl convert-ingress,下图显示了 Istio 网关如何处理进入流量,网关本身也是一个 istio-proxy 组件。

img

总结

Istio 无疑在 Kubernetes 之上又增加了另一层次的复杂性,但是对于现代微服务架构来说,它实际上提供了一种比必须在应用程序代码本身中实现跟踪或可观察性更简单的方法。

关于 Istio 更多的使用说明,可以查看官方文档 https://istio.io 了解更多。

namespace

namespace是为了把一个k8s集群划分为若干个资源不可共享的虚拟集群而诞生的。