[单master节点k8s部署]11.服务service

service

service是一个固定接入层,客户端 可以访问service的ip和端口,访问到service关联的后端pod,这个service工作依赖于dns服务(coredns)

每一个k8s节点上都有一个组件叫做kube-proxy,始终监视着apiserver上获取任何一个与service资源相关的变得信息,一旦service资源发生变动,kube-proxy都会利用规则来调度,保证service实现。

k8s 在创建 Service 时,会根据标签选择器 selector(lable selector)来查找 Pod,据此创建与 Service 同名的 endpoint 对象,当 Pod 地址发生变化时,endpoint 也会随之发生变化,service 接收前 端 client 请求的时候,就会通过 endpoint,找到转发到个 Pod 进行访问的地址。(至于转发到哪个节点的 Pod,由负载均衡 kube-proxy 决定)

写一个service的yaml文件,用来管理之前deployment创建的pod

[root@master yam_files]# cat deploy-service.yaml 
apiVersion: v1
kind: Service
metadata: 
  name: deploy-nginx
  namespace: default

spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: myapp
  type: NodePort
[root@master yam_files]# cat deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    app: my-deployment

spec:
  replicas: 2
  selector:
    matchLabels: 
      app: myapp
      version: v1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1 
  template:
    metadata: 
      name: test
      labels:
        app: myapp
        version: v1
    spec:
      containers:
      - name: my-container
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        startupProbe:
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        livenessProbe:
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        readinessProbe:
          periodSeconds: 5
          initialDelaySeconds: 20
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /

查看svc的端口,发现由于这个服务是nodePort类型的,所以80端口映射到外部的30721端口 

kubectl get svc
NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
deploy-nginx      NodePort    10.111.154.75    <none>        80:30721/TCP                    59m

 发现这个service的endpoint对应着deployment创建的pod

[root@master yam_files]# kubectl describe svc deploy-nginx
Name:                     deploy-nginx
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=myapp
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.111.154.75
IPs:                      10.111.154.75
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30721/TCP
Endpoints:                10.244.104.32:80,10.244.166.175:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
[root@master yam_files]# kubectl get svc -owide
NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE     SELECTOR
deploy-nginx      NodePort    10.111.154.75    <none>        80:30721/TCP                    6h30m   app=myapp
kubernetes        ClusterIP   10.96.0.1        <none>        443/TCP                         10d     <none>
readiness         ClusterIP   10.107.242.111   <none>        80/TCP                          2d3h    app=my-pod
springboot-live   NodePort    10.98.119.36     <none>        8080:31180/TCP,8081:31181/TCP   29h     app=springboot
[root@master yam_files]# kubectl get pods -owide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
my-deployment-8cd4898cd-46g5n   1/1     Running   0          5h11m   10.244.166.175   node1   <none>           <none>
my-deployment-8cd4898cd-mhkbs   1/1     Running   0          5h11m   10.244.104.32    node2   <none>           <none>

查看防火墙ipvs规则,可以看到,172.17.0.1:30721对应的是上面my-deployment的两个pod的80端口,其中172.17.0.1是docker网桥地址,常用于节点内部的容器通信,而10开头的是k8s内部的网络地址,用于pod和服务之间通信

[root@master yam_files]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:30721 rr
  -> 10.244.104.32:80             Masq    1      0          0         
  -> 10.244.166.175:80            Masq    1      0          0         
TCP  172.17.0.1:31181 rr
TCP  192.168.122.1:30721 rr
  -> 10.244.104.32:80             Masq    1      0          0         
  -> 10.244.166.175:80            Masq    1      0          0         
ClusterIP 

建立一个clusterIP的service,用来管理两个pod

cat service_test.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    run: my-nginx
spec:
  type: ClusterIP
  selector: 
    run: my-nginx
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80

[root@master service]# cat pod_test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: my-nginx

spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:  
        - containerPort: 80  

查看service和endpoint,发现nginx-service成功连接到两个pod的80端口 

kubectl get svc
NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
nginx-service     ClusterIP   10.98.178.209    <none>        80/TCP                          70s
[root@master service]# kubectl get pods -owide
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
my-nginx-5684588fff-8djq6   1/1     Running   0          53m   10.244.104.33    node2   <none>           <none>
my-nginx-5684588fff-k5dp6   1/1     Running   0          53m   10.244.166.176   node1   <none>           <none>
[root@master service]# kubectl get ep
NAME              ENDPOINTS                            AGE
nginx-service     10.244.104.33:80,10.244.166.176:80   40m

验证是否可以进行DNS解析: Kubernetes 使用特定的 DNS 命名约定来访问服务,这是为了确保服务发现的统一和规范化。具体格式为 service-name.namespace.svc.cluster.local,可以看到解析出了这个svc的地址:10.98.178.209

kubectl exec -it my-nginx-5684588fff-8djq6 -- /bin/bash
root@my-nginx-5684588fff-8djq6:/# curl nginx-service.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@my-nginx-5684588fff-8djq6:/# nslookup nginx-service.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	nginx-service.default.svc.cluster.local
Address: 10.98.178.209
四层负载均衡

 OSI模型为七层,物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,其中svc工作在OSI模型的第四层,传输层,基于ip和端口来转发和负载均衡。而七层负载均衡器工作在应用层,根据 HTTP/HTTPS 请求的内容(如 URL、头信息、Cookie 等)来进行流量分配。Kubernetes 中的 Ingress 控制器(如 Nginx Ingress Controller、Traefik 等)就属于七层负载均衡器,它们可以基于 HTTP 请求的路径、主机头等信息进行更细粒度的流量管理。

NodePort 

写一个nodePort的service

[root@master service]# ss -antulp | grep :30080
[root@master service]# cat nodeport_service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-nodeport
  labels:
    run: my-nginx-nodeport

spec:
  selector:
    run: my-nginx-nodeport
  type: NodePort
  ports:
  - nodePort: 30380
    targetPort: 80
    protocol: TCP
    port: 80

写一个deployment

[root@master service]# cat nodeport_test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-nodeport

spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx-nodeport
  template:
    metadata:
      name:
      labels:
        run: my-nginx-nodeport
    spec:
      containers:
      - name: my-nginx-nodeport-coontainer
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

 查看发现,端口已经开始监听,防火墙规则已经设置

[root@master service]# kubectl get svc
NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
deploy-nginx        NodePort    10.111.154.75    <none>        80:30721/TCP                    9h
kubernetes          ClusterIP   10.96.0.1        <none>        443/TCP                         11d
my-nginx-nodeport   NodePort    10.99.238.240    <none>        80:30380/TCP                    16m
[root@master service]# ss -antulp | grep :30380
tcp    LISTEN     0      128       *:30380                 *:*                   users:(("kube-proxy",pid=31181,fd=17))
[root@master service]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.99.238.240:80 rr
  -> 10.244.104.34:80             Masq    1      0          0         
  -> 10.244.166.177:80            Masq    1      0          0         

service endpoint已经和正在运行的pod关联上

[root@master service]# kubectl get ep
NAME                ENDPOINTS                            AGE
deploy-nginx        <none>                               9h
kubernetes          100.64.252.90:6443                   11d
my-nginx-nodeport   10.244.104.34:80,10.244.166.177:80   9m31s
nginx-service       <none>                               87m
readiness           <none>                               2d6h
springboot-live     <none>                               32h
[root@master service]# kubectl get pods -owide
NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
my-nginx-nodeport-5c8769d7f8-b7jzk   1/1     Running   0          18m   10.244.104.34    node2   <none>           <none>
my-nginx-nodeport-5c8769d7f8-qkzpb   1/1     Running   0          18m   10.244.166.177   node1   <none>           <none>

 此时在外部请求物理节点ip加上端口,就可以访问service了,同时进入一个pod,可以验证dns解析,解析出来的service ip是10.99.238.340

[root@master service]# curl 100.64.252.90:30380
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

root@master service]# kubectl exec -it my-nginx-nodeport-5c8769d7f8-b7jzk -- /bin/bash
root@my-nginx-nodeport-5c8769d7f8-b7jzk:/# nslookup my-nginx-nodeport.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	my-nginx-nodeport.default.svc.cluster.local
Address: 10.99.238.240

 在 Kubernetes 中,DNS 解析的工作机制是通过集群内部的 CoreDNS 或 kube-dns 服务来完成的。这些服务运行在 Kubernetes 集群内,并且默认只对集群内部的 Pod 提供 DNS 解析服务。这是为什么在 Kubernetes 的 master 节点(或者任何集群外部的机器)上直接运行 nslookup 命令会失败,而在 Pod 内运行则成功的原因。

每个 Pod 都配置了 DNS 解析配置,通常在 /etc/resolv.conf 文件中指定了集群的 DNS 服务器地址(如 10.96.0.10)。在 Kubernetes 的 master 节点或其他集群外部节点上直接运行 nslookup 命令,会请求系统默认的 DNS 服务器,而不是 Kubernetes 集群内部的 DNS 服务器。这些 DNS 服务器不知道 Kubernetes 集群内部的服务 DNS 名称(如 my-nginx-nodeport.default.svc.cluster.local),因此无法解析这些名称。

ExternalName

ExternalName 服务是一种特殊类型的服务,它将集群内部的服务名称解析为外部 DNS 名称。这种服务类型允许你将 Kubernetes 服务映射到外部(集群外部)的服务,而无需进行任何实际的流量转发。ExternalName 服务只是一个 DNS 别名。通过externalName,可以轻松的从集群的内部访问外部数据库、API或其他服务,无需在kubernetes中配置ingress或loadBalancer,只需配置一个DNS别名。

创建一个client.yaml和一个externalName的service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client

spec:
  replicas: 1
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
      - name: busybox
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh","-c","sleep 36000"]

 [root@master service]# cat client_svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: client-svc
spec:
  type: ExternalName
  externalName: nginx-svc.nginx-ns.svc.cluster.local
  ports:
  - name: http
    port: 80
    targetPort: 80

正常的DNS解析的地址是: <service-name>.<namespace-name>.svc.cluster.local

如果要访问另一个命名空间下的服务,如nginx-ns命名空间中的nginx-svc服务,则可能需要配置一些复杂的流量转发规则,通过以上的ExternalName,就可以不进行集群内流量转发,直接DNS解析。可以看到client-svc并没有endpoint,但是有一个externalname的字段

[root@master service]# kubectl get ep
NAME                ENDPOINTS                            AGE
deploy-nginx        <none>                               24h
kubernetes          100.64.252.90:6443                   11d
my-nginx-nodeport   10.244.104.34:80,10.244.166.177:80   14h
nginx-service       <none>                               16h
readiness           <none>                               2d21h
springboot-live     <none>                               47h
[root@master service]# kubectl describe svc client-svc
Name:              client-svc
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ExternalName
IP Families:       <none>
IP:                
IPs:               <none>
External Name:     nginx-svc.nginx-ns.svc.cluster.local
Port:              http  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

 在nginx-ns命名空间下建立pods和service,发现他们正常运行

[root@master service]# cat nginx_svc.yaml 
apiVersion: v1 
kind: Service 
metadata: 
 name: nginx-svc 
 namespace: nginx-ns 
spec: 
 selector: 
   app: nginx 
 ports: 
 - name: http 
   protocol: TCP 
   port: 80 
   targetPort: 80
[root@master service]# cat server_nginx.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
 name: nginx 
 namespace: nginx-ns 
spec: 
 replicas: 1 
 selector: 
   matchLabels: 
     app: nginx
 template: 
   metadata: 
     labels: 
       app: nginx 
   spec: 
     containers: 
     - name: nginx 
       image: nginx 
       imagePullPolicy: IfNotPresent
[root@master service]# kubectl get pods -n nginx-ns -owide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nginx-787f54657b-r5hqz   1/1     Running   0          10m   10.244.166.180   node1   <none>           <none>
[root@master service]# kubectl get svc -n nginx-ns
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx-svc   ClusterIP   10.106.161.203   <none>        80/TCP    58s
[root@master service]# kubectl get ep -n nginx-ns
NAME        ENDPOINTS           AGE
nginx-svc   10.244.166.180:80   7m9s

另一个namespace下面的服务启动以后,从default的命名空间的pod进入,看能不能请求到另一个命名空间下的pod

 docker网桥

为什么第一个yaml也是定义了nodePort服务,但是防火墙规则里面写的是docker网桥的地址呢?

172.17.0.1是docker默认网桥的网关ip地址,通常用于节点内部的容器通信,Kubernetes 使用 Docker 作为容器运行时(在使用 Docker 的情况下),因此,节点上的所有容器(包括 Kubernetes Pod)都通过这个网桥地址进行通信。

Kubernetes 使用 kube-proxy 来管理服务的流量。kube-proxy 可以有不同的模式,如 iptablesipvs。当使用 ipvs 模式时,kube-proxy 设置 IPVS 规则来处理服务的流量转发。这些规则会在节点内部通过 Docker 网桥地址进行配置,以确保流量能够正确转发到相应的 Pod。

当一个外部请求通过NodePort端口进入节点的时候,这个请求会被路由到docker网桥地址,ipvs捕获了到达172.17.0.1:30721的流量,然后通过轮询”rr“的方式转发给两个pod。

而正常的请求,无论是发送到哪一个物理节点上,都会由kube-proxy处理,在 IPVS 模式下,kube-proxy 使用 IPVS 规则来管理服务的负载均衡和流量转发。

[root@master yam_files]# curl http://100.64.252.90:30721
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@master yam_files]# curl http://100.64.212.7:30721
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@master yam_files]# curl http://100.64.147.209:30721
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
ipvs规则

在 Kubernetes 集群中使用 IPVS 进行负载均衡时,可以配置不同的调度算法。IPVS 支持多种调度算法,如轮询 (round-robin, rr)、最少连接 (least-connection, lc) 等。下面是一些常用的调度算法和如何配置 IPVS 规则的方法。

常用调度算法

  1. rr (round-robin): 轮询,每个后端服务器轮流接收请求。
  2. lc (least-connection): 最少连接,具有最少活动连接的后端服务器优先接收请求。
  3. wlc (weighted least-connection): 加权最少连接,考虑权重的最少连接。
  4. lblc (locality-based least-connection): 基于局部性的最少连接。
  5. lblcr (locality-based least-connection with replication): 带复制的基于局部性的最少连接。
  6. dh (destination-hashing): 目标哈希,将请求根据目标 IP 进行哈希并分配到后端服务器。
  7. sh (source-hashing): 源哈希,将请求根据源 IP 进行哈希并分配到后端服务器。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值