K8s Service

什么是service

pod不是永恒存在的,pod会随时被创建,同时pod也会被随时销毁(运行出错,超过资源限制等原因)。pod不可能被复活,因此pod被销毁和重建之后的IP地址是不同的。
其他依赖该pod的服务不可能去维护这些pod的IP地址信息。这里我们引入的service,service保存了我们如何访问一组pod的方式。这一组pod通过pod selector来确定。无论这些pod怎样创建和销毁,他们的label不变。service可以动态维护这些pod的真实IP(通过endpoint对象)。所以说,service解耦了pod和依赖这些pod的应用。

定义一个service

创建service的描述文件:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

这里我们定义了一个service的描述文件。service的名字为my-service。service指向的pod需要具有app: MyApp标签。可以使用80端口访问每个pod的9376端口。这个service拥有一个cluster IP。这个IP只能在kubernetes集群内部访问。

具有selector的service在创建的时候会自动创建一个同名的endpoint。endpoint维护了具有这些标签的一组pod的真正的IP。如果这些pod的IP发生变化,endpoint中的IP也会随着变化。

没有pod selector的service

如下情况我们需要使用没有pod selector的service:

  • 使用集群外部的数据库
  • 要创建的service指向位于另一个namespace,或者是另一个kubernetes集群的service

编写描述文件:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

只有这样是不够的,service需要有一个对应的endpoint对象。创建没有selector的service并不会随之创建一个endpoint。这时候我们需要手工创建endpoint。endpoint的描述文件如下:

apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 192.0.2.42
    ports:
      - port: 9376

service proxy

service使用kube-proxy实现

不使用轮询DNS方式的原因

  • 不少DNS的实现不支持TTL(Time To Live)。无法在pod IP发生变化的时候及时改变缓存。
  • 一部分应用在DNS查询之后便永久保存,再也不会更新。
  • 即便是支持DNS再次解析,我们需要降低DNS的TTL。越低的TTL会导致DNS解析服务的频繁运行,增加系统的负载。

user space proxy 模式

kube-proxy 负责监视service和endpoint的创建和删除。对于每个service,在本地节点上随机开启一个端口(代理端口)。任何连接到该端口的连接会被代理到service后端一组pod中的一个。kube-proxy使用SessionAffinity配置项来决定使用哪一个后端pod。

user space模式使用iptables规则,把目标为service的cluster IP和端口的请求发送到代理端口。

iptables proxy 模式

iptables使用规则配置,将访问service的cluster IP和port的连接重定向到某一个后端pod。默认来说,kube-proxy随机选择后端pod提供服务。

iptables模式系统开销较小。

如果连接到的第一个被选定的pod没有响应,此连接会失败。这个和userspace模式不同。userspace模式中,如果连接到第一个pod失败,系统会自动重试连接另一个后端pod。

可以使用readness probe来确保pod是否正常工作。如果某个podreadness probe 失败,这个pod会从endpoint中移除,网络请求不会再转发到这个pod中,直到readness probe恢复到success状态。

IPVS proxy 模式

ipvs 模式kube-proxy使用netlink接口创建IPVS规则。IPVS基于钩子函数,使用内核空间的hash表作为底层数据结构。因此IPVS相比iptables具有更低的延迟,吞吐量更高。同时同步代理规则的时候也更快。

IPVS重定向网络通信具有如下策略:

  • rr: round-robin 轮询
  • lc: least connection (smallest number of open connections) 优先连接数最少
  • dh: destination hashing 目标hash
  • sh: source hashing 源hash
  • sed: shortest expected delay 延迟最小
  • nq: never queue 不排队

如果需要相同客户端的请求被重定向到相同的pod,需要配置service.spec.sessionAffinityClientIP(默认为None)。我们还可以设置pod和client的最大粘性时间service.spec.sessionAffinityConfig.clientIP.timeoutSeconds。默认为10800,即3小时。如果3小时内client没有访问pod,那么该client下次访问service的时候将重新指定新的pod,原先的session会失效。

多端口服务

service可以暴露多个port。如果使用多个port,必须为每一个port设置name。描述文件如下所示:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

显式指定service的IP

可以设定spec.clusterIP配置项。但是IP必须位于API server的service-cluster-ip-range CIDR范围中。

service发现

环境变量方式

Kubernetes自动为每一个运行的pod中加入各个service环境变量。这些service的环境变量的格式为

  • {SVCNAME}_SERVICE_HOST
  • {SVCNAME}_SERVICE_PORT

以redis-master服务为例,对应的环境变量为:

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中将没有这个service的环境变量。如果使用DNS方式的话不需要担心这个创建顺序问题。

DNS方式

集群的DNS服务,例如CoreDNS会监听service,创建service对应的DNS入口。

如果在命名空间my-ns定义了一个服务my-service,自动创建的DNS入口为my-service.my-ns。集群内任何pod可以通过此DNS访问这个服务。如果是和该服务位于同一个命名空间的pod,可以省略DNS中的命名空间部分,使用my-service这个DNS入口访问my-service服务。

DNS支持命名端口的方式。如果一个端口命名为http,使用的是TCP协议,可以通过_http._tcp.my-service.my-ns这条DNS解析到它的IP和端口号。

Headless Service

特点:

  1. 禁用掉了service的负载均衡功能。
  2. 没有指定service的clusterIP。
  3. service不使用kube-proxy代理。

适用场景:

  1. 需要不经过代理直接访问pod。
  2. 使用服务发现功能,例如部署zookeeper等。

配置方式:
设置spec.clusterIPNone

DNS自动配置的方式和是否配置了pod selector有关。

  • 配置了pod selector:endpoints会被创建,DNS直接指向后台pod的IP
  • 没有配置pod selector:endpoints不会被创建。DNS服务会查找: 1. CNAME记录(ExternalName-type Services)2. 和service同名的endpoints

公开service(允许service在集群外访问)

通过设置服务类型(ServiceType)来实现。
service type有如下类型:

  • clusterIP:一个只有在集群内部可访问的虚拟的IP。这个是Service Type的默认值。
  • NodePort:使用每个节点的一个静态端口来访问service。集群外可使用<NodeIP>:<NodePort>形式访问。
  • LoadBalancer:负载均衡器,使用云提供商的负载均衡器访问服务。
  • ExternalName:映射为一个自定义DNS名称,适用于访问外部服务。

除此之外还可以使用Ingress方式,但是Ingress不是ServiceType。

NodePort

NodePort范围从--service-node-port-rangeflag中随机选择(默认为30000-32767)。分配的端口号在.spec.ports[*].nodePort字段中。

可以使用kube-proxy的--nodeport-addresses配置指定nodePort IP的范围。

可以通过指定nodePort字段的内容,来使得NodePort使用一个固定的IP。

NodePort的使用例子:

apiVersion: v1
kind: Service
metadata:
    name: kubia-nodeport
spec:
    type: NodePort
    ports:
        - port: 80
          targetPort: 8080
          nodePort: 30123
    selector:
        app: kubia

LoadBalancer

自己部署的集群中无LoadBalancer,此部分省略。

ExternalName

映射service到一个DNS名称。

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

External IPs

使用外部IP访问服务。要求可以通过外部IP访问到集群节点。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
  externalIPs:
    - 80.11.12.10

Service 使用Session Affinity

session affinity,同一个client发出的请求会发送给同一个pod处理。配置方法如下:

apiVersion: v1
kind: Service
spec:
    sessionAffinity: ClientIP
    ...

使用命名端口

可以在Pod中为端口命令,在service中使用。

步骤如下所示:

  1. 在pod中给端口命名
kind: Pod
spec:
    containers:
    - name: kubia
      ports:
      - name: http
        containerPort: 8080
      - name: https
        containerPort: 8443
  1. 创建service时使用命名端口(targetPort中使用)
apiVersion: v1
kind: Service
spec:
    ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https

Service关联k8s集群外部的服务

把集群外部的某一服务的入口做成k8s的endpoint。创建service的时候如果不指定label selector,endpoints就不会自动创建。

下面举一个例子。我们需要在k8s集群中访问集群外部11.11.11.11和22.22.22.22的80端口这个服务。

这里我们需要手工创建service和endpoint:

apiVersion: v1
kind: Service
metadata:
    name: external-service
spec:
    ports:
    - port: 80
apiVersion: v1
kind: Endpoints
metadata:
    name: external-service
subsets:
    - addresses:
        - ip: 11.11.11.11
        - ip: 22.22.22.22
    ports:
        - port: 80

完成之后,集群内部可以通过访问external-service来实现访问集群外部11.11.11.1122.22.22.22

减少网络连接的hop数量

可以通过配置service,只把连接重定向到接收这个连接的node上运行的pod。

方法如下:

spec:
    externalTrafficPolicy: Local
    ...

缺点:如果这个node上没有运行该service对应的pod,连接会挂起。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容