kubernetes服务访问与负载均衡(一)

当使用kubernetes来发布应用时,Pod实例的生命周期是短暂,PodIP也是易变的。所以kubernetes中抽象了一个叫Service的概念,给应用提供一个固定的访问入口。

定义一个Service

假如现在:你有一个tomcat镜像,你用它创建了一个Deployment,发布了三个Pod实例;这组Pod暴露了8080端口,并且都拥有标签app=tomcat。那么,你可以创建如下的一个Service对象,然后在kubernetes集群的容器内或集群的Node上,都可以通过该 Service的ClusterIPPort 来访问这组Pod的8080端口:(具体原理见文章后面的实验部分)

kind: Service
apiVersion: v1
metadata:
  name: tomcat
spec:
  type: ClusterIP
  clusterIP: 10.254.11.12  # 可以指定,也可以随机生成
  selector:
    app: tomcat
  ports:
  - protocol: TCP
    port: 8080         # Service的Port
    targetPort: 8080         # Pod的Port

创建如上的一个Service对象后,Endpoints Controller也会自动创建一个与该Service同名的Endpoints。然后根据Service中的selector,把集群中label中含有app=tomcat 的Pod加入到该Endpoints中。

ClusterIP和Service代理

在上面的Service定义文件中,ClusterIP是一个虚拟IP。它既不是某个Pod的IP,也不是某个Node的IP。kubernetes集群中的每个节点上都运行一个kube-proxy,它负责监听ServiceEndpoints的创建与删除,并相应地修改Node上的iptables规则。

kube-proxy有三种代理模式:userspace、iptables、ipvs。从kubernetes v1.2开始,iptables成为默认的代理模式,在kubernetes v1.9-alpha中,加入了ipvs代理模式。本文主要介绍一下iptables代理模式。

Proxy-mode:iptables

在这种模式下,对于每一个Service,它会在Node上添加相应的iptables规则,将访问该Service的ClusterIP与Port的连接重定向到Endpoints中的某一个后端Pod。默认情况下,选择哪一个Pod是随机。

当选择的某个后端Pod没有响应时,iptables模式无法自动重新连接到另一个Pod,所以需要用户自已利用Pod的readness probeliveness probe 来规避这种情况。下图(截自官网)给出了通过ServiceIP:ServicePort 访问应用的原理:

这里写图片描述

服务发现

在上面的内容中,我们讲述了可以通过Service的IP和端口来访问应用。不过,在Pod中(注意在Node上不行),我们也可以通过Service的名字加端口来访问应用,它依赖于kubernetes的服务发现机制。

kubernetes的服务发现机制有两种:环境变量与DNS。

环境变量

当kubelet创建一个Pod时,对于每一个活动的Service,它会往该Pod中加入一组环境变量,形如:{SVCNAME}_SERVICE_HOST{SVCNAME}_SERVICE_PORT 等。其中服务名是大写的,破折号会被转化为下划线。

例如,有一个Service,名叫redis-master,暴露了6379的TCP端口,ClusterIP为 10.0.0.11,那么会产生下面的环境变量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

顺序很重要: 一个Pod想要访问一个Service,则服务必须在该Pod之前创建,否则该Service的环境变量将不会被加入到Pod中。DNS不会有这个限制。

DNS

DNS服务器是一个可选的插件(强烈推荐使用)。DNS服务器会通过Kubernetes的API监听Service的创建,然后为Service创建一组DNS记录。如果在整个集群中开启了DNS,则所有的Pod都能够自动地做Service的域名解析。
例如,如果在Kubernetes的命名空间my-ns中有一个叫my-service的Service,那么就会创建一条my-service.my-ns的DNS记录。命名空间my-ns中的Pod可以直接使用my-service做域名解析。其他命名空间中的Pod则使用my-service.my-ns做域名解析.解析出来的结果是Service的ClusterIP。

Service的类型

kubernetes的Service有四种类型:ClusterIPNodePortExternalNameLoadBalancer。本文主要介绍一下前两种。

ClusterIP

ClusterIP 是Service的默认类型,如果不设置type 字段,则默认为ClusterIP。这种类型的Service把服务暴露成一个内部的集群IP,只能在集群内访问(Pod和Node上都可以)。clusterIP 字段的值可以自动生成,也可以手动设置,不过一定要在规则的范围内,可通过kube-apiserver 的启动参数--service-cluster-ip-range 指定ClusterIP 的范围。

NodePort

如果将type字段设置为NodePort,则Kubernetes master将从启动参数--service-node-port-range配置的范围(默认值:30000-32767)分配端口,并且每个节点将该端口(每个节点上端口号相同)代理到你的Service。该端口可以在Service的spec.ports[*].nodePort字段进行查看。

如果你想要一个特定的端口号,你可以在该nodePort字段中指定一个值,系统将为你分配该端口,或者API事务将失败(也就是说,你需要注意自己可能发生的端口冲突)。你指定的值必须位于节点端口的配置范围内。

这种类型的Service也会有一个ClusterIP。这意味着,它有两种访问方式:通过ServiceIP:SerivcePort 访问,或者通过NodeIP:NodePort 访问。

实验一

发布一个ClusterIP类型的Service,查看在Node上通过ServiceIP:ServicePort 访问服务是如何被重定向到后端Pod的。

1、环境准备

搭建好集群,本文中的实验集群信息如下:

$ kubectl get node
NAME              STATUS    ROLES     AGE       VERSION
132.122.232.101   Ready     <none>    31d       v1.8.6
132.122.232.78    Ready     <none>    13d       v1.8.6

2、创建deployment

创建一个deployment,发布三个实例,yaml文件如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - name: container1
        image: 10.142.232.115:8021/public/tomcat:8
        ports:
        - containerPort: 
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值