Kubernetes(二十二)Service(一)负载均衡

一    Service的引出背景

早期的'解决'方式 -->'Consul、Zookeeper'组件

'拓扑结构图'

nginx consul

二    Service

为'解决这个问题' Kubernetes 就为我们提供了'这样的一个对象' - Service

Service 是Kubernetes一种'抽象的对象',它定义了'一组 Pod 的逻辑集合'和一个用于'访问它们的策略',其实这个概念和'微服务'非常类似,可以理解为'一个Service'就是一个'微服务'

Service作用: 主要是提供'负载均衡'和'服务自动发现-->依赖于CoreDns'

具体解释: Kubernetes 为 Pods 提供自己的 IP 地址,并为'一组 Pod' 提供'相同的 DNS 名',并且可以在'Pods之间'进行'负载均衡'

Service 定义的抽象能够'解耦'这种关联-->'前端和后端'

+++++++++++++++++'Service解耦理解'+++++++++++++++++

假如:我们'后端'运行了3个副本,这些'副本都是可以替代的',因为前端'并不关心'它们使用的是哪一个后端服务,尽管由于各种原因'后端的 Pod 集合会发送变化',但是前端却'不需要'知道这些'变化',也不需要自己用一个'列表来记录'这些后端的服务,Service 的'这种抽象'就可以帮我们'达到这种解耦'的目的

(1)了解各种IP的概念

Node IP:      Node '节点的 IP 地址'  -->节点网络地址是配置在'节点网络'之上
Pod IP:       'Pod 的 IP 地址'
Cluster IP:   'Service 的 IP 地址'-->'Service VIP'-->没有配置在某个网络接口上'ICMP协议:不能ping',它只是'存在Service的规则'当中

(2)Service的类型

常见的'四种'形式

补充:Headless Service 算是'ClusterIP'的'特例' -->'None' 

说明1: 创建'Nodeport类型'的Service,也会自动创建'Cluster IP'

说明2: 创建'LoadBlance类型'的Service,也会'自动创建'-->'NodePort IP'和'Cluster IP'

说明3: Service 能够支持 TCP 和 UDP 协议,'默认是 TCP 协议'

说明4: 使用'LoadBlance',如果不是在云上,会一直'处于pending状态'

(3)k8s各种port

1)'port'

不管Service是哪种类型'Type',这里的'port表示':Service暴露在Cluster IP上的端口

备注: <cluster ip>:port 是提供给'集群内部客户'访问Service的入口

2)'nodePort'

nodePort('首字母小写')是Kubernetes提供给'集群外部客户'访问Service入口的一种方式(另一种方式是LoadBalancer)

备注: <nodeIP>:nodePort 是提供'给集群外部客户'访问Service的入口

3)'targetPort'

targetPort是'pod上的启动监听端口',一般与'Dockerfile中EXPOSE声明暴露的端口一致'

备注:从port和nodePort上到来的数'据最终经过kube-proxy'流入到'后端pod的targetPort上'进入容器

4)'port、nodePort总结'

总的来说port和nodePort都是'Service的端口'

'差异点': 前者暴露给'集群内'客户访问服务,后者暴露给'集群外'客户访问服务

'相同点': 从这两个端口到来的数据都需要'经过反向代理kube-proxy'流入'后端pod的targetPod',从而到达pod上的容器内

+++++++++++++'理解误区'+++++++++++++

下面的'name'没有特殊的含义-->不是'endpoints'

注意

1) 如果'不指定targetPort',默认情况下'targetPort 将被设置'为与 port 字段'相同的值'

'出错(error)'的场景: targetPort省略,但是实际容器的端口'不等于'Cluster IP的服务端口

2)LoadBlance对应'暴露'的端口和集群内的端口'一致'

3) 关于Servic的Type='NodePort'的形式,如果不指定'nodePort',会随机分配一个'30000~32767'端口,也可以'手动指定'

备注1: Kubernetes 服务的 'NodePort 默认端口'范围是 30000-32767

备注2: '不建议'修改,让kubernetes自己来管理,手动可能'造成冲突'

++++'kubeadm修改方式'++++

vim /etc/kubernetes/manifests/'kube-apiserver.yaml'

修改端口的场景: '防火墙'内网'只开放8000-9000'端口,其他都墙了

备注: 关于是否'重启'kube-apiserver'有待'考证

systemctl daemon-reload
systemctl restart 'kubelet'
systemctl status kubelet -l -->'查看状态'

二进制修改端口的方式

1)修改'/etc/kubernetes/apiserver'文件

KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.96.0.0/12 --service-node-port-range=8000-9000"

2)Centos7 '重启服务'

systemctl daemon-reload

systemctl restart kube-apiserver

port端口小知识

因为'标识端口的数据段'只有'两个字节',只有16位,2的16次方是65536,所以只有从0到65535这65536个端口了

备注: 0到1023是'被保留的',不能'自定义'的

说明: 先'粗浅'的这样认知

hostPort

三  Service的创建

Service是'四层',不关心'其上payload-->载荷'的信息

Service也是属于'ns'下的资源

(1)Service有selector字段

1)k8s在创建Service时,会根据'标签选择器selector'(lable selector)来查找'具有该标签的Pod'

2)一旦'找到对应的Pod',据此创建与Service'同名的Endpoint对象'

3)通过'Service IP: port'访问的时候,Service接收'前端client请求'的时候,就会通过endpoint根据'转发策略'找到转发到'某一个Pod'上的容器中

备注: 具体转发到'哪个节点的Pod',由负载均衡'kube-proxy初期'就决定好的

4)理解上:Service 到 'pod backend' 的选择相当于'一个VIP'  -->'类同'理解'Keepalived+Haproxy'
1.Endpoint是k8s集群中的一个'资源对象','存储在etcd中',用来记录一个Service对应的所有pod的'访问地址' 

endpoint组成: 就是Service关联的'Pod的ip地址'+'端口'

2.只有当Service'配置selector(选择器)',endpoint controller才会'自动创建'对应的endpoint对象,否则'不会生成'endpoint对象 

3.在k8s集群中创建'nginx的service','如果'ports不指定name,'默认'就会生成一个'同名'的endpoint对象

①  案例1:ClusterIP

apiVersion: apps/v1
kind: Deployment
metadata:
  name:  nginx
  namespace: default
spec:
  replicas: 2  # 期望的 Pod 副本数量,默认值为1
  selector:      '有这个字段'
    matchLabels:
      app: nginx
  template:  # Pod 模板
    metadata:
      labels:
        app: nginx    '具有该标签的Pod被deployments纳管、进而来管理pod的副本'
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:       '列表的形式,container可以暴露多个端口,一般我们只暴露一个端口'
        - name: wzj
          containerPort: 80
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx  '选择具有哪些标签的pod'      --> '一个 Serivce 下面包含的 Pod 集合是由 Label Selector 来决定的'
  ports:
  - name: http             
    protocol: TCP          '可以省略'
    port: 8080             'Service的端口'
    targetPort: wzj        '两种方式均可'
    #targetPort: 80        '容器中的端口'

细节: 如果'不指定targetPort',默认targetport和port一致,可能会'访问不到'

部署

查看信息

已知: 我们知道Deployment通过控制'ReplicaSet',而'Replicaset'是通过'app=nginx'和'pod-template-hash'来管理pod的

思考: 我们再创建一个具有'app=nginx'的pod,是否会导致最终'Deployment控制两个副本',但是Endpoints'列表却有三个'? -->'后续验证'

继续查看

查看对应'service'的endpoints

访问方式

curl 'Cluster IP:port'

强调: 默认是'趋近于'-->'rr'

Headless Service

无头'没有Cluster IP'服务的特点:'spec:clusterIP: None',但是还是'需要slector'选择对应的pod

②  案例2:NodePort 

备注: NodePort类型,两个'核心'的字段

1)spec.ports[].nodePort   --> '不指定的话,系统在区间范围自行设置'

2)spec.clusterIp:spec.ports[].port

++++'观察实验现象'​++++

观察1: 看是否'也创建Cluster IP'

观察2: 是否会起一个'随机端口'

备注: 'kubeadm方式'搭建的集群,'以上描述的并不准确',会在'集群中所有的节点(包含master)',起一个端口

为了说明: 会在'所有的node'启动一个端口,而不是'只在有pod的node'上启动端口,我们把副本数目改为1,观察'没有pod的node上'是否'有这个端口'
kubectl 'edit' deployments.apps nginx

说明: '在线编辑'的方式修改副本数目

说明: 事实上'master'也会i启动一个端口

访问方式

集群内: 'Cluster IP':'port'

集群外: '集群内的任何一个节点':'nodePort'
备注: 关于'kube-proxy'是什么? 我们'稍后'讲解

(2) Service没有slector字段

原理: 当service'没有配置'selector选择器,endpoint controller'不会'自动创建对应的'endpoint'对象

③  案例3:自定义Endpoint

'自己定义'Endpoints来'创建Service'

++++++++++'要求如下'++++++++++

1)自定义Service没有IP,'ClusterIP=None'

2)自定义Service的没有'slector参数'-->'不需要选择pod'

3)'Endpoint的名称'要和 'Service 保持'一致

++++++++++'应用场景'++++++++++

场景:etcd集群部署在'k8s集群之外'的,换句话说'并没有以pod的形式'部署在集群内

前提:api-server与etcd做过'认证',是可以'相互通信'的

模板文件

apiVersion: v1
kind: Service
metadata:
  name: etcd-k8s
  namespace: kube-system     '上面和下面要一致'
  labels:
    k8s-app: etcd
spec:
  type: ClusterIP
  clusterIP: None
  ports:
  - name: port
    port: 2379               'etcd暴露的端口'

---

apiVersion: v1
kind: Endpoints              '上面和下面要一致'
metadata:
  name: etcd-k8s             注意: 名称必须'和 Service 一致'
  namespace: kube-system
  labels:
    k8s-app: etcd
subsets:
- addresses:
  - ip: 10.151.30.57         说明:Service 将连接'重定向'到 endpoint
  - ip: 10.151.30.58
  - ip: 10.151.30.59
  ports:
  - name: port
    port: 2379    endpoint 的'目标端口'

备注:上面这个服务就是将外部的 etcd 服务引入到 Kubernetes 集群中

④ 案例4:ExternalName

应用场景

'应用场景': 后续决定要将'集群外的数据库'迁移到 'Kubernetes 集群中',可以启动对应的 Pod,'只需要'增加'合适的' Selector 或 Endpoint,修改 Service 的 type,完全'不需要修改调用的代码',这样就完全'解耦了'

特点 

说明: ExternalName 是 Service 的'特例','特点如下'

1)它没有 'selector'  -->'不是典型的选择器'

2)也没有定义任何的'端口'和'Endpoint'

作用: 对于运行在'集群外部'的服务,它通过'返回该外部服务的别名'这种方式来提供服务

模板文件

kind: Service
apiVersion: v1
metadata:
  name: mysql
spec:
  type: ExternalName  
  externalName: database.example.com  -->  '指定外部服务的域名'

说明: 进入'busybox'这个pod,'nsllokup无法'解析该Cname原因,集群'找不到对应的ip'

达到的效果

当访问地址 mysql.default.svc.cluster.local'涉及服务发现'时,集群的 DNS 服务将返回一个值为 my.database.example.com 的 'CNAME 记录'

注意:访问这个服务的工作方式与其它的相同,唯一'不同'的是'重定向发生在 DNS 层',而且'不会'进行代理或转发
备注: 由于上述'externalName'无法解析,这里换成'www.baidu.com'

两个不同的namespace之间的不同pod可以通过name的形式访问

实现方式:

A:在其他pod内ping [svcname].[namespace] ping出来到结果就是svc的ip地址

B:通过externalname,把'对方'到[svcname].[namespace].svc.cluster.local,'绑定到'externalname定义到字符串上  --> '核心关注这个'

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值