[kubernetes] Endpoint 和 Service介绍与应用

417 阅读5分钟

0x01 介绍

   每个Pod都有独有的IP地址,而每次Pod重建后IP地址都会发生变化,那我们如何长期对一个Pod进行访问呢?答案就是ServiceServcie可以理解为一组Pod的四层代理,Service作为kubernets一种标准的资源,它可以通过节点的kube-proxyapiserver中获取每个Pod的地址,从而实现代理功能。由下图可见,每一个Service资源都有一个endpointsendpoints主要记录了每个pod的IP地址信息,当Pod的IP发生变化时,endpoints会进行更新。

图片

    Service常见的代理模式有两种,一种是IPVS,一种是iptables;还有比较新的cni:ebpf、nftables。本篇使用的是IPVS,启用IPVS可以通过以下方式进行设置:

    1、使用kubeadm安装的集群配置

   # kubectl edit configmap kube-proxy -n kube-system
   ...
   mode: “ipvs“
   ...、
   # kubectl delete pod kube-proxy-btz4p -n kube-system
   注:1、kube-proxy配置文件以configmap方式存储
   2、如果让所有节点生效,需要重建所有节点kube-proxy pod

    2、二进制安装的集群配置

# vi kube-proxy-config.ymlmode: ipvsipvs:scheduler: "rr“
# systemctl restart kube-proxy
注:参考不同资料,文件名可能不同。

    值得注意的是:当 kube-proxyIPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

0x02 Service快速入门

定义一个deployment资源

[root@aliyun168-37 nginx]# cat dp.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
  namespace: test
spec:
  replicas: 3
  selector: 
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80

    定义一个service资源

[root@aliyun168-37 nginx]# cat svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: test
spec:
  selector:
    app: nginx   # 选择的pod
  ports:
  - port: 8080 # service端口
    targetPort: 80  # container端口
    protocol: TCP  # 协议类型

    应用:

kubectl apply -f dp.yaml
kubectl apply -f svc.yaml

   至此一个Service资源就创建好了,Serviceendpointlabels app:nginxpod.

   

    查看Pod

[root@aliyun168-37 nginx]# kubectl get pod -n test -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP             NODE      NOMINATED NODE   READINESS GATES
nginx-7848d4b86f-mdql8   1/1     Running   0          6m45s   10.244.4.140   wokayou   <none>           <none>
nginx-7848d4b86f-t5zmt   1/1     Running   0          6m45s   10.244.4.139   wokayou   <none>           <none>
nginx-7848d4b86f-zt7jj   1/1     Running   0          6m45s   10.244.4.141   wokayou   <none>           <none>

    查看Service

[root@aliyun168-37 nginx]# kubectl describe svc/nginx-svc -n test
Name:              nginx-svc
Namespace:         test
Labels:            <none>
Annotations:       Selector:  app=nginx
Type:              ClusterIP
IP:                10.109.58.23
Port:              <unset>  8080/TCP  # 代理后的端口
TargetPort:        80/TCP  # Container的端口
Endpoints:         10.244.4.139:80,10.244.4.140:80,10.244.4.141:80
Session Affinity:  None
Events:            <none>

    查看Endpoints(创建Service后会自动创建一个同名的endpoints)

[root@aliyun168-37 nginx]# kubectl get endpoints nginx-svc -n test
NAME        ENDPOINTS                                         AGE
nginx-svc   10.244.4.139:80,10.244.4.140:80,10.244.4.141:80   18m

图片

    访问:

图片

    查看IPVS规则:

图片

0x03 Service类型和应用

    Service支持4种类型:

  1. ClusterIP(默认模式)

  2. NodePort:主机端口模式

  3. Headless ClusterIP:无头模式

  4. LoadBalancer:使用外部负载均衡

  5. ExternalName:将外部服务引入集群内部

**0x03.1 ClusterIP
**

     不指定Service类型时,默认类型为ClusterIP,而这个ClusterIP的地址段在安装集群的时已经配置好了,ClusterIP一般只能在集群内访问,集群外是无法访问的。

图片

    配置位置:

cat kube-controller-manager.yaml 
...
    - --service-cluster-ip-range=10.96.0.0/12
...

      ClusterIP类型使用:

[root@aliyun168-37 nginx]# cat svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: test
spec:
  selector:
    app: nginx
  ports:
  - port: 8080   # service端口
    targetPort: 80 # container Port
    protocol: TCP
  type: ClusterIP

    也可以指定ClusterIP

...
spec:
...
  type: ClusterIP
  clusterIP: 10.100.100.100
...

0x03.2 NodePort

    NodePort类型的Service应用后,每个Node都会监听该端口。我们可以通过任意一个NodeIP:Port来访问。

图片

    创建一个NodePort类型的Service

...
spec:
...
  ports:
  - port: 80
    protocol: TCP
  type: NodePort
...

    查看_Service_,可以看到已经将80端口映射为31321端口了

[root@aliyun168-37 nginx]# kubectl get svc -n test
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx-svc   NodePort   10.104.215.99   <none>        80:31321/TCP   3m23s

    随便登录一台主机,查看端口监听情况

图片

    集群外访问测试:

图片

    NodePort类型的Service在不指定Port的情况下,将随机分配一个Port,而分配的访问默认为_30000-32767_,可以通过以下配置文件进行修改:

vim kube-apiserver.yaml

增加:
- --service-node-port-range=1-65535

    也可以指定_NodePort_

...
spec:
...
  ports:
  - port: 80
    protocol: TCP
    nodePort: 1023
  type: NodePort
...

0x03.3 Headless ClusterIP无头服务

    无头服务是一种特殊_ClusterIP类型的Service,但是没有ClusterIP,只能通过域名进行访问,无头服务一般在StatfulSet_中使用。

    定义一个_Headless ClusterIP_资源

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: test
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    protocol: TCP
  clusterIP: "None"  # 此处定义为Node,即为Headless

    查看_Service_

[root@aliyun168-37 nginx]# kubectl get svc -n test
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx-svc   ClusterIP   None         <none>        80/TCP    48s

图片

    获取集群内_DNS_地址

图片

    解析地址,域名组成为_servicename.namespace.svc.cluster.local_:

[root@aliyun168-37 nginx]# nslookup nginx-svc.test.svc.cluster.local 10.96.0.10
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   nginx-svc.test.svc.cluster.local
Address: 10.244.4.140
Name:   nginx-svc.test.svc.cluster.local
Address: 10.244.4.141
Name:   nginx-svc.test.svc.cluster.local
Address: 10.244.4.139

    集群内访问:

图片

0x****03.4 ExternalName 将外部流量引入集群内部

    _ExternalName类型的Service通过CNAM__E和它的值,可以将服务映射到externalName_字段的内容引入外部服务到内部流量,即使用DNS _CNAME机制把自己CNAME_到你指定的另外一个域名上。

图片

    定义一个_externalName类型Service_:

[root@aliyun168-37 nginx]# cat svc3.yaml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: test
spec:
  type: ExternalName
  externalName: mysql.51yunwei.top

    _pod使用mysql_进行访问

图片

0x****03.5 LoadBalancer****使用外部负载均衡

    LoadBalancer需要使用外部Balancer(负载均衡器)来实现,我的环境无法演示。

图片

0x04 使用endpoint代理集群外部服务

     通过上面的例子,我们知道service是依靠endpoint实现的,而这个endpoint也是一种kuberntes资源,支持自定义,这就意味着我们也可以使用service实现集群外部的资源代理访问。

图片

    定义endpoints:

apiVersion: v1
kind: Endpoints
metadata:
  name: mysql-svc
  namespace: test
subsets:
  - addresses: 
    - ip: 1.1.1.1
    ports:
    - port: 3306

    定义service(名字和endpoints一样就可以自动关联起来了):

apiVersion: v1
kind: Service
metadata: 
  name: mysql-svc
  namespace: test
spec:
  ports:
  - port: 3306
    targetPort: 3306
    protocol: TCP

    查看:

[root@aliyun168-37 nginx]# kubectl describe svc mysql-svc -n test      
Name:              mysql-svc
Namespace:         test
Labels:            <none>
Annotations:       Selector:  <none>
Type:              ClusterIP
IP:                10.103.36.61
Port:              <unset>  3306/TCP
TargetPort:        3306/TCP
Endpoints:        1.1.1.1:3306
Session Affinity:  None
Events:            <none>
[root@aliyun168-37 nginx]# 

    访问:

图片


--结束。

本文使用 文章同步助手 同步