K8S headless 服务


1. 定义

  在某些场景下,开发人员可能不想使用 Service 提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,Kubernetes 提供了 Headless Service,这类 Service 不会分配 ClusterIP,如果想要访问 Service,只能通过 service 的域名进行查询。
  因为没有 ClusterIP,kube-proxy 并不处理此类服务,因为没有 load balancing 或 proxy 代理设置,在访问服务的时候回返回后端的全部的 Pods IP 地址,主要用于开发者自己根据 pods 进行负载均衡器的开发 (设置了 selector),相比于 clusterIP,headless 少了一层,直接解析的 podip 所以速度更快。

需要注意的是,不管是 headless 类型的 service 还是 clusterip 类型的 service,都可以在相同命名空间的容器内解析 service 名称;headless 解析出来的是 podip,ping servicename 可以通,clusterIP 类型的 service 解析出来的是分配的 clusterip,ping 不通。通过 headless 类型的 service 访问的直接是容器内端口 headless-service-name containerport,这时候在 service 里面指定的 port 和 targetport 都是无用的;通过 clusterIP 类型的 service 名称是无法直接访问容器内端口的,需要先通过 targetPort 指定容器内端口,port 指定转发后的端口,访问的是 cluterip-service-name port

2. 创建 headless 服务

将 service spec 中 的 clusterIP 字段设置为 None 会使服务成为 headless 服务,因为 Kubernetes 不会为其分配集群 IP,DNS 服务器将返回 podIP 而不是单个服务 IP。

open1-headless.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open1-headless
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: open1-headless
  template:
    metadata:
      labels:
        app: open1-headless
    spec:
      containers:
      - name: open1-headless
        image: openresty:1.21.4.1
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: open1-headless
  namespace: dev
spec:
  selector:
    app: open1-headless
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

open2-headless.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: open2-headless
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: open2-headless
  template:
    metadata:
      labels:
        app: open2-headless
    spec:
      containers:
      - name: open2-headless
        image: openresty:1.21.4.1
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: open2-headless
  namespace: dev
spec:
  selector:
    app: open2-headless
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

查看

[root@master ~/openresty]#kubectl get pods,svc,deploy -o wide -n dev
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod/open1-headless-79b845f7fc-bkv4g   1/1     Running   0          14s   10.244.0.8    master   <none>           <none>
pod/open1-headless-79b845f7fc-jqtqv   1/1     Running   0          14s   10.244.1.9    node01   <none>           <none>
pod/open1-headless-79b845f7fc-m24x2   1/1     Running   0          14s   10.244.2.8    node02   <none>           <none>
pod/open2-headless-69bb4dcf5c-l9gtc   1/1     Running   0          14s   10.244.1.10   node01   <none>           <none>
pod/open2-headless-69bb4dcf5c-n6bdn   1/1     Running   0          14s   10.244.0.9    master   <none>           <none>
pod/open2-headless-69bb4dcf5c-qw8mr   1/1     Running   0          14s   10.244.2.9    node02   <none>           <none>

NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/open1-headless   ClusterIP   None         <none>        80/TCP    15s   app=open1-headless
service/open2-headless   ClusterIP   None         <none>        80/TCP    14s   app=open2-headless

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS       IMAGES               SELECTOR
deployment.apps/open1-headless   3/3     3            3           15s   open1-headless   openresty:1.21.4.1   app=open1-headless
deployment.apps/open2-headless   3/3     3            3           14s   open2-headless   openresty:1.21.4.1   app=open2-headless

3. 访问服务

headless 服务因为没有 ClusterIP,所以不能使用 ip 去访问了,只能使用域名,而且只能在容器内部生效,域名格式:

[service的名字].[命名空间].svc.cluster.local

进入容器

[root@master ~]#kubectl exec -it open1-headless-79b845f7fc-m24x2 bash -n dev
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
[root@open1-headless-79b845f7fc-m24x2 /]# cat /etc/resolv.conf 
nameserver 10.96.0.10
search dev.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5

域名解析

[root@open1-headless-79b845f7fc-m24x2 /]# dig @10.96.0.10 open1-headless.dev.svc.cluster.local

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.9 <<>> @10.96.0.10 open1-headless.dev.svc.cluster.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44669
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;open1-headless.dev.svc.cluster.local. IN A

;; ANSWER SECTION:
open1-headless.dev.svc.cluster.local. 30 IN A	10.244.1.9
open1-headless.dev.svc.cluster.local. 30 IN A	10.244.2.8
open1-headless.dev.svc.cluster.local. 30 IN A	10.244.0.8

;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Sat Aug 20 05:34:34 UTC 2022
;; MSG SIZE  rcvd: 221
# 通过域名解析可以看到三个后端 podIP
[root@open1-headless-79b845f7fc-m24x2 /]# nslookup open1-headless 10.96.0.10 
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	open1-headless.dev.svc.cluster.local
Address: 10.244.1.9
Name:	open1-headless.dev.svc.cluster.local
Address: 10.244.0.8
Name:	open1-headless.dev.svc.cluster.local
Address: 10.244.2.8

通过域名访问另一个服务

[root@open1-headless-79b845f7fc-m24x2 /]# telnet open2-headless 80
Trying 10.244.2.9...
Connected to open2-headless.
Escape character is '^]'.
^CConnection closed by foreign host.
[root@open1-headless-79b845f7fc-m24x2 /]# ping open2-headless -c 3
PING open2-headless.dev.svc.cluster.local (10.244.1.10) 56(84) bytes of data.
64 bytes from 10-244-1-10.open2-headless.dev.svc.cluster.local (10.244.1.10): icmp_seq=1 ttl=62 time=0.438 ms
64 bytes from 10-244-1-10.open2-headless.dev.svc.cluster.local (10.244.1.10): icmp_seq=2 ttl=62 time=0.454 ms
64 bytes from 10-244-1-10.open2-headless.dev.svc.cluster.local (10.244.1.10): icmp_seq=3 ttl=62 time=0.470 ms

--- open2-headless.dev.svc.cluster.local ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.438/0.454/0.470/0.013 ms

4. 详细配置

apiVersion: v1
kind: Service
metadata:
  name: open-headless
  namespace: dev
spec:
  clusterIP: None
  ports:
  - name: open-headless
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: open-headless
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-headless 
  namespace: dev
  labels:
    app: open-headless
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: open-headless
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: open-headless
    spec:
      containers:
      - name: open-headless
        image: openresty:1.21.4.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: open-headless
          protocol: TCP
        resources:
          limits:
            cpu: 1000m
            memory: 1024Mi
          requests:
            cpu: 200m
            memory: 128Mi
        livenessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 5 
          periodSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 5
          periodSeconds: 5
          successThreshold: 1
          failureThreshold: 5
posted @ 2022-08-20 13:57  公博义  阅读(1017)  评论(0编辑  收藏  举报