service及工作负载型控制器

servfer与服务发现

Service资源

Service是Kubernetes标准的API资源类型之一
◼ 为动态的Pod资源提供近似静态的流量入口
◆ 服务发现:通过标签选择器筛选同一名称空间下的Pod资源的标签,完成Pod筛选
⚫ 实际上是由与Service同名的Endpoint或EndpointSlice资源及控制器完成
◆ 流量调度:由运行各工作节点的kube-proxy根据配置的模式生成相应的流量调度规则
⚫ iptables
⚫ ipvs
◼ 持续监视着相关Pod资源的变动,并实时反映至相应的流量调度规则之上

动态可配置负载均衡

从Service的视角来看,Kubernetes集群的每个工作节点都是动态可配置的负载均衡器
⚫ 对于隶属某Service的一组Pod资源,该Service资源能够将集群中的每个工作节点配置为该组Pod的负载均衡器
⚫ 客户端可以是来自集群之上的Pod,也可以是集群外部的其它端点
⚫ 对于一个特定的工作节点上的某Service来说,其客户端通常有两类
◆ 该节点之上的进程,可通过该Service的Cluster IP进入
 Service_IP:Service_Port
◆ 该节点之外的端点,可经由该Service的NodePort进入
 Node_IP:Node_Port
显然,若客户端进入的节点,并非目标Pod所在的节点时,报文转发的路径中必然存在跃点

Service类型

Service根据其所支持的客户端接入的方式,可以分为4种类型
⚫ ClusterIP:支持Service_IP:Service_Port接入;
⚫ NodePort:支持Node_IP:Node_Port接入,同时支持ClusterIP;
⚫ LoadBalancer:支持通过外部的LoadBalancer的LB_IP:LB_Port接入,同时支持NodePort和ClusterIP;
◆ Kubernetes集群外部的LoadBalancer负责将接入的流量转发至工作节点上的NodePort
◆ LoadBalancer需与相关的NodePort的Service生命周期联动
 LoadBalancer应该是由软件定义
 Kubernetes需要同LoadBalancer所属的管理API联动
⚫ ExternalName
◆ 负责将集群外部的服务引入到集群中
◆ 需要借助于ClusterDNS上的CNAME资源记录完成
◆ 特殊类型,无需ClusterIP和NodePort
◆ 无须定义标签选择器发现Pod对象

Service及流量转发

创建Service资源

由Service表示的负载均衡器,主要定义如下内容
⚫ 负载均衡器入口:ClusterIP及相关的Service Port、NodePort(每个节点的Node IP都可用)
◆ 根据通信需求,确定选择的类型
⚫ 标签选择器:用于筛选Pod,并基于筛选出的Pod的IP生成后端端点列表(被调度的上游端点)
⚫ Service类型的专有配置

标签:附加在资源对象上的键值型元数据
⚫ 键标识:由“键前缀(可选)”和“键名”组成,格式为“key_prefix/key_name”
◆ 键前缀必须使用DNS域名格式
◆ 键名的命名格式:支持字母、数字、连接号、下划线和点号,且只能以字母或数字开头;最长63个字符;
⚫ “kubectl label”命令可管理对象的标签
标签选择器:基于标签筛选对象的过滤条件,支持两种类型
⚫ 基于等值关系的选择器
◆ 操作符:=或==、!=
⚫ 基于集合关系的选择器
◆ 操作符:in、notin和exists
◆ 使用格式:KEY in (VALUE1, VALUE2, …)、 KEY notin (VALUE1, VALUE2, …)、KEY 和 !KEY

Service资源规范

Kubernetes上标准的API资源类型
apiVersion: v1
kind: Service
metadata:
	name: ...
	namespace: ...
spec:
	type <string> # Service类型,默认为ClusterIP
	selector <map[string]string> # 等值类型的标签选择器,内含“与”逻辑
	ports: # Service的端口对象列表
	- name <string> # 端口名称
	  protocol <string> # 协议,目前仅支持TCP、UDP和SCTP,默认为TCP
	  port <integer> # Service的端口号
	  targetPort <string> # 后端目标进程的端口号或名称,名称需由Pod规范定义
	  nodePort <integer> # 节点端口号,仅适用于NodePort和LoadBalancer类型
clusterIP <string> # Service的集群IP,建议由系统自动分配
externalTrafficPolicy <string> # 外部流量策略处理方式,Local表示由当前节点处理,Cluster表示向集群范围调度
loadBalancerIP <string> # 外部负载均衡器使用的IP地址,仅适用于LoadBlancer
externalName <string> # 外部服务名称,该名称将作为Service的DNS CNAME值
Service资源示例

ClusterIP Service

kind: Service
apiVersion: v1
metadata:
	name: demoapp
spec:
	type: ClusterIP # 类型标识,默认即为ClusterIP;
	selector:
		app: demoapp
	ports:
	- name: http # 端口名称标识
	  protocol: TCP # 协议,支持TCP、UDP和SCTP
	  port: 80 # Service的端口号
	  targetPort: 80 # 目标端口号,即后端端点提供服务的监听端口号

 NodePort Service

kind: Service
apiVersion: v1
metadata:
	name: demoapp
spec:
	type: NodePort # 必须明确给出Service类型
	selector:
		app: demoapp
	ports:
	- name: http
	  protocol: TCP
	  port: 80
	  targetPort: 80
	  nodePort: 30080 # 可选,为避免冲突,建议由系统动态分配
NodePort Service流量策略(1)

流量策略一:Cluster,表示在整个Kubernetes集群范围内调度;
⚫ 该流量策略下,请求报文从某个节点上的NodePort进入,该节点上的Service会将其调度至任何一个可用后端Pod之上,而不关心Pod运行于哪个节点;

NodePort Service流量策略(2)

流量策略二:Local,表示仅将请求调度至当前节点上运行的可用后端端点;
⚫ 该流量策略下,请求报文从某节点NodePort进入后,该节点上的Service仅会将请求调度至当前节点上适配到该Service的后端端点
⚫ 仅应该从运行有目标Service对象后端Pod对象的节点的NodePort发起访问

LoadBalancer类型的Service

在接入外部流量方面,NodePort存在着几个方面的问题
⚫ 非知名端口、私网IP地址、节点故障转移、节点间负载均衡、识别能适配到某Service的Local流量策略的节点等
⚫ 外置的Cloud Load Balancer可以解决以上诸问题

Service名称解析

Service和Cluster DNS

Cluster DNS(CoreDNS)是Kubernetes集群的必备附件,负责为Kubernetes提供名称解析和服务发现
⚫ 每个Service资源对象,在CoreDNS上都会自动生成一个遵循“..svc.”格式的名称
◆ :当前Service对象的名称
◆ :当前Service对象所属的名称空间
◆ :当前Kubernetes集群使用的域名后缀,默认为“cluster.local”
⚫ 围绕该名称会生成一些DNS格式的资源记录
CoreDNS会持续监视API Server上的Service资源对象的变动,并实时反映到相关的DNS资源记录中
Pod中各容器默认会在/etc/resolv.conf中,将nameserver指向CoreDNS相关的Service的ClusterIP
⚫ 由kubelet创建Pod时根据指定的配置自动注入

Service在Cluster DNS上的资源记录

每个Service,在CoreDNS上都会有A/AAAA、SRV和PTR资源记录
⚫ A/AAAA资源记录
◆ ..svc.. IN A
◆ ..svc.. IN AAAA
⚫ 为每个定义了名称的端口生成一个SRV记录,以支持服务发现
....svc.. IN SRV ..svc..
⚫ 为每个A记录(例如a.b.c.d)或AAAA记录生成对应的PTR记录,例如
◆ ....in-addr.arpa. IN PTR ..svc..
◆h4.h3.h2.h1.g4.g3.g2.g1.f4.f3.f2.f1.e4.e3.e2.e1.d4.d3.d2.d1.c4.c3.c2.c1.b4.b3.b2.b1.a4.a3.a2.a1.ip6.arpa IN PTR ..svc..

Pod可基于Service的DNS名称向其发起服务访问请求

Pod上的DNS解析策略

Kubernetes支持在单个Pod资源规范上自定义DNS解析策略和配置,并组合生效
⚫ spec.dnsPolicy:解析策略
⚫ spec.dnsConfig:名称解析机制
DNS解析策略
⚫ Default:从运行在的节点继承DNS名称解析相关的配置
⚫ ClusterFirst:于集群DNS服务上解析集群域内的名称,其他域名的解析则交由从节点继承而来的上游名称服务器
⚫ ClusterFirstWithHostNet:专用于在设置了hostNetwork的Pod对象上使用的ClusterFirst策略
⚫ None:用于忽略Kubernetes集群的默认设定,而仅使用由dnsConfig自定义的配置
DNS解析机制
⚫ nameservers <[]string>:DNS名称服务器列表,附加于由dnsPolicy生成的DNS名称服务器之后
⚫ searches <[]string>:DNS名称解析时的搜索域,附加由于dnsPolicy生成的搜索域之后
⚫ options <[]Object>:DNS解析选项列表,同dnsPolicy生成的解析选项合并成最终生效的定义

Headless Service

Service的各类型中,ClusterIP、NodePort和LoadBalancer都为其Service配置一个ClusterIP,CoreDNS上,这些Service对象的A记录也解析为它的ClusterIP;
广义上,那些没有ClusterIP的Service则称为Headless Service,它们又可以为分两种情形
⚫ 有标签选择器,或者没有标签选择器,但有着与Service对象同名的Endpoint资源
◆ Service的DNS名称直接解析为后端各就绪状态的Pod的IP地址
◆ 调度功能也将由DNS完成
◆ 各Pod IP相关PTR记录将解析至Pod自身的名称,假设Pod IP为a.b.c.d,则其名称为a-b-c-d...svc.
◆ 这种类型也就是狭义上的Headless Service
⚫ 无标签选择器且也没有与Service对象同名的Endpoint资源
◆ Service的DNS名称将会生成一条CNAME记录,对应值由Service对象上的spec.externalName字段指定

示例

External Service示例

kind: Service
apiVersion: v1
metadata:
name: externalname-mageedu
spec:
type: ExternalName
externalName: www.magedu.com
ports:
- protocol: TCP
port: 80
targetPort: 80
selector: {}

 Headless Service示例

kind: Service
apiVersion: v1
metadata:
name: demoapp-headless-svc
spec:
clusterIP: None
selector:
app: demoapp
ports:
- port: 80
targetPort: 80
name: http

Service流量转发简析

Service流量转发机制

ClusterIP类型
⚫ 源自Pod
◆ 没启动masquerade-all:请求报文的目标IP和目标端口由Service转为挑选出的后端Pod的IP和端口,并由后端Pod直接响应给客户端Pod
 发夹问题:Pod访问自身所属的Service后,由Service又调度回该Pod
 存在发夹问题(haripin)的场景中,需要启用源IP地址转换
◆ 启用masquerade-all:请求报文的源IP和目标IP都将由Service进行转换,原IP将转为客户端Pod所在节点在Pod网络中的IP地址
⚫ 源自非Pod网络中的请求流量
◆ 接入流量的节点充当NAT网关,请求报文的源IP和目标IP都将由Service进行转换
NodePort和LoadBalancer类型
⚫ 流量来自集群外部,节点扮演网关的角色,请求报文的源IP和目标IP都将由Service进行转换,原IP将转为客户端Pod所在节点的IP地址,以确保响应报文能正确送达

流量转发示意图:请求报文,目标地址转换都会进行,未启用masquerade-all时,源地址转换将视情况进行
⚫ Pod网络是虚拟网络,最终还是要通过节点网络完成报文传送,因此,SNAT通常会使用节点网络中的地址

应用编排

Kubernetes控制器模式

声明式API
API设计方法
◼ 命令式API
◆ 也称为指令式API,用户需要一步步地告诉机器该如何做(How),机器自身不具有任何“智能”,只被动接受指令
◆ 高度依赖用户自身理解和达成目标的能力和处理各类异常问题的经验,实现的是“命令式编程(ImperativeProgramming)”
◼ 声明式API
◆ 也称为申明式API,用户只需要告诉机器想要的结果(What),机器自身需要确定如何达成该目标
◆ 机器需要一定的“智能”,但通常只能支持事先预设和可被其理解的特定任务
◆ 实现的是“声明式编程(Declarative Programming)”

声明式API和控制器模式

相较于命令式编程,声明式编程是一个更高的层次上的编程
◼ 声明式API允许用户以给出最终期望目标的方式编写代码,但具体的执行过程(即机器智能的那部分代码),最终仍然需要以命令式编程实现,只不过,它们可由不同的人群完成
◼ 类比来说,声明式编程的用户类似于企业的高管,只用关心和交待最终目标;而命令式编程的用户类似于企业部门经理,他需要理解目标的达成路径,并组织人力完成目标
Kubernetes的声明式API
◼ 用户能够以声明式定义资源对象的目标状态(spec)
◼ 由控制器代码(机器智能组件)负责确保实际状态(status)与期望状态一致
◆ 控制器即“部门经理”,负责确保部门内的各项具体任务得以落地
◆ 控制器通常由API的提供者负责编写
◼ 用户需要做的是根据资源类型及其控制器提供的DSL进行声明式编程

声明式API和控制器模式

 控制器模型(控制回路)
◼ 初始,Controller负责根据Input(目标状态)控制System,并生成Output(结果状态)
◼ Feedback根据Output生成Feedback Signal,而后由ErrorDetector基于Feedback Signal和Input来判定是否存在错误,并在有错误时生成Error Signal
◼ Error Signal将驱动Controller生成Actuating Signal,并控制System的行为与Input要求相同
 Kubernetes Controller的控制回路
◼ Controller根据spec,控制System生成Status
◼ Controller借助于Sensor持续监视System的Spec和Status,在每一次控制回路中都会对二者进行比较,并确保System的Status不断逼近或完全等同Status

Kubernetes的控制器

Kubernetes的控制器类型
◼ 打包于Controller Manager中内置提供的控制器,例如Service Controller、Deployment Controller等
◆ 基础型、核心型控制器
◆ 打包运行于kube-controller-manager中
◼ 插件或第三方应用的专用控制器,例如Ingress插件ingress-nginx的Controller,网络插件Project Calico的Controller等
◆ 高级控制器,通常需要借助于基础型控制器完成其功能
◆ 以Pod形式托管运行于Kubernetes之上,而且这些Pod很可能会由内置的控制器所控制
以编排Pod化运行的应用为核心的控制器,通常被统称为工作负载型控制器
◼ 无状态应用编排:ReplicaSet、Deployment
◼ 有状态应用编排:StatefulSet、第三方专用的Operator
◼ 系统级应用:DaemonSet
◼ 作业类应用:Job和CronJob

应用编排

应用编排
定义工作负载型控制器资源对象以编排应用
◼ 内置的各工作负载型控制器都有对应的资源类型,控制器专用于管控其对应类型的资源对象
◆ 例如,Deployment控制器对应有Deployment资源类型
◆ 这些资源类型都是Kubernetes上标准的API资源,并遵循资源规范的通用格式
◼ 用户需要编排某应用时,需要事先确认好应用的运行目标模式,例如实例数据及结束条件等,并根据模式选出对应的工作负载控制器类型
◼ 而后根据相应控制器的资源类型的规范,编写资源配置,并提交给API Server即可
◼ 相应控制器监视到API Server上新建的资源后,即会运行代码确保对象实例的实际状态(Status)与期望状态(Spec)一致
注意:控制器对象仅负责确保API Server上有相应数量的符合标签选择器的Pod对象的定义,至于Pod对象的Status如何与Spec保持一致,则要由相应节点上的kubelet负责保证

Deployment资源及控制器

Deployment控制器简介

负责编排无状态应用的基础控制器是ReplicaSet,相应的资源类型通过三个关键组件定义如何编排一个无状态应用
◼ replicas:期望运行的Pod副本数
◼ selector:标签选择器
◼ podTemplate:Pod模板
Deployment是建立在ReplicaSet控制器上层的更高级的控制器
◼ 借助于ReplicaSet完成无状态应用的基本编排任务
◼ 它位于ReplicaSet更上面一层,基于ReplicaSet提供了滚动更新、回滚等更为强大的应用编排功能
◼ 是ReplicaSet资源的编排工具
◆ Deployment编排ReplicaSet
◆ ReplicaSet编排Pod
◼ 但是,应该直接定义Deployment资源来编排Pod应用,ReplicaSet无须显式给出

ReplicaSet资源示例

apiVersion: apps/v1
kind: ReplicaSet
metadata:
	name: rs-example
spec:
	replicas: 2
	selector:
		matchLabels:
			app: demoapp
			release: stable
		template:
		  metadata:
		  labels:
			app: demoapp
			release: stable
		spec:
		containers:
		- name: demoapp
		  image: ikubernetes/demoapp:v1.0
		  #各Pod的名字以ReplicaSet名称为前缀,后缀随机生成

 Deployment资源示例

apiVersion: apps/v1
kind: Deployment
metadata:
	name: deploy-example
spec:
	replicas: 2
	selector:
		matchLabels:
			app: demoapp
			release: stable
	template:
		metadata:
		labels:
		app: demoapp
		release: stable
	spec:
		containers:
		- name: demoapp
		  image: ikubernetes/demoapp:v1.0
		  
#各Pod的名字以Deployment名称为前缀,中间是Pod模板的hash码,后缀随机生成
#ReplicaSet对象名称以Deployment名称为前缀,后缀是Pod模板的hash码
获取资源状态
获取ReplicaSet资源对象的状态
	~$ kubectl get replicasets/rs-example
	NAME DESIRED CURRENT READY AGE
	rs-example 2 2 2 115s
获取Deployment资源对象的状态
	~$ kubectl get deployment/deploy-example
	NAME READY UP-TO-DATE AVAILABLE AGE
	deploy-example 2/2 2 2 27s
	⚫ Deployment自动创建的ReplicaSet被添加等同于Pod对象的标签
	~$ kubectl get replicasets -l app=demoapp,release=stable
	NAME DESIRED CURRENT READY AGE
	deploy-example-66db74fcfc 2 2 2 6m

#获取ReplicaSet资源对象的状态
DESIRED:期望的Pod数量
CURRENT:当前的Pod数量
READY:就绪状态的Pod数量
AGE:当前资源的创建后生存时长

#获取Deployment资源对象的状态
READY:就绪的Pod数量/期望的Pod数量
UP-TO-DATE:到达期望的版本的Pod数量
AVAILABE:运行中并可用的Pod数量
AGE:当前资源的创建后生存时长
更新策略

Deployment控制器支持两种更新策略
◼ 滚动式更新(rolling updates)
◆ 逐批次更新Pod的方式,支持按百分比或具体的数量定义批次规模,默认策略
◆ 触发条件:podTemplate的hash码变动
⚫ 仅podTemplate的配置变动才会导致hash码改变
⚫ replicas和selector的变更不会导致podTemplate的hash变动
◼ 重建式更新(recreate)
◆ 在Pod资源被删除时,使用新的模板定义被足缺失的Pod数量,完成更新
◆ 触发条件:现有Pod被删除

strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate

触发更新

触发滚动更新
◼ 最为常见的更新需求是应用升级,即镜像文件更新,常用方法
◆ ~$ kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 …
◆ ~$ kubectl patch (-f FILENAME | TYPE NAME) [-p PATCH|–patch-file FILE] [options]
◆ 直接更新原配置文件,而后使用“kubectl apply”命令触发更新
◼ 上面第二和第三种方法可用于模板中任何必要配置的更新
查看更新
◼ 更新状态:kubectl rollout status (TYPE NAME | TYPE/NAME) [flags] [options]
◼ 更新历史:kubectl rollout history (TYPE NAME | TYPE/NAME) [flags] [options]
回滚
◼ 回滚到前一版本: kubectl rollout undo (TYPE NAME | TYPE/NAME)
◼ 回滚到指定版本: kubectl rollout undo (TYPE NAME | TYPE/NAME) --to-revision=X

配置滚动更新策略

Deployment的滚动更新支持使用如下两个字段来配置相关的策略
◼ maxSurge:指定升级期间存在的总Pod对象数量最多可超出期望值的个数,其值可以是0或正整数,也可以是相对于期望值的一个百分比
◼ maxUnavailable:升级期间正常可用的Pod副本数(包括新旧版本)最多不能低于期望值的个数,其值可以是0或正整数,也可以是相对于
期望值的一个百分比,默认值为1

 存在的问题:必须以Pod为原子单位切割规模比例,且无法控制流量路由比例;

扩容和缩容

容量管理类型
◼ 横向伸缩:增加或减少Pod数量
◼ 纵向(垂直)伸缩:调整Pod上的资源需求和资源限制
变动Deployment资源对象中的replicas字段的值即会触发应用规模的扩容或缩容
◼ 扩容和缩容是ReplicaSet的功能,具体操作由ReplicaSet完成
◼ 根据应用规模的需要进行手动配置
操作方法
◼ patch命令
◆ kubectl patch (-f FILENAME | TYPE NAME) [-p PATCH|–patch-file FILE] [options]
◆ 例如:kubectl patch deployment deploy-example -p ‘{“spec”:{“replicas”:3}}’
◼ 直接更新原配置文件,而后使用“kubectl apply”命令触发更新
扩展:自动扩容和缩容
◼ HPA(Horizontal Pod Autoscaler)控制器
◼ VPA(Vertical Pod Autoscaler)控制器

涉及到的命令

[root@master1 ~]#kubectl get pods --show-labels	#查看pod默认名称空间下的pod资源的标签

[root@master1 ~]#kubectl label pods nginx-55f494c486-j9zsw version=v1.0	#向这个指定的pod上添加一个version=v1.0的标签

[root@master1 ~]#kubectl label pods nginx-55f494c486-j9zsw --overwrite version=v1.1	#修改指定pod上的指定的标签(version)的内容为v1.1

[root@master1 ~]#kubectl label pods nginx-55f494c486-j9zsw version-	#删除指定的资源上的version这个标签

[root@master1 ~]#kubectl get pods -l version=v1.1	#查看标签version=v1.1的pods

[root@master1 ~]#kubectl get pods -l version=v1.1 	#查看

[root@master1 ~]#kubectl get pods -l version=v1.1 --show-labels	#查看并显示详细信息
NAME                     READY   STATUS    RESTARTS   AGE   LABELS
nginx-55f494c486-wxd9z   1/1     Running   0          19h   app=nginx,pod-template-hash=55f494c486,version=v1.1


[root@master1 ~]#kubectl get pods -l version=v1.1 -L version	#查看有version的标签的pod并显示version的值
NAME                     READY   STATUS    RESTARTS   AGE   VERSION
nginx-55f494c486-wxd9z   1/1     Running   0          19h   v1.1

[root@master1 ~]#kubectl get pods -l 'version!=v1.0' -L version	#查看pod的标签version不等于v1.0的资源并显示详细信息

[root@master1 ~]#kubectl label pods nginx-55f494c486-p6rtj version=v1.0 env=testing	#一次定义多个标签

[root@master1 ~]#kubectl get pods -l 'env=testing' -l 'version=v1.1' --show-labels	#查看满足env=testing的和version=v1.1的标签的pod资源

[root@master1 ~]#kubectl get pods -l 'version in (v1.0,v1.1)' --show-labels	#查看满足version=v1.0的和version=v1.1的标签的pod资源

[root@master1 ~]# kubectl delete pods NAME --force --grace-period=0		#强制删除pods


[root@master1 ~]#kubectl get pods -l 'version notin (v1.0,v1.1)' --show-labels	#查看pod资源没有version=v1.0的和version=v1.1的标签的pod资源

[root@master1 ~]#kubectl get pods -l '!version' --show-labels	#查看没有version标签的资源

实验

实验:将svc默认的iptables更换成ipvs

[root@master1 zuoye]#kubectl get configmaps kube-proxy -n kube-system -oyaml > /root/1.yaml	#将kube-proxy的配置文件输出到指定的文件中
[root@master1 zuoye]#vim /root/1.yaml		#更改此文件
......*
mode: "ipvs"		#将此文件的mode的值改为ipvs即可
......*
[root@master1 zuoye]#kubectl apply -f /root/1.yaml	#重读此文件‘
[root@master1 zuoye]#kubectl delete pods -n kube-system -l k8s-app=kube-proxy	#删除这个标签有k8s-app=kube-proxy的pod(删除此pod会自动重建)

[root@master1 zuoye]#apt install -y ipvsadm		#安装ipvsadm用户空间管理工具
[root@master1 zuoye]#ipvsadm -ln	#已生成ipvs规则
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:31342 rr
  -> 10.244.4.38:80               Masq    1      0          0         
TCP  10.0.0.100:31342 rr
  -> 10.244.4.38:80               Masq    1      0          0         
TCP  10.0.0.200:31342 rr
  -> 10.244.4.38:80               Masq    1      0          0         
TCP  10.0.0.250:80 rr
  -> 10.244.4.38:80               Masq    1      0          0         
TCP  10.96.0.1:443 rr
  -> 10.0.0.100:6443              Masq    1      2          0         
  -> 10.0.0.101:6443              Masq    1      0          0     
........*

实验:使用externalIPs作为外部流量的访问入口

apiVersion: v1
kind: Service
metadata:
  labels:
    app: demoapp
  name: demoapp
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: demoapp
  type: ClusterIP
  externalIPs:	#使用外部的IP地址作为流量的访问入口
  - 10.0.0.200	#指定的IP的地址为10.0.0.200


[root@master1 chapter7]#kubectl get svc	#查看
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE	#externalIPs已经有了地址
demoapp      ClusterIP   10.108.191.52   10.0.0.200    80/TCP    6m13s
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   6m19s






**测试:使用无头服务**

```shell
[root@master1 chapter7]# vim demoapp-headless-svc.yaml 
---
kind: Service
apiVersion: v1
metadata:
  name: demoapp-headless-svc
spec:
  clusterIP: None	#不分配clusterIP地址
  selector:
    app: demoapp
  ports:
  - port: 80
    targetPort: 80
    name: http
[root@master1 chapter7]#kubectl apply -f demoapp-headless-svc
[root@master1 chapter7]#kubectl run pod-test --image=ikubernetes/admin-box:v1.2 --restart=Never -it --command -- /bin/bash	#进入一个pod
root@pod-test /# curl demoapp-headless-svc	#使用域名访问仍然可以
iKubernetes demoapp v1.0 !! ClientIP: 10.244.3.32, ServerName: demoapp-55c5f88dcb-n8hjz, ServerIP: 10.244.3.30!
root@pod-test /# curl demoapp-headless-svc   #使用域名访问仍然可以
iKubernetes demoapp v1.0 !! ClientIP: 10.244.3.32, ServerName: demoapp-55c5f88dcb-thd6f, ServerIP: 10.244.4.32!

是因为访问的时候直接将域名解析成为了pod的IP地址

root@pod-test /# host -t A demoapp-headless-svc
demoapp-headless-svc.default.svc.cluster.local has address 10.244.3.30		#直接解析出来pod的IP地址	
demoapp-headless-svc.default.svc.cluster.local has address 10.244.5.30		#直接解析出来pod的IP地址
demoapp-headless-svc.default.svc.cluster.local has address 10.244.4.32		#直接解析出来pod的IP地址
#查看此svc匹配的pod
[root@master1 chapter7]#kubectl describe svc demoapp-headless-svc 
Name:              demoapp-headless-svc
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=demoapp
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                None
IPs:               None
Port:              http  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.3.30:80,10.244.4.32:80,10.244.5.30:80	#刚好也是三个
Session Affinity:  None
Events:            <none>

无头服务实验二:

[root@master1 chapter7]#vim externalname-redis-svc.yaml 
kind: Service
apiVersion: v1
metadata:
  name: externalname-redis-svc
  namespace: default
spec:
  type: ExternalName	#类型为externalName
  externalName: redis.ik8s.io	#重定向解析到这个域名上
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
    nodePort: 0
  selector: {}

[root@master1 ~]#kubectl exec -it pod-test -- /bin/sh	#进入一个pod
root@pod-test # host -t A externalname-redis-svc	#解析
externalname-redis-svc.default.svc.cluster.local is an alias for redis.ik8s.io.
redis.ik8s.io has address 1.2.3.4	#重定向到1.2.3.4

root@pod-test # host -t CNAME externalname-redis-svc 	#使用cname解析
externalname-redis-svc.default.svc.cluster.local is an alias for redis.ik8s.io.

实验:利用无头服务、externalIPs、pvc持久存储、secret卷、自定义endpoints实现外接数据库的连接

1、定义secret卷

[root@master1 ~]# kubectl create secret generic mysql-secret-2 --from-literal=MYSQL_RANDOM_ROOT_PASSWORD=1 --from-literal=MYSQL_DATABASE=wordpress --from-literal=MYSQL_USER=wordpress --from-literal=MYSQL_PASSWORD=123456 --dry-run=client -oyaml > mysql-secret2.yaml	#指定数据库的库名字为wordpress、指定连接数据库的用户为wordpress、指定连接的密码为123456
[root@master1 zuoye]#vim secret/mysql-secret2.yaml 
apiVersion: v1	#创建的版本
data:	#数据表内容
  MYSQL_DATABASE: d29yZHByZXNz		#指定键值内容	为base64加密
  MYSQL_PASSWORD: MTIzNDU2		#指定键值内容为base64加密
  MYSQL_RANDOM_ROOT_PASSWORD: MQ==		#指定键值内容为base64加密
  MYSQL_USER: d29yZHByZXNz		#指定键值内容为base64加密
kind: Secret	#资源类型
metadata:	#元数据
  creationTimestamp: null	#创建时间
  name: mysql-secret-2	#资源名称


[root@master1 chapter7]#echo "d29yZHByZXNz"| base64 -d	#解码

2、定义pv及pvc卷

#现在NFS服务器上将目录共享出来
[root@ubuntu2004 wordpress]#apt install -y nfs-kernel-server 	#安装nfs服务
[root@ubuntu2004 wordpress]#vim /etc/exports	#指定目录
/data/wordpress_pv  10.0.0.0/24(rw,no_subtree_check,no_root_squash)
[root@ubuntu2004 wordpress]#mkdir /data/wordpress_pv -p
[root@ubuntu2004 wordpress]#exportfs -ar	#读取nfs配置文件

#创建pv
[root@master1 zuoye]#vim pv_pvc/01-pv-wordpress.yaml 
apiVersion: v1  #指定资源版本
kind: PersistentVolume  #指定资源类型
metadata:   #元数据
  name: pv-nfs-demo #资源名称
spec:   #定义终态
  capacity:     #指定大小
    storage: 10Gi   #定义大小
  volumeMode: Filesystem    #指的设备类型
  accessModes:  #指定工作模式
    - ReadWriteMany #多路读写
    - ReadOnlyMany  #多路只读
    - ReadWriteOnce #单路读写
  persistentVolumeReclaimPolicy: Retain #使用的删除策略为Retain
  mountOptions: #使用的存储类型
    - hard
    - nfsvers=4.1   #为nfs存储
  nfs:
    path:  "/data/wordpress_pv" #指定的远程目录为
    server: 10.0.0.106  #远程服务器的地址

#创建pvc
[root@master1 zuoye]#vim pv_pvc/02-pvc-wordpress.yaml 
apiVersion: v1  #资源版本
kind: PersistentVolumeClaim #资源类型
metadata:   #元数据
  name: pvc-wordpress   #资源名称
  namespace: default    #名称空间
spec:   #定义终态
  accessModes: ["ReadWriteMany"]    #指定工作模式为ReadWriteMany
  volumeMode: Filesystem    #指定设备类型
  resources:    #资源定义
    requests:   #最小容量为3G
      storage: 3Gi
    limits:     #最大容量为10G
      storage: 10Gi

3、部署集群外部数据库

[root@ubuntu2004 wordpress]#apt install -y mysql-server		#安装数据库
[root@ubuntu2004 wordpress]#mysql
mysql> create database wordpress;	#创建数据库
mysql> create user wordpress@"10.0.0.%" identified by '123456';	#创建用户及密码
mysql> grant all on wordpress.* to wordpress@"10.0.0.%";	#授权

4、创建连接外部的server及externalIPs使用标准端口连接服务

apiVersion: v1
kind: Endpoints	#创建endpoints资源
metadata:
  name: mysql-external	#名字必须与server名字相同
  namespace: default	#默认的名称空间
subsets:	#指定外部的ip地址
- addresses:
  - ip: 10.0.0.106
  ports:	#外部的服务器端口为
  - name: mysql
    port: 3306
    protocol: TCP
---
apiVersion: v1
kind: Service	#创建svc资源
metadata:
  name: mysql-external
  namespace: default
spec:
  type: ClusterIP
  clusterIP: None	#不分配clusterIP地址
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306
    protocol: TCP
    
#创建连接wordpress的svc
[root@master1 zuoye]#vim wordpress/03-svc-wordpress.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: wordpress
  name: wordpress
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: wordpress
  type: NodePort
  externalIPs:
    - 10.0.0.250

5、创建pod资源

apiVersion: v1
kind: Pod
metadata:
    name: wordpress
    labels:
        app: wordpress
spec:
    containers:
      - image: wordpress:5.7
        volumeMounts:
        - mountPath: /var/www/html/
          name: wordpress
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: "mysql-external"
        - name: WORDPRESS_DB_NAME   #赋值pod中的WORDPRESS_DB_NAME变量
          valueFrom:    #从卷中读取数据
            secretKeyRef:   #使用secret卷
                name: mysql-secret-2    #读取mysql-secret这个secret卷中的值
                key: MYSQL_DATABASE #将mysql-secret卷中的MYSQL_DATABASE的值复制到pod上的WORDPRESS_DB_NAME上
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyRef:	#使用secret卷赋值环境变量
                name: mysql-secret-2	#指定secret卷的名字
                key: MYSQL_USER	#指定secret卷中的MYSQL_USER的值赋值给WORDPRESS_DB_USER
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
                name: mysql-secret-2
                key: MYSQL_USER
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:	
                name: mysql-secret-2
                key: MYSQL_PASSWORD
    volumes:
    - name: wordpress   #名字
      persistentVolumeClaim:    #使用pvc
        claimName: pvc-wordpress    #pvc的名字

6、启动服务并测试

[root@master1 zuoye]#kubectl apply -f pv_pvc/01-pv-wordpress.yaml -f pv_pvc/02-pvc-wordpress.yaml -f secret/mysql-secret2.yaml -f wordpress/01-svc-wordpress.yaml -f wordpress/02-pod-wordpress.yaml -f wordpress/03-svc-wordpress.yaml	#按照顺序启动对应服务

#创建externalIPs的指定的虚拟IP地址(在集群任意节点创建即可)
[root@master1 zuoye]#vim /etc/netplan/01-netcfg.yaml 

# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      addresses:
      - 10.0.0.100/24
      - 10.0.0.200/24	
      - 10.0.0.250/24	#创建指定的IP地址
      gateway4: 10.0.0.2
      nameservers:
        search: [wang.com, wang.org]
        addresses: [180.76.76.76, 223.6.6.6]
[root@master1 zuoye]#netplan apply	#读取配置文件
[root@master1 zuoye]#ip addr |grep "10.0.0.250"
    inet 10.0.0.250/24 brd 10.0.0.255 scope global secondary eth0		#创建成功
    inet 10.0.0.250/32 scope global kube-ipvs0		#创建成功

实验:利用ngin反向代理带wordpress和外接数据库

1、创建pv及pvc及nfs存储

#配置nfs存储
#[root@ubuntu2004 conf.d]# vim /etc/exports
/data/nginx_pv  10.0.0.0/24(rw,no_subtree_check,no_root_squash)
[root@ubuntu2004 conf.d]#exportfs -ar	#读取配置文件

#创建pv
[root@master1 zuoye2]#vim pv_pvc/01-pv-nginx.yaml 
apiVersion: v1  #指定资源版本
kind: PersistentVolume  #指定资源类型
metadata:   #元数据
  name: pv-wordpress-nfs    #资源名称
spec:   #定义终态
  capacity:     #指定大小
    storage: 5Gi    #定义大小
  volumeMode: Filesystem    #指的设备类型
  accessModes:  #指定工作模式
    - ReadWriteMany #多路读写
    - ReadOnlyMany  #多路只读
    - ReadWriteOnce #单路读写
  persistentVolumeReclaimPolicy: Retain #使用的删除策略为Retain
  mountOptions: #使用的存储类型
    - hard
    - nfsvers=4.1   #为nfs存储
  nfs:
    path:  "/data/nginx_pv" #指定的远程目录为
    server: 10.0.0.106  #远程服务器的地址
    
    
#创建pvc
[root@master1 zuoye2]#vim pv_pvc/02-pvc-nginx.yaml 

apiVersion: v1  #资源版本
kind: PersistentVolumeClaim #资源类型
metadata:   #元数据
  name: pvc-wordpress-nfs   #资源名称
  namespace: default    #名称空间
spec:   #定义终态
  accessModes: ["ReadWriteMany"]    #指定工作模式为ReadWriteMany
  volumeMode: Filesystem    #指定设备类型
  resources:    #资源定义
    requests:   #最小容量为3G
      storage: 3Gi
    limits:     #最大容量为10G
      storage: 10Gi

2、创建secret卷

[root@master1 zuoye2]# kubectl create secret generic wordpress-secret --from-literal=MYSQL_RANDOM_ROOT_PASSWORD=1 --from-literal=MYSQL_DATABASE=wordpress --from-literal=MYSQL_USER=wordpress --from-literal=MYSQL_PASSWORD=123456 --dry-run=client -oyaml > wordpress-secret.yaml
[root@master1 zuoye2]#vim secret/wordpress-secret.yaml 
apiVersion: v1
data:
  MYSQL_DATABASE: d29yZHByZXNz
  MYSQL_PASSWORD: MTIzNDU2
  MYSQL_RANDOM_ROOT_PASSWORD: MQ==
  MYSQL_USER: d29yZHByZXNz
kind: Secret
metadata:
  creationTimestamp: null
  name: wordpress-secret

3、创建configmaps卷

#写好nginx的配置文件
[root@master1 zuoye2]#vim nginx-file/nginx1.conf
upstream cluster {
    server wordpress-svc-dl;
}
server{
    listen 80 default_server;
    server_name www.wwj.com;
    location / {
    proxy_pass http://cluster;
    proxy_set_header Host $http_host;
    }
}
[root@master1 zuoye2]# kubectl create configmap nginx.conf --from-file=nginx-file/ --dry-run=client -oyaml > configmaps/nginx1.conf	#利用写好的配置文件生成configmaps卷

4、创建外接数据库

[root@ubuntu2004 wordpress]#apt install -y mysql-server		#安装数据库
[root@ubuntu2004 wordpress]#mysql
mysql> create database wordpress;	#创建数据库
mysql> create user wordpress@"10.0.0.%" identified by '123456';	#创建用户及密码
mysql> grant all on wordpress.* to wordpress@"10.0.0.%";	#授权

5、创建wordpress及连接外部的server和负载均衡连接的server

#创建连接外部的server
[root@master1 zuoye2]#vim wordpress/01-wordpress-svc.yaml 
apiVersion: v1
kind: Endpoints	#创建endpoints资源
metadata:
  name: mysql-external	#此名称必须和对应的server名称相同
  namespace: default
subsets:
- addresses:
  - ip: 10.0.0.106
  ports:
  - name: mysql
    port: 3306
    protocol: TCP
---
apiVersion: v1
kind: Service	#创建server资源
metadata:
  name: mysql-external
  namespace: default		#指定名称空间
spec:
  type: ClusterIP	#svc类型
  clusterIP: None	#不分配cluster  IP地址
  ports:
  - name: mysql
    port: 3306	#指定端口
    targetPort: 3306	
    protocol: TCP


#创建wordpress的pods
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: wordpress
    version: "5.7"
  name: wordpress
spec:
  containers:
  - image: wordpress:5.7
    name: wordpress
    resources: {}
    env:
    - name: WORDPRESS_DB_HOST
      value: "mysql-external"
    - name: WORDPRESS_DB_NAME   #赋值pod中的WORDPRESS_DB_NAME变量
      valueFrom:    #从卷中读取数据
        secretKeyRef:   #使用secret卷
          name: mysql-secret    #读取mysql-secret这个secret卷中的值
          key: MYSQL_DATABASE #将mysql-secret卷中的MYSQL_DATABASE的值复制到pod上的WORDPRESS_DB_NAME上
    - name: WORDPRESS_DB_USER
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_USER
    - name: WORDPRESS_DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_DATABASE #将mysql-secret卷中的MYSQL_DATABASE的值复制到pod上的WORDPRESS_DB_NAME上
    - name: WORDPRESS_DB_USER
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_USER
    - name: WORDPRESS_DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_PASSWORD
    volumeMounts:
    - name: wordpress-data
      mountPath: /var/www/html
  volumes:  #定义储存卷
    - name: wordpress-data    #定义储存卷的名字
      persistentVolumeClaim:  #使用pvc
         claimName: pvc-wordpress-nfs	#指定pvc的名字


#创建负载均衡连接的svc
[root@master1 zuoye2]#vim wordpress/03-wordpress-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: wordpress
    version: "5.7"
  name: wordpress-svc-dl
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: wordpress
  type: ClusterIP

6、创建nginx负载均衡和svc

#创建nginx的server
[root@master1 zuoye2]#vim nginx/01-nginx-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx-svc
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
  externalIPs:
  - 10.0.0.200		#使用外部的IP地址#在集群中的一个IP地址可以使用虚拟IP地址在配置文件中添加一个即可


#创建nginx的pods
[root@master1 zuoye2]#vim nginx/02-nginx-pod.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:alpine
        name: nginx
        volumeMounts:
        - mountPath: /etc/nginx/conf.d/	#挂载到
          name: nginx-cm	#指定定义好的cm卷
      volumes:
       - name: nginx-cm #定义cm卷
         configMap:
           name: nginx.conf #引用的cm卷的名字(和刚刚创建好的cm卷的名字呼应上)
           optional: false

7、启动并测试

#启动
[root@master1 zuoye2]#kubectl apply -f configmaps/ -f pv_pvc/ -f secret/ -f wordpress/ -f nginx/

测试:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值