目录

k8s是什么

集群管理

master

node

k8s资源对象

namespace

容器

初始化容器 initContainers

Pod

Pod Volume

Endpoints

Service

Headless Service

service对象的type取值

从k8s集群外部访问Service

Deployment

Deployment对象参数说明

ReplicaSet

ingress

有状态服务与无状态服务

什么是无状态服务和有状态服务及区别

StatefulSet

Kubernetes Operator

批处理应用--Job

Job

CronJob

k8s通用配置

Label 与标签选择器

ConfigMap

业务场景

传统解决方案

k8s解决方案

Secret

自动伸缩

自动伸缩概念

HPA( Horizontal Pod Autoscaler)水平伸缩

VPA( Vertical Pod Autoscaler )垂直伸缩

Kubernetes 集群自动缩放器(CA)

存储类对象

概述

pod中如何挂载存储卷

    VOL_TYPE举例:

PV自动创建实现原理

Dynamic Volume Provisioning

Background

Enabling Dynamic Provisioning

安全类对象

Secret

k8s支持的用户类型

ServiceAccout

ServiceAccount结构

Service Account准入控制器

ServiceAcount访问API Server认证过程

自定义具备cluster-admin角色的ServiceAccount并绑定到pod

角色权限相关对象

Subjects

Role/RoleBinding

ClusterRole/ClusterRoleBinding

k8s内置角色

k8s 内置cluster role(集群角色) cluster-admin、admin、 edit、 view的作用范围及区别_51CTO博客_k8s cluster api

NetworkPolicy

kublet命令

问题

如何部署一个服务

术语


k8s是什么

Kube:netes 是谷歌十几年来大规模容器技术应用的重要成果,是谷歌严格保密十几年的秘密武器— -Borg 的一个开源版本。
Kubemetes 也是一个全新的基于容器技术的分布式架构 领先方案,是 器云的优秀平台选型方案,已成为新 代的基于容器技术的 PaaS 平台的 重要底层框架,也是云原生技术生态圈的核心,服务网格 (Service Mesh) 无服务器架构 (Serverless) 等新 代分布式架构框架及技术纷纷基于 Kubemetes 现,这些都奠定了 Kubernetes 在基础架构领域的王者地位
有了k8s,我们不必再费心于负载均衡器的选型和部署实施问题,不必再考虑引入或自已开发一个复杂的服务治理框架,不必再头疼于服务监控和故障处理模块的开发。这些都已被k8s实现。 使用 Kubernetes 提供的解决方案,我们不仅节省了不少于30 %的开发成本,还可以将精力更加集中于业务本身,而且由于 Kubernetes 提供了强大的自动化机制,所以系统后期的运维难度和运维成本大幅 度降低。
然后, Kubernetes 是一个开放的开发平台 它不局限于任何一种语言, 没有限定任何编程接口,任何语音编写的 服务,都可以部署到k8s上 ,并通过标准的 TCP 通信协议进行交互此外, Kubemetes 平台对现有的编程语言 编程框架、中间件没有任何侵入性,因此现有的系统也很容易改造升级并迁移到 Kubernetes 平台上。
最后, Kubernetes 是一个完备的分布式系统支撑平台。 Kubernetes 具有完备的集群管
理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力 透明的服务注册和服
务发现机制、内建的智能负载均衡器、强大的故障发现和自我修复能力 服务滚动升级和
在线扩容能力、可扩展的资源自动调度机制,以及多粒度的资源配额管理能力 同时,
Kubernetes 提供了完善的 管理工具,这些工具涵盖了 包括开发 、部署测试、运维监控在内
的各个环节 因此, kubernetes 是一个全新的基于容器技术的分布式架构侔决方案,并且
是一个一站式的完备的分布式系统开发和支撑平台。

集群管理

集群 (Cluster) 表示一个由 Master和Node 组成的 kubernetes 集群。

master

Master 指的是集群的控制节点 在每个 Kubemetes 集群中都需要有一个或 组被称为

Master 的节点,来负责整个集群的管理和控制 Master 通常占据一个独立的服务器(在高
可用部署中建议至少使用 台服务器),是整个集群的“大脑”,如果它发生宒机或者不可
用,那么对集群内容器应用的管理都将无法实施。
Master 上运行着集群管理相关的一些进程: ku be-apiserver kube-controller-manager kube-scheduler, 这些进程实现了整 集群的资源管理、 Pod 度、弹性伸缩、安全控制、系统监控和纠错等 管理功能,并且都是自动完成的。
  • Kubemetes API Server(kube-apiserver) :提供 HTTP RESTful API 接口的主要服务,Kubernetes 里对所有资源进行增、删 查等操作的唯 入口,也是集群控 制的入口进程
  • Kubernetes Controller Manager ( kube-controller-manager)Kubernetes 里所有 资源 对象的自动化控制中心 ,可以将其理解为资源对象的“大总管”。
  • Kubemetes Scheduler kube-scheduler) :负责资源调度 Pod 调度 的进程,相当于公交公司的调度室

另外,在 Master 上通常还需要部署 etcd 服务。

node

Node 作为集群中的工作节点,其上运行着真正的应用程序,是 Kubemetes 集群中的工作负载节点。
Node 上, Ku bernetes 管理的最小运行单元是 Pod。
Node 上运行着 Kubemetes kubelet、 kube-proxy 服务进程,这些服务进程负责 Pod 的创建、启动 监控、重启 销毁,以及实现软件模式的负载均衡器。
  • kubelet: 负责 Po 对应容器的创建 启停等任务,同时与 Master 密切协作,实现 集群管理的基本功能
  • kube-proxy: 实现 Kubemetes Service 的通信与负载均衡机制的服务
  • 容器运行时(如 Docker ):负责本机的容器创建和管理
Node 以在运行期间动态增加到 Kubernetes 集群中,前提是 在这个 Node 上已正确安
装、配置和启动了上述关键进程 在默认情况下, kubelet 会向 Master 注册自己,这也是
Kubernetes 推荐的 Node 管理方式 。一 Node 被纳入集群管理范畴, kubelet 进程就会定
时向 Master 汇报自身的情报,例如操作系统、主机 CPU 和内存使用情况,以及当前有哪些
Pod 在运行等,这样 Master 就可以获知每个 Node 的资源使用情况,并实现高效均衡的
资源调度策略 而某个 Node 在超过指定时间不上报信息时,会被 Master 判定为“失联”,该
Node 的状态就被标记为不可用 (Not Ready), Master 随后会触 发”工作负载大转移”
的自动流程。

Taint Nod和Toleration Pod:当需要节点需要运维、下线或升级时,需剔除节点上运行的服务,并防止新的pod被调度到该节点,可以通过给节点打上一种特殊的标签---污点(Taint)来实现。node一旦打了该标签,新的容器被不会被调度到该Node,但Pod可以定义可以 (短期)容忍 (Toleration 某种污点的存在,这些Pod可以继续将其调度到该 Node。Taint和Toleration 这两个术语属Kubernetes 调度相关的重要术语和概念。

k8s资源对象

namespace

namespace在很多情况下用于实现多租户 的资源隔离,典型的一种思路就是给每个租户都分配一 个命名空间。
命名空间属于Kubernetes 集群范畴的资源对象,在一个集群里可以创建多个命名空间,每个命名 间都是相互独立的存在,属于不同命名空间的资源对象从逻辑上相互隔离。
在每个 Kubernetes集群安装完成且正常运行之后, Master 会自动创建两个命名空间,一个是默认的 (default),一个是系统级的 (kube-systern). 用户创建的资源对象如果没有指定命名空间,则被默认存放在 default 命名空间中;而系统相关的资源对象如网络组件 DNS 组件 监控类组件等,都被安装在 kube-systern 命名空间中。
我们可以通过命名空间将集群内部的资源对象“分配”到不同的命名空间中,形成逻辑上分 的不同项目 、小 组或用户组,便于不同的分组在共享使用整个集群 资源的同时能被分别管理。
当给每个租户都创建一个命名空间来实现多租户的资源隔离时 还能结合 Kubernetes 的资源配额管理,限定不同租户能占用的资源,例如 CP 蜇、 存使用证等

容器

初始化容器 initContainers

Pod

pod用于定义运行在其中的一个或多个业务容器,k8s通过pod提供了强大的服务隔离能力,将一组容器(业务)封装到一起共同部署和卸载,在每个 Pod 中都运行着一个特殊的技称为 Pause 容器,其他容器则为业务容器,这些业务容器共享 Pause 容器的网络栈和 Volume挂载卷。

Pod是k8s进行调度部署的最小单位。运行在一个被称为节点 (Node) 的环境中, 这个节点既可以是物理机,也可以是私有云或者公有云 的一个虚拟机,在每个节点上能 够运行多个 Pod;
可以为pod设置多个不同标签,以为pod进行识别和分组。其它对象(如Service、Deployment对象)通过pod的标签来关联满足条件的pod。
为什么 Kubernetes 会设计出一个全新的 Pod 概念并且 Pod 有这样特殊的组成结构?原如下:
  • 为多进程之间的协作提供 个抽象模型,使用 Pod 作为基本的调度 复制等管理工作的最小单位,让多个应用进程能一起有效地调度和伸缩。
  • Pod 里的 多个业务容器共享 Pause 容器的 IP, 共享 Pause 容器挂接的 Vo lume,样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。
Kubernete 为每个 Pod 分配了唯一 IP 地址,称之为 Pod IP, 一个 Pod 里的 多个
容器共享 Pod IP 地址。
Kubernetes 要求底层网络支待集群内任意两个 Po 之间的 TCP/IP
直接通信,这通常 采用虚拟二层网络技术实现,例如 Flannel Open vSwitch 等,因此我们
需要牢记一点 Kubernetes 里, 一个 Pod 里的容器与另外主机上的 Po 容器能够直接通信。

Pod 其实有两种类型:普通的 Pod 及静态 Pod (Static Pod) 。后者比较特殊,它并没被存放在 Kubernetes etcd 中,而是被存放在某个具体的 Node 上的 一个具体文件中,并且只能在此 Node 启动、运行 而普通的 Pod 旦被创建,就会被放入 etcd 中存储,随后被Kuberntes Master 调度到某个具体的 Node 上并绑定 Binding Pod 技对应的 node上的 ub 进程实例化成一组相关的 Docker 容器并启动。在默认情况下,当 里的某个容器停 时, Kubernetes 会自动检测到这个问题并且重新启动这个 Pod (重启 Pod 里的所有容器),如果 Pod 所在的 Node 宥机,就会将这个 Node 上的所有 Pod 都重新调度到其他节点上

问题:静态pod的用途?

Pod Volume

Pod Volume 是被定义在 Pod 上,然后被各个容器挂载到自己的文件系统中 的。 Volume 单来
说就是被挂载到 Pod 里的文件目录。

Endpoints

pod中包含了业务容器, Pod IP 加上这里的容器端口 (containerPort)组成了一个新的概念一 Endpoint, 代表此 Pod 里的 一个服务进程的对外通信地址

一个 Pod 存在具有多个 Endpo int 的情况,比如 当我们把 Tomcat 定义为一个 Pod 时,可以对外暴露 管理端口与服务端口这两个 En dpoint。

相同的业务(pod)可以被k8s调度运行在多个主机上,形成服务集群,这些服务列表被封装在EndPoints对象中。

Service

Ku bernetes 中, Service 是分布式集群架构的核心 。一个 Servi ce 象拥有如下关键
特征。
  • 拥有唯一指定的名称(比如 mys ql- serve
  • 拥有一个虚拟 地址 (Clu sterI 地址)和端口号
  • 能够提供某种远程服务能力
  • 能够将客户端对服务的访问请求转发到一组负载上,即一个Service对应一个Endpoints。

Service 的服务进程通常基于 Socket 通信方式对外提供服务,比如 Redis Memcached MySQL Web Server ,或者是实现了某个具体业务的特定 TCP Server 进程

虽然一个 Service 通常由多个相关的服务进程提供服务 每个服务进程都有一个独立的 Endpoint ( IP+Port ) 访问点,但 Kubernetes 能够让我们通过 service (ClusterIP+Service Port )连接指定的服务。

在创建Service定义中,若不指定type,则默认为ClusterIP类型的Service,这样的Service创建后,k8s会自动为其分配一个ClusterIP,Service 本身一 创建就不再变化,且在service的整个生命周期内,ClusterIP(若存在)不会改变。

ClusterIP 地址是一种虚拟 IP 地址,它有以下特点:

  • ClusterIP 地址仅仅作用于 Kubemetes Service 这个对象, 并由 Kubemetes 管理和分IP 地址(来源于 ClusterIP 地址池),与 Node Master 所在的物理网络完全无关。
  • ClusterIP没有一个“实体网络对象”来对应,所以 ClusterIP 地址无法被 Ping通。
    Cluster IP 地址只能与 Service Port 组成一个具体的服务访问 端点,单独的 ClusterIP 不具备 TCP IP 通信的基础。
  • ClusterIP 属于 Kubernetes 集群这个封闭的空间,集群外的节点无法直接访问,若想访问则需要做一些额外的工作。

k8s内部的服务发现机制

在k8s内部,除了可以通过Service的ClusterIP访问Service,更希望通过service name而不是ClusterIP访问servie,因此需要k8s提供服务发现机制。

k8s通过Add-On增值包的方式引入kube-dns,为每一个Service名称生成一条dns记录,name是service名称,port为该service的port。 定义Service时若不指定port,k8s会自动为其创建随机端口,推荐让k8s自动为其创建port。

k8s内部的负载均衡实现机制

k8s的基于iptables+IPVS为ClusterIP类型的Service添加了负载均衡和会话保持功能。通过负载均衡,将集群内发出的到clusterIP(也叫VIP):servicePort的请求路由到后端某个具体的Endpoint上。同时还实现了会话保持机制。

k8s在集群的每一个节点上上都运行了一套全局的虚拟负载均衡器,其实现原理是通过cube-proxy为集群内的所有service,添加并自动实时依据最新的Service Endpoint列表更新iptabless规则,结合ipvs机制,把对 Service 的请求转发到其后端对应的某个 Pod 实例上,并在内部实现服务的负载均衡与会话保待机制。

从实现原理上可以看出,k8s是交友位于请求发起端的iptables规则+ipvs实现了负载均衡能力,因此是一种客户端的负载均衡(而非将负载均衡作为一个独立的服务组件)。

问题:
1. 会话保持机制如何实现的
答:在k8s内部访问服务,走的是k8s内部的负载均衡,会话保持基于客户端IP实现。由于请求端和服务端位于二层虚拟网络,client ip不会被中途篡改( 问题:是这样吗?),会话保持机制不会有问题。
通过k8s外部的ingress访问内部服务时,走的是nginx上的负载均衡,而非k8s内部的负载均衡,会话保持实现机制就不是基于客户端ip了,可以是其它实现方式,因而也不会有问题。
2. k8s内部的负载均衡策略如何设置?
3. istio 是利用 k8s 的服务发现 + 负载均衡机制,还是自己设计了独立的负载均衡机制 ?

Headless Service

除了正常的 service ,还有一种特殊的 Service--Headless Service ,只要在Service的定义中设置了clusterIP:none就定义了一个Headless Service, 它与普通Service的关键区别在于它没有ClusterIP 地址,如果解析Headless Service 的DNS域名,则返回的是该Service 对应的全部 Pod的Endpoint列表,这意味着客户端是直接与后端的Pod建立 TCP/IP连接进行通信的,没有通过虚拟ClusterIP 地址进行转发,因此通信性能最高,等同于”原生网络通信”

问题:何时用Headless Service?不需要对外保留服务地址时?

service对象的type取值


1. ClusterIP(默认):k8s会为当前Service分配ClusterIP地址(设置ClusterIP:None,即Headless Service则会不分配ClusterIP),负载均衡一组Pod对应的Endpoints负载。从集群外无法直接访问
2. NodePort:在ClusterIP基础上,将服务的ip映射到节点上。其实现方式是,在 Kubernetes 集群的每个 Kode 上都为需要外部访问的Service 开启 一个对应的 监听端口,外部系统只要用任意一个 Node IP 地址+NodePort端口号即可访问此服务,在任意 Node 上运行 netstat 命令,就可以看到有 NodePort 端口被监听。 缺点:每个端口只能是一种服务,另外端口范围只能是 30000-32767,另外如果节点/VM 的 IP 地址发生变化,需要能处理这种情况,因此不建议使用NodePort类型的Service。若不指定nodePort,系统将选择一个随机端口。应该让 Kubernetes 来选择端口,因为用户自己来选择可用端口代价太大。 不推荐这种方式暴露服务到k8s外部。
3. ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理
4. LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。缺点是每个服务都要有自己的公网IP, 付费,成本太高。要从外部访问service,推荐使用Ingress.

从k8s集群外部访问Service

几种实现方式:
  • 将Service类型定义为NodePort;不推荐
  • 将Service类型定义LoadBanlancer;不推荐
  • 通过ingress对象访问service。推荐

Deployment

Deployment用于执行pod的线上部署操作。通过Deployment可以定义哪个pod需要部署,部署几份实例,以及pod所需的运行的环境、配置信息、资源,并可以定义系统资源(CPU、内存)的配额。定义Deployment时,可同时定义Pod。

Kubemetes 集群中,只需为需要扩容的 Service 关联的 Pod 创建 Deployment
象,服务扩容以至服务升级等令人头疼的问题就都迎刃而解了 在一个 Deployment 定义
文件中包括以下 个关键信息

  • 目标 Pod 的定义
  • 目标 Pod 需要运行的副本数益 (Replicas)
  • 要监控的目标 Pod 标签

在创建好 Deployment 之后, Kubemetes 会根据这一定义创建符合要求的 Pod, 并且通
过在 Dep loyment 中定义的 Label 筛选出对应的 Pod 实例并实时监控其状态和数量 如果
实例数量少于定义的副本数量,则会根据在 Dep loyment 对象中定义的 Pod 模板创建一个
新的 Pod, 然后将此 Pod 调度到合适的 Node 上启动运行,直到 Pod 实例的数噩达到预定
目标。这个过程完全是自动化的,无须人工干预 有了 Deployment, 服务扩容就变成一个
纯粹的简单数字游戏了,只需修改 Deployment 中的副 本数撮即可 后续的服务升级也将
通过修改 Deployment 来自动完成。

只有一个 Pod 副本实例时,我们是否也需要 Deployment 来自动创 Pod ?在大多数情况下,这个答案是"需要“。这是因为 Deployment 除自动创建 Pod 副本外,还有一个很重要的特性:自动控制 举个例子,如果 Pod 所在的节点发生岩机事件, Kubernetes会第一时间观察到这个故障,并自动创建一个新的 Pod 象,将其调度到其他合适的节点上, Kubernetes 会实 时监控集群中目标 Pod 的副本数氮,并且尽力与 Deployment 声明的replicas 数量保持一致。

Deployment对象参数说明

参见:

k8s-deployment常见参数说明 | 努力挣扎的生活

 

Deployment配置对象可配置的参数包括:

  1. 基本信息:Deployment名称、所属命名空间、pod选择器
  2. 副本数 replicas
  3. 更新策略,rollingUpdate(滚动更新默认)、Recreate(先全部删除已有的Pod对象,然后创建新版本的Pod对象)。对rollingUpdate(默认),共T个pd,更新过程是先上m个,再下n个。其中m和n分布通过maxSurge和maxAvailable参数进行控制,可以是0、正整数或百分比,且二者不能同时为0。如:m=1,n=0表示逐个升级,先上一个新,再除一个旧。
  4. 模板(Pod)定义,包括:
    1. 容器定义,包括:
      1. 镜像(image)及拉取策略(imagePullSecrets)、镜像拉取加密的用户密码(imagePullPolicy)、端口(ports)
      2. 启动/存活检测startupProbe/livenessProbe/readinessProbe:分别用于判断容器起到是否完成(用于控制起到完成之前不能对外提供服务)、端口是否正常、业务程序是否正常(端口正常不代表业务正常),检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除
      3. 资源限制,包括初始资源请求(requests)和最大资源限制limits
      4. 容器内环境变量设置(env)、磁盘挂载(volumeMounts,通过name属性从volumes加载存储,挂载到mountPath下),如:
        #容器挂载
        volumeMounts:
        #容器挂载内部目录
        - mountPath: /usr/share/nginx/html/
          name: nginx-dp
    2. pod重启策略(restartPolicy):
      • OnFailure:容器异常时自动重启,
      • Never:从不重启容器,
      • Always:只有容器不允许状态,就自动重启容器
      • restartPolicy: Always
    3. 亲和设置(affinity):包括部署的节点亲和(nodeAffinity)和pod亲和性(podAffinity)(一定和某个pod部署在同一个节点上,希望pod部署在某个节点上)、pod反亲和性(podAntiAffinity,与亲和力相反,一定不能部署在某个节点上或不希望与某个pod一起部署)、尽量亲和(尽量但不必须)
    4. pod调度规则,包括
      • 预选策略Predicates包括:
        • PodFitsPorts(PodFitsPorts)
        •  PodFitsResources(PodFitsResources)
        • NoDiskConflict(NoDiskConflict)
        • MatchNodeSelector(PodSelectorMatches)
        • HostName(PodFitsHost)
      • 节点亲和性(nodeAffinity)
      • pod亲和性(podAffinity)
      • 污点(Taint,Toleration)
    5. 安全上下文securityContext,举例:docker限制了最大文件句柄数,如何解除这个限制?
      参见:K8S为 Pod 或容器配置安全上下文securityContext,解决Docker容器限制文件句柄数的问题_运维@小兵的博客-CSDN博客_k8s securitycontext
    6. #优雅的终止服务(terminationGracePeriodSeconds),默认30s,
    7. 挂载卷信息(volumes,为volumeMounts的name属性提供挂载存储块),volume数组,包括PVC如:
       
      #集群挂载信息
      volumes:
        #与容器volumeMounts部分的name相同
        - name: nginx-dp
      	#指定pvc类型
      	persistentVolumeClaim:
      	  #指定pvc名
      	  claimName: nginx-dp-pvc
      ​​​​
    8. Pod设置DNS的策略(dnsPolicy)
      • ClusterFirst(默认),所有请求会优先在集群所在域查询,如果没有才会转发到上游DNS,
      • Default:使用宿主机的/etc/resolv.conf,
      • ClusterFirstWithHostNet:Pod运行在hostNetwork:true的情况下强制指定的
      • None:自定义dns


 

ReplicaSet

Deployment 资源对象其实与 replicaSet 资源对象密切相关 k8s内部会根据Deployment 对象自动创建相关联的 plicaSet 对象,通过以下命令,我们可以看到它的命名与 Deployment 的名称有对应关系。

ingress

通过ingress对象,可以将多个k8s内部的service,以http地址的方式暴露到集群之外。不同的service的http uri不同。如外部访问http://mycompany.com/articile,就会路由到k8s内部的article服务上,当访问http://mycompany.com/vote,就会路由到k8s内部的vote服务上。

ingress对象配置示例:

#外部访问foo.bar.com时,路由到servicel
#访问bar.foo.com时,路由到service2 
kind: Ingress 
metadata: 
	name: name-virtual-host-ingress
spec: 
	rules: 
	  - host: foo.bar.com 
		http: 
		  paths: 
		  - backend: 
			  serviceName: servicel 
			  servicePort: 80 
	  - host: bar.foo.com 
		http: 
		  paths: 
		  - backend: 
			  serviceName: service2 
			  servicePort: 80 

ingress实现原理

k8s提供了IngressController,以DaemonSet方式,部署在k8s的所有节点上。

IngressController内置了nginx,作为反向代理服务器。

同时,还内置了一个对应的controller,通过与k8s api交互,实时、动态的去感知集群中ingress规则变化,根据最新的ingress定义,获取对应的Service和对应Endpoint列表(Endpoint列表在nginx中生成upstream),生成最新的nginx的配置,再写到nginx pod的nginx.conf,最后reload一下。

注意:写入nginx.conf的不是service地址,而是service backend的pod地址列表(nginx upstream片段),避免在service上增加一层负载均衡转发。

ingress对象定义的只是逻辑映射关系规则,IngerssController解析ingress时,并不是将各个service放到nginx的同一个upstream中,而是会从中提取出每一个service对应的Endpoint列表,为每一个service其生成访问的uri,并将其Endpoint列表放到upstream中。

参见:Ingress的概念和原理_m0_46172263的博客-CSDN博客_ingress

有状态服务与无状态服务

什么是无状态服务和有状态服务及区别

https://www.jianshu.com/p/1abdbe8e557d

有状态服务和无状态服务对比
对比维度有状态服务无状态服务
配管k8s对象StatefulSet(对应无状态服务的Deployment)、Headless Service、Kubernete OperatorRC、Deployment、DaemonSet和Job
唯一性唯一性。
有状态服务中的每一个pod的业务角色不同,因此集群中的每个Pod都需要具有唯一、稳定的网络标识。StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。唯一性体现在:
1. 每个pod都有唯一名称:StatefulSet-序号(从0开始),如mySql-0
2.  每个pod都有唯一DNS域名:pod名称.Headless service名称,如mySql-0-mySqlService。(StatefulSet要结合Headdless Service使用,在StatefulSet定义中声明它属于哪个Headless Service,在此基础上为每一个控制的pod实例都创建了一个唯一的DNS域名)
 

随机性。
通过Deployment创建的无状态服务中的每个pod实例实现的业务都完全相同,在集群内都是随机调度的,各Pod名称,IP、主机名、存储都是随机,不稳定的,并且Pod的创建与销毁也是无序的,没有唯一性和顺序性要求,集群中的某个成员节点岩机后,可在其他节点上随意启动 一个新的 Pod 实例。

稳定性稳定。
Pod主机名,DNS地址、挂载的PV、不会随着Pod被重新调度而发生变化.
不稳定。
pod被重新启动调度后,它的名称与IP都会发生变化
顺序性
有序性
StatefulSet控制的Pod副本的启、停、更新、删除顺序是受控的,操作第n个Pod时,前n-1个Pod已经时运行且准备好的状态
 
无序性
启动、更新、停止、删除都没有顺序要求
状态特性有状态。
有状态服务中的每一个pod都是有状态的、各自运行不同的功能,各自在其本地独立存储不同的数据、通常会持久化数据到永久存储中。每个实例对于同一个用户请求的响应结果不一致。
如果停止集群中的某个pod服务、或对应的存储发生损坏,则业务功能会受损甚至崩溃。
 
无状态。
无状态服务不会在本地(要么共享存储、要么无存储)存储持久化数据.多个服务实例对于同一个用户请求的响应结果是完全一致的.这种多服务实例之间是没有依赖关系,
某个pod故障后,随机找一个可用的节点重新调度一个新的pod即可。
存储特性稳定的持久化存储: StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)
Pod被重新调度后,仍然能挂载原有的PV,从而保证了数据的完整性和一致性.
无存储或共享存储
集群规模
 有状态服务中的集群规模是比较固定的,不能随意伸缩,需人为干预,在伸缩前后需要做大量工作。
业务规模可以根据访问压力自动伸缩。
举例主从架构功能的服务,如数据库、Redis主从、 nginx、zookeeper、kafka比如web应用,在k8s控制器 中动态启停无状态服务的pod并不会对其它的pod产生影响.


 

无状态服务与有状态服务存储对比:前者为共享存储,后者为独立存储。

在这里插入图片描述

StatefulSet

Kubernetes Operator

批处理应用--Job

批处理应用的特点是一个或多个进程处理一组数据(图像、文件、视频等),在这组数据都处理完成后,批处理任务自动结束。为了支持这类应用, k8s引入了新的资源对象一一Job与CronJob。
Job用于执行一次性任务,CronJob用于执行周期任务。

Job

用于执行一次性任务。举例如下(计算圆周率):(注意apiVersion、kind、completions、parallelism几个参数)。

apiVersion:batch/vl 
kind:Job 
metadata:
    name:pi 
spec: 
    template:
        spec:
            containers: 
                - name: pi 
                image:perl 
                command:["perl ", "-Mbignum=bpi ", "-wle ", "print bpi (10:J) " J 
        restartPolicy: Never 
    #两个控制并发数的参数

    #表示需要运行任务数的总数
    completions:5

    #并发运行的个数
    parallelism: 1

CronJob

k8s通用配置

Label 与标签选择器

Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。我们可以通过给指定的资湃对象捆绑一个或多个不同的 Labe] 来实现多维度的资源分组管理功能,以便灵活、方便地进行资源分配、调度 、配置、部署等管理工作,例如,部署不同版本的应用到不同的环境中,以及监控 分析应用(日志记录、监控、告警)等 一些常用的 Label 示例如下:

  • 版本标签: release : stable release : canary
  • 环境标签: environment : dev nvironment : qa env onment : production
  • 架构标签: tier : frontend tier : backend tier : middleware
  • 分区标签: partition : customerA partition : customerB
  • 质量管控标签 track : daily track : weekly

给某 资源对象定义一个 Label, 就相当于给它打了一个标签,随后可以通过 Label Selector (标签选择器)查询和筛选拥有某些 Label 的资源对象, Kubemetes 通过这种方式实现了类似 SQL 的简单又通用的对象查询机制 Label Selector 可以被类比为 SQL 语句中where 查询条件,例如, “name=redis-slave" 这个 Label Selector 作用于 Pod 时,可以被类比为 “select* from pod where pod's name='redis-slave'" 这样的语句 。

当前有两种 LabelSelector 表达式:基于等式的 (Equality-based) Selector 表达式和基于集合的 Set-based)Selector 表达式;

基于等式的 Selector 表达式采用等式类表达式匹配标签,下面是一些具体的例子

  • name = redis-slave: 匹配所有具有 name redis-slave 标签的资源对象
  • env production: 匹配所有不具有 env=production 标签的资源对象,比如 “env=test"
  • 就是满足此条件的标签之一。

基于集合的 Selector 表达式则使用集合操作类表达式匹配标签,下面是一些具体的例
子。

  • name in ( redis-master, redis-slave) :匹配所有具有 name=redis-master 签或者name= redis-slave 标签的资源对象
  • name not in php-fronlend :匹配所有不具有 name=php-frontend 标签的 资源对象。

可以通过多个 Label Selector 表达式的组合来实现复杂的条件选择 ,多个表达式之间用“,”进行分隔即可,几个条件之间是 “AND" 的关系,即同时满足多个条件,比如下面的例子:
narne=redis-slave,env!=preduction 
name notin (php-frontend),env !=production

下面是一个具体的例子。

apiVersion : apps/ v l 
kind: Dep.l:oyment 
metadata: 
name : frontend 
spec : 
    replicas : 1 
    selector: 
matchLabels : 
    tier : frontend 
    matchExpressions: 
    {key: tier, operator : In , values : [frontend]} 
template : 
   ...

ConfigMap

业务场景

每一个应用都需要一个静态配置文件提供启动参数,尤其是一个分布式应用,多个副本部署在不同的机器上,如何方便地分发它们的配置?

传统解决方案

很多多分布式系统本身都有一个配置中心组件来解决这个问题。但配置中心通常会引入新的API,从而导致应用的耦合和侵入。

k8s解决方案

Kubernetes则采用了一种简单的方案,即ConfigMap来规避传统解决方案的问题,如图所示,具体做法如下:

  • 用户将配置文件的内容保存到ConfigMap中,文件名可作为key,value就是整个文件的内容,多个配置文件都可被放入同一个ConfigMap。
  • 在建模用户应用时,在Pod里将ConfigMap定义为特殊的Volume进行挂载。在Pod被调度到某个具体Node上时,ConfigMap里的配置文件会被自动还原到本地目录下,然后映射到Pod里指定的配置目录下,这样用户的程序就可以无感知地读取配置了。
  • 在ConfigMap的内容发生修改后,Kubernetes会自动重新获取ConfigMap的内容,并在目标节点上更新对应的文件。

Secret

Secret也用于解决应用配置的问题, 不过它解决的是对敏感信息的配置问题,比如数据库的用户名和密码、 应用的数字证书、 Token、 SSH密钥及其他需要保密的敏感配置 。对于这类敏感信息,我们可以创建一个Secret 对象,然后被Pod引用 。 Secret 中的数据要求以 BASE64编码格式存放。注意,BASE64编码并不是加密的。

在Kubernetes 1. 7版本以后, Secret中的数据才可以以加密的形式进行保存,更加安全。

自动伸缩

自动伸缩概念

什么是弹性伸缩?
弹性伸缩概述

HPA( Horizontal Pod Autoscaler)水平伸缩

Deployment来控制Pod,若手工伸缩,则执行命令kubectl scale命令来实现Pod扩容或缩容。

运维目标---自动化、智能化:k8s希望能动态追踪分析指定Deployment控制的所有目标Pod的负载变化情况,来确定是否需要有针对性地调整目标Pod的副本数量,做到无人值守,实现自动运维。

为此,k8s提供了HPA对象。可以将HPA理解为Pod横向自动扩容,即自动控制Pod数量的增加或减少。Kubernetes内置了基于Pod 的CPU利用率进行自动扩缩容的机制,应用开发者也可以自定义度量指标如每秒请求数, 来实现自定义的 HPA功能。

下面 是一个HPA定义的例子(副本数量限定在1-0范围,pod扩缩容的依据是CPU使用率超过了90%):

HPA问题:需要运行基准测试任务来确定 CPU 和内存请求的合适值,这通常不易确定。一是需要一定的测试,有一定的工作量,二是可能不具备相对应的投产环境(如CPU、内存、网络、存储等)条件,无法得到一个合理的基准值。

解决办法:VPA。

VPA( Vertical Pod Autoscaler )垂直伸缩

HPA设置的资源阈值设置多少通常不易确定,因为实际运行过程中会动态变化(比如预估1000人访问,实际可能很多或很少,如高峰时段和闲暇时不一样),VPA是根据pod在投产环境运行过程中实际占用的资源量,自动推测并设置Pod合理的CPU和内存的需求指标(在定义Deployment时可以设置请求的最小和最大资源,有了VPA,),从而更加精确地调度Pod,实现整体上节省集群资源的目标, 因为无须人为操作, 因此也进一步提升了运维自动化的水平。

VPA优势:

  • Pod 资源用其所需,所以集群节点使用效率高;
  • Pod 会被安排到具有适当可用资源的节点上;
  • 不必运行基准测试任务来确定 CPU 和内存请求的合适值;
  • VPA 可以随时调整 CPU 和内存请求,无需人为操作,因此可以减少维护时间;

Kubernetes 集群自动缩放器(CA)

使用业务场景:我们从云厂商申请了1000核cpu,1T内存搭建k8s集群,随着部署的应用增多,当5个节点的资源达到瓶颈而出现pending pod时,希望云厂商能自动添加新的资源进来。

集群自动伸缩器(CA)基于待处理(状态:pedding)的pod扩展集群节点。它会定期检查是否有任何待处理的pod,如果需要更多的资源,并且扩展的集群仍然在用户提供的约束范围内,则会增加集群的大小。CA与云供应商接口,请求更多节点或释放空闲节点。它与GCP、AWS和Azure兼容。版本1.0(GA)与Kubernetes 1.8一起发布。

参见:

Kubernetes-自动扩展器HPA、VPA、CA_SRE运维充电站的博客-CSDN博客_hpa vpa

存储类对象

概述

目前k8s支持的存储卷可以大致分为一下几类,它们各自有着不同的实现插件:

  • 临时存储卷:emptyDir
  • 本地存储卷:hostPath
  • 特殊存储卷:configmap、secret、gitRepo(通过挂载一个空目录,并从 Git 库克隆 clone 一个 git repository 以供Pod 使用)
  • 网络存储卷:nfs、cinder、rbd、iscsi等
  • 扩展支持第三方存储的存储接口:CSI (Container Storage Interface(容器存储接口)

通常k8s内置的存储卷插件可以归类为In-Tree类型,它们通k8s源码一起发布迭代,而由存储厂商借助CSI接口扩展的独立于k8s源码的插件统称为Out-of-Tree类型,集群管理员可以根据需要创建自定义的扩展插件,CSI是比较常用的实现方式。目前k8s已经开始逐步将In-Tree类型的存储卷插件迁移到CSI,所以建议在新环境中使用CSI。

pod中如何挂载存储卷

在pod.spec中声明要挂载的存储卷,然后在container中将这些存储卷挂载到指定的目录。

spec:

  #声明要挂载的存储卷(可以有多个)
  volumes:
  - name <string>  # 存储卷名称标识,仅可使用DNS标签格式的字符,在当前Pod中必须唯一
    VOL_TYPE <Object>  # 存储卷插件及具体的目标存储供给方的相关配置

  containers:
  - name: …
    image: …

    #将pod.spec中声明的存储卷(通过name关联)挂载到mountPath 指定的目录
    volumeMounts:
    - name <string>  # 要挂载的存储卷的名称,必须匹配存储卷列表中某项的定义
      mountPath <string> # 容器文件系统上的挂载点路径
      readOnly <boolean>  # 是否挂载为只读模式,默认为“否”
      subPath <string>     # 挂载存储卷上的一个子目录至指定的挂载点
      subPathExpr <string>  # 挂载由指定的模式匹配到的存储卷的文件或目录至挂载点

    VOL_TYPE <Object> 举例:

emptyDir

kind: Pod
spec:

   #声明要挂载的存储卷(可以有多个)
  volumes:
  - name: config-file-store
    emptyDir:
      medium: Memory      #如果要使用磁盘就使用""就可以了,但是这里只会在节点上创建一
个临时存储目录
      sizeLimit: 16Mi

  #由initContainer加载数据(比如配置信息)到挂载点,其它容器读取数据
  initContainers:
  - name:configInit

    volumeMounts:
    - name: config-file-store
      mountPath: /data
  containers:
  - name: envoy
    volumeMounts:
    - name: config-file-store
      mountPath: /etc/envoy
      readOnly: true

NFS方式

kind: Pod
spec:
  volumes:
    - name: redisdata
      nfs:
        server: 192.168.8.30
        path: /data/redis
        readOnly: false

  containers:
  - name: redis
    volumeMounts:
    - mountPath: /data
      name: redisdata

Persistent Volume(PV)方式

PV方式实现原理如下:

  1. 定义存储卷PV:一个PV对象相当于一个指定存储容量的存储卷(如一块1T的NFS网络存储,通过PV对象可以定义NFS存储的IP地址,映射地址、提供的存储容量等)。PV做为存储资源,主要包括存储容量、访问模式、存储类别(storageClassName)、回收策略、后端存储类型等与存储设备相关的配置。
  2. 由业务用户(pod开发者)通过创建PVC对象来申请满足条件的PV。PVC由是用户根据业务的存储需求对存储资源(即PV)的一个“申请”,主要包括请求的存储空间大小、存储类别(storageClassName)等信息,k8s会自动从集群管理员已提前创建好的PV(手动创建PV方式)的PV中匹配合适的PV绑定到该PVC上,或自动(自动创建PV方式)创建满足条件的PV)。
  3. 将PVC绑定到pod并挂载到pod上的容器。

手动创建PV

在上述第1步,需要集群管理员手动方式预创建好一批PV:先由集群管理员根据配置的各类存储(如NFS、glusterFS),并结合k8s上部署的各类业务的存储场景,提前手工创建一系列对应不同存储类型、不同容量大小和访问模式的PV,一个PV对象相当于一个指定大小的存储卷。

PV手动创建的问题:
在一个大规模的Kubernetes集群里,可能有成千上万个PVC,这就意味着运维人员必须事先手工创建出这么多个PV,此外,随着项目的需要,会有新的PVC不断被提交,那么运维人员就需要不断的添加新的,满足要求的PV,否则新的Pod就会因为PVC绑定不到PV而导致创建失败。而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求。

而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等。

自动创建PV

为了解决PV手动创建的问题,Kubernetes 引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。

自动创建PV方式只需要步骤2和步骤3即可,不需要第1步,因为k8s会自动根据PVC的要求创建PV。其实现原理见下一节描述。

PV方式举例,实施步骤如下:

1. 定义存储卷PV(自动挂载不需要这一步,PV是由k8s自动创建,但涉及的PV的概念、PV的配置信息都相同):

PV是对底层网络共享存储的抽象,将共享存储定义为一种“资源”,好比Node也是容器应用能够消费的资源。PV由管理员建立和配置,与共享存储的具体实现直接相关。
PV做为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。集群管理员可以为不同存储卷(如nfs、glusterFS)在k8s上创建多个pv(每一种存储卷可以创建多个PV)。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-1g-pv

spec:
  storageClassName: nfs //存储类别
  accessModes:  #访问模式
    - ReadWriteMany

  persistentVolumeReclaimPolicy: Recycle  #回收策略
  capacity: #存储容量
    storage: 1Gi

  nfs:   #具体存储卷的配置信息
    path: /root/zwf/share
    server: 10.64.2.153

kubernetes支持以下PV类型:

  • AWSElasticBlockStore:AWS公有云提供的ElasticBlockStore。bash
  • AzureFile:Azure公有云提供的File。网络
  • AzureDisk:Azure公有云提供的Disk。架构
  • CephFS:一种开源共享存储系统。socket
  • FC(Fibre Channel):光纤存储设备。
  • FlexVolume:一种插件式的存储机制。
  • Flocker:一种开源共享存储系统。
  • GCEPersistentDisk:GCE公有云提供的PersistentDisk。
  • Glusterfs:一种开源共享存储系统。
  • HostPath:宿主机目录,仅用于单机测试。
  • iSCSI:iSCSI存储设备。
  • Local:本地存储设备,目前能够经过指定块(Block)设备提供Local PV,或经过社区开发的sig-storage-local-static-provisioner插件( https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner )来管理Local PV的生命周期。
  • NFS:网络文件系统。
  • Portworx Volumes:Portworx提供的存储服务。
  • Quobyte Volumes:Quobyte提供的存储服务。
  • RBD(Ceph Block Device):Ceph块存储。
  • ScaleIO Volumes:DellEMC的存储设备。
  • StorageOS:StorageOS提供的存储服务。
  • VsphereVolume:VMWare提供的存储系统。

访问模式(Access Modes): 用于描述应用对存储资源的访问权限,包括

  • ReadWriteOnce(RWO):读写权限,而且只能被单个Node挂载。
  • ReadWriteMany(RWX):读写权限,容许被多个Node挂载。
  • ReadOnlyMany(ROX):只读权限,容许被多个Node挂载。

PV生命周期:

  • Available:可用状态,还未与某个PVC绑定。
  • Bound:已与某个PVC绑定。
  • Released:绑定的PVC已经删除,资源已释放,但没有被集群回收。
  • Failed:自动资源回收失败。

回收策略:

  • Retain:默认,删除pv后,挂载卷的数据会保留。可以通过kubectl get pv看到
  • Recycle:删除卷的内容并使PV可再次被PVC使用。通过这种方式,PV可以被不同的PVC和pod反复使用。但是删除pv以后,挂载卷的数据会被删除掉。
  • Delete:删除底层存储

2. 业务用户创建PVC

PVC由业务用户根据业务需求进行创建,是用户对存储资源的一个“申请”,主要包括请求的存储空间大小、访问模式、PV选择条件、存储类别(storageClassName)等信息的设置。

就像Pod消费Node资源同样,PVC可以消费PV资源。k8s根据PVC中的条件(StorageClass、访问模式等)查找(若PV已创建)满足条件的PV或创建(若PV是自动创建)合适的PV绑定到该PVC上。

PVC与PV一一对应。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-static-pvc

spec:
  storageClassName: nfs  #存储类别
  accessModes: #访问模式
    - ReadWriteMany

  resources:
    requests:
      storage: 1Gi

3. 将PVC绑定到pod

在pod.spec.volumes中将pvc绑定到pod中,然后挂载到pod的容器中。

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      labels:
        app: nfs-pvc-demo
    spec:
      volumes:
      - name: nfs-pvc-volume
        persistentVolumeClaim:
          claimName: nfs-pvc

      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: nfs-pvc-volume
          mountPath: /usr/share/nginx/html/static

参见:k8s中PV、PVC、StorageClass的简单理解_可乐多点冰的博客-CSDN博客_k8s pv

PV自动创建实现原理

k8内置(也可以使用第三方)了存储卷插件 volume plugin 即PV制备器(provisioner),由PV制备器根据PVC的条件,自动在目标存储(如NFS存储、GlusterFS)上为其创建满足条件的、大小与PVC相匹配的PV。

PV制备器只是连接目标存储执行PV创建的可执行程序,具体要操作哪一个网络存储设备(如IP地址)、相关配置参数(如映射路径、回收策略等),则需要由StorageClass来配置。

StorageClass指定了操作的PV制备器及相关配置参数,是创建PV 的模板

apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
    name: glusterfs
provisioner: kubernetes.io/glusterfs  #指定存储插件PV制备器
allowVolumeExpansion: true
parameters://连接参数
    resturl: "http://10.111.209.188:18080"
    clusterid: "6fd6bf78b84315e12abcf8b6db6b1a40"
    restauthenabled: "true"
    restuser: "admin"

每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须指定。

业务用户根据业务需要创建PVC,声明希望申请的存储空间大小(resources)以及基于哪个StorageClass(通过storageClassName参数指定,早期版本通过volume.beta.kubernetes.io/storage-class参数指定)来创建PV。

k8s会根据PVC查找StorageClass,然后结合PVC和StorageClass,调用PV制备器,由PV制备器来完成PV的创建以及与PVC的绑定工作。

在这里插入图片描述

StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。

管理员可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类。

参见:K8S 快速入门(十六)实战篇:StorageClass(存储类)_豪犬的博客-CSDN博客_storageclass

以下参见官网:Dynamic Volume Provisioning | Kubernetes

Dynamic Volume Provisioning

Dynamic volume provisioning allows storage volumes to be created on-demand. Without dynamic provisioning, cluster administrators have to manually make calls to their cloud or storage provider to create new storage volumes, and then create PersistentVolume objects to represent them in Kubernetes. The dynamic provisioning feature eliminates the need for cluster administrators to pre-provision storage. Instead, it automatically provisions storage when it is requested by users.

Background

The implementation of dynamic volume provisioning is based on the API object StorageClass from the API group storage.k8s.io. A cluster administrator can define as many StorageClass objects as needed, each specifying a volume plugin (aka provisioner) that provisions a volume and the set of parameters to pass to that provisioner when provisioning. A cluster administrator can define and expose multiple flavors of storage (from the same or different storage systems) within a cluster, each with a custom set of parameters. This design also ensures that end users don't have to worry about the complexity and nuances of how storage is provisioned, but still have the ability to select from multiple storage options.

More information on storage classes can be found here.

Enabling Dynamic Provisioning

To enable dynamic provisioning, a cluster administrator needs to pre-create one or more StorageClass objects for users. StorageClass objects define which provisioner should be used and what parameters should be passed to that provisioner when dynamic provisioning is invoked. The name of a StorageClass object must be a valid DNS subdomain name.

参考:

k8s volume存储卷、PV、PVC和存储类_TimeRovers的博客-CSDN博客_pvc存储卷

k8s之PV、PVC和StorageClass_Crazy灬峰少的博客-CSDN博客_k8s pvc storageclass

k8s 网络持久化存储之StorageClass(如何一步步实现动态持久化存储) - 渡边灬 - 博客园

k8s存储卷_林凡修的博客-CSDN博客_k8s存储卷

安全类对象

Secret

secret定义了在etcd中保存的一些保密信息,可以是用户名密码,也可以是秘钥

 一个Secret对象的内容包含namespace、token、ca.crt三部分。

k8s支持的用户类型

各类资源都是一个个对象,访问(一般通过API Server)需要认证和授权。

api server是集群的入口,对于kunbernetes的api server 是肯定不能随便访问。所以必须需要一些认证信息。

用户访问集群(例如使用kubectl命令)时,apiserver 会将您认证为一个特定的 User Account(目前通常是admin,除非您的系统管理员自定义了集群配置)。
Pod 容器中的进程也可以与 apiserver 联系。 当它们在联系 apiserver 的时候,它们会被认证为一个特定的 Service Account

因此,k8s有两类用户:

  1. useraccount(用户账户):使用这类账户的是人。典型的是命令行工具kubectl、kubeadm、kubelet等
  2. 服务用户(ServiceAccout):运行在pod里面的服务(应用,即进程)访问API-Server时使用的用户。Service Account则属于某个具体的Namespace。使用这类账户的是访问API-Server的程序。

ServiceAccout

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

  • User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
  • User account是跨namespace的,而service account则是仅局限它所在的namespace;
  • 名为ServiceAccount的准入控制器实现了服务账户的自动化,它会为每个名称空间自动生成一个名称为default的默认资源对象

    k8s会在每个namespace中自动创建一个名为default的service account
  • Token controller检测service account的创建,并为它们创建secret

ServiceAccount结构

apiVersion: v1
kind: ServiceAccount
metadata:
  name <string>   #资源名称
  namespace <string>     #所属名称空间
autoMountServiceAccountToken <boolean>     #是否让POD自动挂载API令牌
secrets: <[]Object>    #以该SA运行的POD要使用的secret对象所组成的列表
  apiVersion:  <string>  #Secret对象所属的API群组和版本,可以省略
  kind: <string>    #资源类型,secret,可省略
  name: <string>    #引用的secret对象名称
  namespace: <string>  #secrets所属的名称空间
  uid: <string>    #secret对象标识符
imagePullSecrets <[]object>:  #引用用于下载容器镜像的Secret对象列表,用于pod在拉取容器镜像时,提前完成与镜像仓库的身份认证
  name <string>   #
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test
  namespace: default
autoMountServiceAccountToken: true 

可以看出一个ServiceAccount可包含两部分:

(1)名为Tokens(上面ServiceAccount没有看到Tokens定义,而是secrets,莫非是新老版本语法问题?)的Secret用于访问API Server的Secret,也被称为Service Account Secret。

(2)名为imagePullSecrets的Secret用于下载容器镜像时的认证过程,通常镜像库运行在Insecure模式下,所以这个为空

(3)用户自定义的其他Secret,用于用户的进程。

如果一个Pod在定义时没有指定spec.serviceAccountName属性,则会默认赋值为default,可进行如下指定:

创建ServiceAccout

查看创建的Service Account:

Service Account准入控制器

针对Pod新增或修改的请求,Service Account准入控制器会验证Pod里的Service Account是否合法:

(1)如果spec.serviceAccount域没有被设置,则Kubernetes默认为其指定名称为default的Service Account。

apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
  - name: podtest
    image: nginx
  serviceAccountName: myServiceAccount

(2)如果指定了spec.serviceAccountName并且不是default,如果此Service Account不存在,则该Pod操作失败。

(3)如果在Pod中没有指定ImagePullSecrets,那么这个spec.serviceAccount域指定的Service Account的ImagePullSecrets会自动加入到该Pod中。

(4)给Pod添加一个特殊的Volume,在该Volume中包含ServiceAccount Secret中的Token,并将Volume挂载到Pod中所有容器的指定目录下(/var/run/secrets/kubernetes.io/serviceaccount),该目录下的内容即为展开的一个Secret(一个Secret包含namespace、ca.crt、tocken这三个部分,参见Secret章节)。

 其中:

  • token文件是由Kubernetes Controller进程用API Server的私钥(--service-account-private-zkey-file指定的私钥)签名指定生成的一个JWT Secret
  • ca.crt:用于在pod与API server交互时,使用该文件验证API Server的服务器证书是否是由所在集群kubernetes-ca签发
  • namespace文件z作用?用于描述该Secret所属的命名空间?

ServiceAcount访问API Server认证过程

为了确保k8s集群的安全,API Server都会对客户端进行安全认证。在Pod中访问API Server服务时,是以Service方式访问名为Kubernetes这个服务的,是以类似HTTP Token的新认证方式:Service Account Auth,Pod在调用API Server时,在Http Header中传递了一个Token字符串,类似于之前提到的Http Token认证方式,有以下几处不同:

(1)Token内容来自Pod前述/var/run/secrets/kubernetes.io/serviceaccount路径下的token文件,由Kubernetes Controller进程用API Server的私钥(--service-account-private-zkey-file指定的私钥)签名指定生成的一个JWT Secret。

(2)通过HTTPS方式与API Server建立连接后,会用Pod里/var/run/secrets/kubernetes.io/serviceaccount/ca.crt 验证API Server发来的证书,验证是否为CA证书签名的合法证书。

(3)API Server收到Token后,采用自身私钥(service-accountkey-file指定,如果没有指定,则默认采用tls-private-key-file指定的参数)对Token进行合法性验证。

上面的认证过程中所涉及的Pod中的以下三个文件:token、ca.crt、namespace,三个文件都在/run/secrets/kubernetes.io/serviceaccount目录下

自定义具备cluster-admin角色的ServiceAccount并绑定到pod

默认的default service account 仅只能获取当前Pod自身的相关属性,无法观察到其他名称空间Pod的相关属性信息。如果想要扩展Pod,假设有一个Pod需要用于管理其他Pod或者是其他资源对象,是无法通过自身的名称空间的default serviceaccount进行获取其他Pod的相关属性信息的,此时就需要进行手动创建一个serviceaccount,并在创建Pod时进行定义。

1. 创建名为admin的ServiceAccount :

2. 将ServiceAccount 赋予cluster-admin角色

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard-admin
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system

3. 创建Pod,声明使用ServiceAcount admin,该pod就具备了cluster-admin权限。

参见:

k8s认证及ServiceAccount-十五 - 走看看

k8s之ServiceAccount_上古伪神的博客-CSDN博客_serviceaccount



角色权限相关对象

局限于某个命名空间的角色及将角色赋予用户(组)由 Role和 RoleBinding对象定义,作用于整个 Kubernetes 集群范围内的角色及将角色赋予用户(组)则通过 ClusterRole 和ClusterRoleBinding对象定义

Subjects

Subjects表示要授权的目标主体,可以是用户、用户组或Servcie Acount。

Role/RoleBinding

RoleBinding(角色绑定)把角色Role的权限映射到用户或者用户组,从而让用户继承角色Role在namespace中的权限。RoleBinding也可以引用ClusterRole,对属于同一命名空间内ClusterRole定义的资源主体进行授权。

ClusterRole/ClusterRoleBinding

《蹲坑学K8S》之22-2:Kubernetes授权机制

K8s中ServiceAccount、Role、RoleBinding、ClusterRole、ClusterRoleBinding之间的关系_-小末的博客-CSDN博客_rolebinding

k8s内置角色


k8s 内置cluster role(集群角色) cluster-admin、admin、 edit、 view的作用范围及区别_51CTO博客_k8s cluster api

NetworkPolicy

NetworkPolicy用于设定pod之间、Pod 与其他网络端点之间的网络安全规则。

在安全领域,除了以上针对API Server访问安全相关的资源对象,还有一种特殊的资源对象NetworkPolicy (网络策略),它是网络安全相关的资源对象,用于解决用户应用之间的网络隔离和授权问题。 NetworkPolicy是一种关于 Pod 间相互通信,以及Pod与其他网络端点间相互通信的安全规则设定。

NetworkPolicy资源使用标签选择Pod,并定义选定Pod 所允许的通信规则。在默认情况下, Pod 间及 Pod 与其他网络端点间的访问是没有限制的,这假设了k8s集群被一个厂商(公司/租户)独占,其中部署的应用都是相互可信的,无须相互防范。但是,如果存在多个厂商共同使用一个k8s 集群的情况,则特别是在公有云环境中,不同厂商的应用要相互隔离以增加安全性,这就可以通过 NetworkPolicy 来实现了。

kublet命令

kubectl create/ apply -f mysql-dep loy.yarnl
kubectl get deploy/deployments/pods/nodes/endpoints/replicaset/secrets/cm(controller manager)/
kubectl get svc mysql
 
kubectl 如果不加--na mes pace 参数,则 kub ec tl get   命令将仅显示属 default 命名空间的资源对像。
可以在 ub ct get 命令中加入--na mes pace 参数来操作某个命名空 间中的对象:
kubectl get nodes  --na mes pace cubectl-system
可通过--all- name spaces参数查看所有命名空间中的对象。
kubeclt get命令通过-o yaml,可以查看对应对象的yaml定义,如: kubectl get svc tomcat-service -o yaml
kubectl describe node k8s-node-l
kubectl describe serviceaccounts serviceaccountName

 kubectl create serviceaccount admin  #创建一个名为admin的sa

 kubectl describe sa admin 
 kubectl explain sa

 kubectl config view

问题

  1. Kubernetes Operator如何实现,各自产品是否已包含对应的Operator?
  2. 如何定义StatefulSet
  3. Job结合两个参数的业务举例?CronJob举例。
  4. ReplicationController ReplicaSet Deployment三者的联系与区别

    K8S Pod控制器:ReplicationController ReplicaSet Deployment三者的联系与区别_学亮编程手记的博客-CSDN博客
  5. 利用StorageClass如何实现快速存储、慢速存储的分组和查找。
  6. 准入控制器作用?

如何部署一个服务

部署一个服务需要创建pod、Deployment、Service对象,实际只需要两步:
1. 创建服务的Deployment,Deployment通过template包含了pod的定义,pod的定义包括选择的容器定义(包括镜像、容器端口、环境变量传入等))。通过Deployment定义一组pod负载,用于批量部署一组相同的pod(或负载Endpoints),同时也定义了负载副本数。

2.创建mysql服务(Service,p10) ,Service为1定义的一组负载pod提供在集群内(p10)或集群外(p12 type:NodePort)访问的统一的访问入口(通过service名称或vip:vport访问)和负载均衡能力。Service也通过pod的标签选择后端的负载pod

术语

  • 容器运行时 (Container Runtime Interface, CRI) :如Docker、Containerd、CRI-O、frakti。
    每个容器运行时都有特点,因此不少用户希望 Kubernetes 能够支持更多的容器运行时,
    Kubernetes 从1.5 版本开始引入了 CRI 接口规范,通过插件接口模式, Kubernetes无
    须重新编译就可以使用更多的容器运行时。CRI 包含 Protocol Buffers、gRPC API 、运行库支持及开发中的标准规范和工具。Docker CRI 实现在 Kubernetes 1.6 中被更新为 Beta 版本,并在 kubelet 启动时默认启动。
  • CNI(Container Network Interface, ):网络插件,如Calico

Logo

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

更多推荐