K8S自学笔记

概念

什么是K8S

Kubernetes,读音库伯耐踢死,简称K8s,是一个最初由Google开发的,用于自动化部署、扩展和管理容器化应用的开源容器编排器技术。

K8s使部署和管理微服务架构应用程序变得很简单。它通过在集群之上形成一个抽象层来实现这一点,允许开发团队平滑地部署应用程序,而 K8s主要处理以下任务:

控制和管理应用程序对资源的使用

自动负载均衡应用程序的多个实例之间请求

监控资源使用和资源限制,为了可以自动阻止应用消耗过多的资源并且可以再次恢复它们

如果主机资源耗尽或主机死机,将应用程序实例从一台主机迁移到另一台主机是一个可行的选项

当有新的主机加入集群时,新增加的额外资源可以被自动使用

竞品:Docker Swarm和Apache Mesos

什么是容器引擎

容器引擎允许你绑定和运行一个应用在一个容器里,这是一个松散隔离的环境。由于隔离性和安全性,你可以在一台主机上操作多个容器。容器引擎利用了操作系统的内核资源隔离特性,可以在同一个操作系统上运行多个容器。人们通常把容器引擎比作虚拟机(VMs)Docker就是一个容器引擎。

image.png

什么是容器

一个容器镜像是一个可运行的软件包,其中包含了一个完整的可执行程序,包括代码和运行时需要应用、系统库和全部重要设置的默认值。Docker运行后的实例,就是容器。

什么是容器编排

容器编排与容器的生命周期管理相关,特别是在大型动态环境中。软件团队用容器编排器来控制和自动化容器管理的各种任务。

容器编排器可以工作在使用容器的任何环境。它可以帮助你在多个环境中部署相同的程序,而不需要重新编写它。K8S就是容器编排工具。

K8s有两层:主节点( Master )和工作节点(Node)。

MasterK8S集群中的控制节点,负责整个集群的管理和控制,可以做成高可用,防止一台Master不可用。

Node会被Master分配一些工作,当某个Node不可用时,会将工作负载转移到其他Node节点上。

image.png

主节点

控制平面

控制平面是管理员和用户管理不同节点的地方。它通过HTTP调用接收命令或者连接到系统并且运行命令行脚本。顾名思义,它控制了K8s与应用程序的交互方式。

API 服务器

API 服务器为K8s集群提供了一个REST接口。 所有在pod上激活的服务和别的对象都是可以用可编程的方式与与终端进行交互。

调度器

调度器负责将任务分配给各个节点。它监控资源容量并保证工作节点的性能保持在可接受的范围内。

控制器管理器

K8s控制器管理器是管理K8s核心控制循环的服务。它负责确保集群的共享状态正常运行。

Etcd

K8s使用了Etcd,一个提供分布式键值存储的数据库,用来共享集群的整体状态的信息。

image.png

工作节点

节点

节点是运行了pod的物理机或虚拟机。控制平面管理集群中的每个节点,该节点包含运行 pod所需的服务。

Pod

K8s pod K8s管理容器集的最小单位。 每个pod有一个分配给pod中的所有容器的单独的IP 地址。在pod中的容器内存和存储资源是共享的。当应用程序只有一个进程时,pod 也可以有一个容器。

Kubelet

Kubelet是一个工作节点组件。它的任务是跟踪pod及其容器的运行状态。它与podYAML JSON描述文件相关。Kubelet检查 pod 规格并确定 pod 是否健康。

Kube代理

Kube代理是一个网络代理和负载均衡器,充当每个节点和API服务器之间的连接。它在集群中的每个节点上运行,并允许你从内部和外部连接到pod

Kubectl

KubectlK8s的命令行工具。它用于部署应用程序、监控和控制集群资源以及查看日志。

从用户的角度来看,Kubectl是你的K8s的控制面板。它使你能够执行所有K8s操作。从技术角度来看,Kubectl是K8s API的客户端。

image.png

配置和使用

POD

概述

一个由多个进程组成的应用程序往往是需要被运行在同一个台机器上。每个容器都非常像一台独立的机器,所以我们自然而然的就会认为,在单个容器中运行多个进程是合乎逻辑的。然而,在实践中这种做法并不合理。

一个容器中运行一个进程。因为一个容器中运行一个进程会让水平扩缩容变的简单。举个例子:我们将一个前端服务和一个后端服务同时部署在同一个容器中,这时由于请求负载过大,我们只需要对后端服务进行扩容,由于前后端服务部署在同一个容器中,这就让我们没办法去为一个单独容器(或者Pod)进行扩容,这就让扩缩容的过程变得非常复杂。一个容器中运行一个进程,这样才能够最好地应用容器编排来管理好容器和服务。因此建议一个容器中只运行一个进程。

由于不能将多个进程聚集在一个单独的容器中,所以就需要一种更高级的结构将容器绑定在一起,并将她们作为一个单元进行管理,这就产生了Pod。在一个Pod中,我们可以同时运行一些密切相关的进程,并为他们提供相同的环境,这时这些进程就好像全部运行于单个容器中一样,同时又保持着一定的隔离。

但实际操作,一个pod内如果是多容器,那么这几个容器必须是共生状态的,否则宁愿一个pod运行一个容器。

image.png

创建

apiVersion: v1 ### 描述文件遵循v1版本的kubernetes API 
kind: Pod ### 表示资源类型 
metadata: 
name: test-pod ### pod的名称 
spec: 
containers: 
- name: zaq-container ### 容器的名称 
image: nginx ### 创建容器所用的镜像 
ports: 
- containerPort: 80 ### 应用监听的端口 
protocol: TCP

通过kubectl apply -f mypod.yaml即可部署这个Pod

这个文件表达的含义是:该文件遵循kubernetes APIv1版本,描述的资源类型是Pod类型,名称为test-pod,该Pod由基于nginx镜像的单个容器组成,该容器的名称为zaq-containers,他正在监听80端口。

K8s的所有资源都可以通过一个Yaml文件来进行描述

获取所有的Podkubectl get pod -A

查看Pod的完整定义:kubectl get pod test-pod -o yaml

查看Pod的日志:kubectl logs test-pod

查看Pod内容器日志:kubectl logs test-pod -c zaq-containers

标签

Pod越来越多时,Pod的管理会变得很难,这就需要标签。

标签不仅可以组织Pod,还能组织Kubernetes中的其他资源。他的主要功能就是为资源进行分组,方便管理。

这是从两位维度上为他们分组:一个是按服务来分,一个是按环境来分。分别为各个Pod上打了两个标签:app和rel。

image.png

POD标签yaml

apiVersion: v1   ### 描述文件遵循v1版本的kubernetes API
kind: Pod		### 表示资源类型
metadata:
  name: test-pod   ### pod的名称
  namespace: default
  labels:
    env: prod        ###为pod指定 env:prod 标签
    app: testapp	 ###为pod指定 app:testapp 标签
spec:
  containers:
  - name: zaq-containers   ### 容器的名称
    image: nginx	### 创建容器所用的镜像
    ports:
    - containerPort: 80   ### 应用监听的端口
      protocol: TCP

探针

K8s中每个容器都可以都有三种探针

启动探针(startupProbe

kubelet使用启动探针,来检测应用是否已经启动完成。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet将杀死容器,而容器依其 重启策略进行重启。

慢容器一定指定启动探针。如果一直检测到未启动,则会一直在等待启动。

启动探针是一个一次性探针。成功以后就不用了,剩下存活探针和就绪探针持续运行

存活探针(livenessProbe

kubelet使用存活探针,来检测容器是否正常运行。(有些容器可能产生死锁应用程序在运行,但是无法继续执行后面的步骤), 如果检测失败,则 kubelet会杀死容器, 并且容器将根据其重启策略决定未来。

对于生产中运行的Pod,一定要定义一个存活探针,如果容器不提供存活探针, 则默认状态为SUCCESS

就绪探针(readinessProbe

kubelet使用就绪探针,来检测容器是否准备好了可以接收客户端的请求(也就是是否能对外提供服务)。当一个Pod内的所有容器都准备好了,才能把这个Pod看作就绪了

如果容器不提供就绪态探针,则默认状态为 Success

与存活探针不同的是,如果就绪探针检测失败,是不会被终止或重新启动的。

检测探针状态,重启容器这项任务是由承载Pod的节点上的Kubelet执行的,在Master节点上的Kubenetes Control Plane组件是不会参与此过程的。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: luksa/kubia-unhealthy    ### 这是一个测试镜像,在发送第六次请求的时候都会返回一个500异常
    livenessProbe:
      httpGet:          ### 一个基于HTTP GET机制的存货探针
        path: /		### HTTP请求的路径
        port: 8080   ### 探针链接的网络端口

Namespace

K8sNamespaceDocker中提到的基于LinuxNamespace实现资源隔离是不一样的。KubernetesNamespace简单地为资源名称提供了一个作用域,实际项目管理中,我们一定不会将所有的资源都放在同一个命名空间中,而是将她们组织到多个命名空间中,这样就可以允许我们在不同的名称空间中多次使用相同的资源名称。

我们可以通过Namespace将一个包含大量组件的复杂系统拆分为多个不同的组,这些组也可以用于在多租户环境中分配资源,将资源分配为生产、开发和QA环境。

apiVersion: v1 
kind: Namespace 
metadata:
name: custom-namespace ### 指定名称空间的名称

通过命令执行kubectl create namespace test-ns

工作负载

什么是工作负载

实际上在开发中我们并不会直接手动的去创建Pod,而是创建一个Deployment这样的工作负载,由他们来创建并管理实际的Pod。

常用的工作负载

Deployment:动态部署Pod,用于无状态、常规、频繁变更的应用

StatefulSet:用于有状态、分布式应用,比如有主从关系、主备关系的Pod

DaemonSet:在每个节点上部署一个Pod,一般用于日志收集、监控守护进程等。

Job创建一个或多个 Pod,并确保指定数量的 Pod 可以成功执行到进程正常结束,之后删除Pod

CronJob:按照预定的时间计划(schedule)创建 Job,每次执行时创建Pod,执行完成后删除Pod。

Deployment

概述

为什么要用Deployment来管理Pod呢,直接创建Pod不行吗?

通过Deployment管理的Pod具有自愈能力、动态扩缩容能力、滚动升级能力。

自愈能力:只要由Deployment管理的Pod内的容器出现了异常,那么他会重启这个容器,而如果是Pod被删除了,那么他会重新拉起一个Pod

滚动升级:不停机进行新包热部署。当Deployment中定义的Pod模板(即 .spec.template)发生改变时,那么Deployment会使用更新后的Pod模板来创建新的实例,同时会删除旧的Pod

支持动态扩容HPA、蓝绿部署(同时存在蓝绿2个版本代码,经过反复测试可以随意切换环境对应的代码版本本)、金丝雀部署(同时存在V1和V2两个版本,新版本V2由最初的少量交易到后面慢慢增加V2交易减少V1交易,达到版本的逐步变更)。

蓝绿部署

image.png

金丝雀部署

image.png

创建

apiVersion: apps/v1
kind: Deployment
metadata:
  name:  dep-v2  ### 遵循域名编写规范
  namespace: default
  labels:
    app: test-01
### 期望状态
spec:
  replicas: 5   ### 期望副本你数量
  selector:   ### 选择器,指定Deployment要控制的所有的Pod的共同标签(即帮助Deployment筛选他要控制哪些Pod)
    matchLabels:
      pod-name: ppp    ### 和模板template里面的Pod的标签必须一样
  ### 编写Pod
  template:
    metadata:    ### Pod的metadata
      labels:
        pod-name: ppp
    spec:
      containers:
      - name: nginx-01
        image: nginx

部署:kubectl apply -f dep-v2.yaml –record

ReplicaSet

创建一个Deployment会产生三个资源:Deployment资源、ReplicaSet资源(RS只提供了副本数量的控制功能)、Pod资源。

Deployment不直接管理Pod,而是间接的通过ReplicaSet来管理Pod

他们之间的关系是:Deployment控制RSRS创建和管理Pod

Deployment怎么关联Pod

通过标签选择器来选择具有特定标签的Pod

image.png

升级策略

Deployment的升级策略有两种

滚动更新(RollingUpdate),这是默认的升级策略,逐渐地删除旧的Pod,与此同时创建新的Pod,使应用程序在整个升级过程中都处于可用状态,并确保其处理请求的能力没有因为升级而有所影响。

重新创建(Recreate),会一次性删除所有旧版本的Pod,之后才开始创建新的Pod。如果你的应用程序不支持多个版本同时对外提供服务,需要在启动新版本之前完全停用旧版本,那么需要使用这种策略。但是使用这种策略的话,会导致应用程序出现短暂的不可用。

image.png

Deployment更新图

image.png

类比weblogic

image.png

动态扩容(HPA)

通过Deployment可以对Pod副本数进行扩缩容,但是这毕竟还是需要人为检测我们部署的服务的压力状况,然后去手动调整Pod的副本数量。在Kubernetes中,有一种感知能力,可以在请求高峰期的时候动态扩容Pod的数量,在高峰期过去后动态缩容。完全不需要人为干预。

想要实现动态扩缩容需要先准备一个Metrics服务器,这个服务器可以监控当前系统的指标。

image.png

StatefulSet

概述

有状态的应用、分布式应用,它的多个实例之间,往往有依赖关系,比如:主从关系、主备关系。
还有就是数据存储类应用,它的多个实例,往往都会在本地磁盘上保存一份数据。而这些实例一旦被杀掉,即便重建出来,实例与数据之间的对应关系也已经丢失,从而导致应用失败。

这些实例不适合使用Deployment来创建实例,而是使用StatefulSet

1拓扑状态
应用的多个实例之间不是完全对等的关系。这些应用实例,必须按照某些顺序启动,删除重建也要是相同的顺序。并且,新创建出来的
Pod,必须和原来Pod的网络标识一样,这样原先的访问者才能使用同样的方法,访问到这个新 Pod

2 存储状态
应用的多个实例分别绑定了不同的存储数据。对于这些应用实例来说,
Pod A 第一次读取到的数据,和隔了十分钟之后再次读取到的数据,应该是同一份,哪怕在此期间 Pod A 被重新创建过。

StatefulSet的核心功能,就是通过某种方式记录这些状态,然后在 Pod 被重新创建时,能够为新Pod 恢复这些状态。

创建

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx" #重点关注,对应的headless service
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web

升级策略

RollingUpdateStatefulSet Controller会删除并创建StatefulSet相关的每个Pod对象,与Deployment的滚动更新不同,StatefulSet是顺序滚动。其处理顺序与StatefulSet终止Pod的顺序一致,即从序号最大的Pod开始重建,每次更新一个Pod。注意,如果StatefulSetPod Management Policy被设置为OrderedReady,则可能在更新过程中发生一些意外,从而导致StatefulSet陷入奔溃状态,此时需要用户手动修复。

OnDelete,StatefulSet Controller并不会自动更新StatefulSet中的Pod实例,而是需要用户手动删除这些Pod并触发StatefulSet Controller创建新的Pod实例来弥补,因此这其实是一种手动升级模式。

Partitioned:特殊的分区升级策略(Partitioned),在这种模式下,用户指定一个序号,StatefulSet中序号大于等于此序号的Pod实例会全部被升级,小于此序号的Pod实例则保留旧版本不变,即使这些Pod被删除、重建,也仍然保持原来的旧版本。这种分区升级策略通常用于按计划分步骤的系统升级过程中。

StatefulSet更新图

image.png

DaemonSet

在每个节点上运行集群的存储守护进程,例如 glusterdceph

在每个节点上运行日志收集守护进程,例如 fluentdlogstash

在每个节点上运行监控守护进程,例如 Prometheus Node Exporter、Sysdig Agent、collectd、Dynatrace OneAgent、APPDynamics Agent、Datadog agent、New Relic agent、Ganglia gmond、Instana Agent 等有新节点加入时会自动创建对应Pod实例

image.png

Service

概述

就微服务而言,部署一个微服务肯定会产生很多个Pod,不仅集群内的这些Pod之间需要进行相互通信,而且还要对集群外部的客户端的HTTP请求做出响应。

Pod需要一种寻找其他Pod的方法来使用其他Pod提供的服务,在传统的世界,系统管理员要在用户端配置文件中明确指出服务的精确的IP地址或者主机名来配置每个客户端应用,但是同样的方式在Kubernetes中并不适用,因为:

1.KubernetesPod启动时会给已经调度到节点上的Pod分配IP地址,因此客户端不能提前知道提供服务的PodIP地址

2.Pod是短暂的,他们随时都可能会杀死,然后重启,因此每个PodIP是不固定的。

3.水平伸缩意味着多个Pod可能会提供相同的服务,每个Pod都有自己的IP地址,但是客户端只想通过一个IP来访问到这些Pod

为了解决这一问题(Pod的IP不固定、相同Pod的IP不唯一,无法提供同一的对外暴露方式),Kubernetes提供了一种资源类型——Service!

Service是一种为一组功能相同的Pod提供单一不变的接入点的资源。当Service存在时,他的IP地址和端口不会改变。客户端通过这个IP+端口建立连接,这些连接会被路由到提供该服务的任意一个Pod上。通过这种方式,客户端不需要知道每个单独的提供服务的Pod的地址。

前面提到过我们可以在Pod上打一个标签,Service就是通过Pod的标签来选择哪些Pod是由他来管理的。当Service接收到一个请求后,他会将请求负载均衡到他所选择的Pod中的任意一个。

image.png

三种模式

ClusterIP(默认): 为当前Service分配或者不分配(headless服务)集群IP,负载均衡一组Pod

他的缺点是只能在集群内进行互相访问(没有指定type时,默认就是ClusterIP类型)

NodePort:外界可以使用 机器IP+暴露的nodePort端口 访问。

nodePort端口由kube-proxy开在机器上的(集群中的每台机器都会开放这个端口!)

机器IP+暴露的NodePort流量会先来到kube-proxy,然后再转到serviceport,再转到Pod中容器的targetPort

LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 负载均衡器可以将流量重定向到跨所有节点的节点端口。客户端通过负载均衡器的IP连接到服务。

headless服务

headless服务和普通Service的区别就是他是一个无头的Service,也就是为这个Service设置clusterIPNode + typeClusterIP的配置,这样创建出来的Service是不会有Service集群IP的。在集群内部,我们仍然可以通过这个ServiceFQDNsystem.ocr.svc.cluster.local)来访问他所管理的Pod,但是如果在集群外部,我们根本没有办法访问这个Service,因为这个Service根本就没有分配任何IP

FQDN:格式:Service_NAME.NameSpace_NAME.Domain.LTD.

Domain.LTD.=svc.cluster.local.

NodePort方式

portservice端口,即k8s中服务之间的访问端口,集群内其他pod访问本pod的端口。图中80就是port

targetPortpod(也就是容器)的端口 。图中8080就是targetport

nodePort是容器所在node节点的端口,即外部机器可访问的端口。(通过nodePort类型的service暴露给集群节点)。图中31666就是nodeport。

创建
apiVersion: v1 
kind: Service 
metadata: 
  name: nginx-service 
spec: 
  type: NodePort      # 有配置NodePort,外部流量可访问k8s中的服务 
  ports: 
  - port: 80       # 服务访问端口 
    targetPort: 8080    # 容器端口 
    nodePort: 31666   # NodePort 
  selector: 
    name: nginx-pod
示意图

image.png

负载均衡

概述

为什么需要Ingress

Service可以使用NodePort暴露集群外访问端口,但是性能低下,不安全

Service只能进行简单的负载均衡,而Ingress可以进行复杂的负载、限流、路径重写、会话保持等各种高级功能。

Ingress 公开了从集群外部到集群内服务的 HTTP HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。

我们可以使用Ingress作为整个集群统一的入口,配置Ingress规则转到对应的Service

在生产环境一般建议将Service设置为headless类型的,然后再通过Ingress去对外暴露他,这样做可以保证后端服务的安全性。

创建

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-ingress
  namespace: default
spec:
  rules:
  - host: xxxx.com    ### 指定监听的主机域名
    http:		### 指定请求的路由规则
      paths:
      - path: /
        pathType: Prefix	### 匹配规则———前缀匹配,由上面的path指定,现在这种就表示只要访问http:// xxxx.com/,请求就会来到这里
        backend:  	### 指定路由的后台服务的Service名
          service:
            name: canary-test  ### kubernetes集群的svc名称
            port:
              number: 80  	### service中指定的port端口号

示意图

image.png

概述

Pod类似于一个逻辑主机,它内部的一组容器是共享一些资源的,比如CPURAM、网络接口等。但是当涉及到文件系统时,各个容器就是隔离的,因为大多数容器的文件系统来自容器镜像,因此默认情况下, 每个容器的文件系统与其他容器完全隔离。

K8s中的Pod是有自愈能力的,一个Pod内的容器是有可能被重新启动的(如果出现了异常)。而在Docker中我们也学的过,容器内的数据都是临时存储的,当容器被删除,它里面的数据也会被删除。那么问题来了,一个运行的容器被重启了,那么重启后产生的新容器中该怎么恢复他原来在旧容器中产生的数据呢?

在Kubernetes中,通过定义存储卷来满足这个需求。

调用图

Pod中存在两个卷:publicHtmllogVol

挂在到Pod中3个容器,每个容器都能共同访问2个卷的内容。

image.png

卷的类型

配置信息(用于将K8s部分资源和集群信息公开给Pod的特殊类型的卷,用来存储配置和密码)
	Secret:对配置信息利用Base64进行编码
	ConfigMap:对配置信息不编码

非持久性存储
	emptyDir:用来存储临时数据的简单空目录
	hostPath:用来将目录从工作节点的文件系统挂载到Pod中

持久性存储
	网络连接性存储
		NAS:iSCSI、ScaleIO Volumes、FC (Fibre Channel)
		NFS:挂载到Pod中的NFS共享卷
	PV、PVC:一种使用预置或者动态配置的持久存储类型。(重点)
	分布式存储
		GlusterFS
		RBD (Ceph Block Device)
		CephFS
	云端存储
	自定义存储

PV和PVC

PVPersistentVolume)和PVCPersistentVolumeClaim

首先由集群管理员创建持久卷PV,在创建时可以指定这个PV的大小和所支持的访问模式。当开发者(集群用户)需要在他的Pod中添加特定的卷时,他们首先需要创建持久卷声明PVC清单,指定所需要的最低容量要求和访问模式,然后这个PVC会交给K8s,K8s将找到可匹配的持久卷并将其绑定到持久卷声明。

image.png

ConfigMap

概述

Docker,有三种方式处理应用程序的配置信息:

一种是通过命令行参数传入应用程序,然后应用程序在进行解析。

由于配置项的逐渐增多,另一种方式是将配置文件化,然后嵌入应用程序本身,这种方式往往需要将配置文件打入容器镜像,亦或是挂载包含该文件的卷。

将配置文件打入容器镜像的方式不可取,因为这种方式每次修改完配置都需要重新打镜像。而且,任何拥有镜像访问权限的人都可以看到配置文件中包含的敏感信息,比如证书和密钥。

通过卷挂载的方式相比更好,但是这种方式需要在容器启动之前将配置文件已经写入相应的卷中。

最后一种是借助环境变量,让应用程序主动查找某一特定环境变量的值,而不是读取配置文件或者解析命令行参数。

比如MySQL官方镜像内部通过环境变量MYSQL_ROOT_PASSWORD设置超级用户root的密码。

在Kubernetes中,有一种专门用来存储配置数据的资源——ConfigMap,他可以很好的解决关于配置文件的问题

环境变量

创建

apiVersion: v1
kind: ConfigMap
metadata:
  name: fortune-config
data:
  INTERVAL: "25“

POD使用

apiVersion: v1
kind: Pod
metadata:
  name: fortune-configmap
spec:
  containers:
  - image: luksa/fortune:env
    name: html-generator
    envFrom:
    - configMapRef:
        name: fortune-config   ### 引用名为fortune-config的ConfigMap

命令行参数

apiVersion: v1
kind: Pod
metadata:
  name: fortune-args-from-configmap
spec:
  containers:
  - image: luksa/fortune:args
    name: html-generator
    env:
    - name: INTERVAL  ### 指定环境变量中的key名
      valueFrom:      ### 这种方式是从ConfigMap中引用单个指定条目的方式,而前面envFrom的方式是从ConfigMap中一次性引用所有条目的方式
        configMapRef:
          name: fortune-config   ### 引用名为fortune-config的ConfigMap
          key: INTERVAL   ### 指定要引用的fortune-config中的条目的key名
     args: ["$(INTERVAL)"]   ### 在参数设置中引用环境变量

使用ConfigMap卷

环境变量或者命令行参数值作为配置值通常适用于变量值较短的场景。但是大多数情况下,配置文件的内容是有很多的,这时我们就可以借助在上一章提到的一种特殊的卷——configMap卷。

configMap卷和ConfigMap不是同一个东西。

configMap卷会将ConfigMap中的每个条目均暴露成一个文件。运行在容器中的应用程序可以读取文件内容来获取对应条目的值。

image.png

Secret

前面通过ConfigMap给容器传递的信息都是一些非敏感数据,因为ConfigMap保存的内容就是普通的明文文本,不会对内容进行编码。但如果我们需要传一些证书或者密钥该怎么办呢?使用Secret就行了!Secret保存的内容是密文,他会对保存的内容通过Base64进行编码。

Secret的结构与ConfigMap类似,均是kv键值对的映射。Secret的使用方法也和ConfigMap相同:

Secret条目作为环境变量传递给容器

Secret条目暴露为卷的文件

apiVersion: v1

kind: Secret

metadata:

name: db-secret  

data:

password: cm9vdA==     ### base64编码了一下

username: MTIzNDU2     ### 用base64编码了一下

架构图

image.png


Deployment和StatefulSet区别


DeDeploymentpymen

StaStatefulSettefulSet

状态

无状态

有状态

名字

名字不固定,会包含随机数

名字固定

部署顺序

无顺序,并行扩缩容

有顺序,串行有序扩缩容

service

有ClusterIP,可以负载均衡

没有ClusterIP,是headlessservice,所以无法负载均衡,返回的都是pod名,所以pod名字必须固定

共享卷

可以共享同一个PVC卷

每个pod必须拥有自己的PVC卷

控制Pod

通过ReplicaSet控制

通过自身StatefulSet Controller控制

使用场景

业务系统

Nacos、redis、Mysql、Oracle


果然做项目才是最好的老师,不去真正的实施相关项目,这么多抽象的概念,理清都很难,更何况了解其逻辑和原理。

{context}