Kubernetes 學習10 Service資源


一、Service對應組件關系

  1、在kubernetes平台之上,pod是有生命周期的,所以為了能夠給對應的客戶端提供一個固定的訪問端點,因此我們在客戶端和服務Pod之間添加一個固定的中間層,這個中間層我們稱之為Service,這個Service的真正工作還要嚴重依賴於我們k8s之上部署的附件。稱之為kubernetes的dns服務,不同的k8s版本實現可能不同,較新版本中默認使用的CoreDNS,1.11版本之前版本用的kube-dns,Service名稱解析是強依賴於DNS附件的,因此我們部署完k8s以后必須要去部署一個CoreDNS或者kube-dns。

  2、k8s要想能夠向客戶端提供網絡功能,它需要依賴於第三方的方案,這種第三方方案可通過(至少較新版本中) cni(容器網絡插件標准的接口)來進行接入任何遵循這種插件標准的第三方方案。當然,這里面的方案有很多個,像我們之前部署的flannel,canal等。

  3、在k8s中有三類網絡地址,分別是節點網絡(node network),pod網絡(pod network),集群網絡(cluster network或Service network)前兩種網絡都是實實在在的存在純硬件設備或軟件模擬的,都是存在的。后一種集群網絡 的IP稱之為virtual IP,因為這些IP沒有實實在在配置在某個接口上。它僅是出現在Service的規則中。

  4、那么Service是什么呢?在每一個節點上我們工作了一個組件叫kube-proxy,此組件將始終監視着master上的api server中有關Service的資源變動信息,這種是通過k8s中的固有的一種請求方法watch(監視)來實現的。一旦有Service的資源的變動,包括創建,kube-proxy都要將其轉換為當前節點之上的能夠實現service資源調度,包括將用戶請求調度到后端特定pod資源之上的規則中,這個規則有可能是iptables,也有可能是ipvs,取決於Service的實現方式

  5、Service實現方式在k8s上有三種模型

    a、userspace,來自內部的請求client pod請求某個服務時一定先到達當前節點內核空間的iptables規則,也就是service的規則。這個service的工作方式是請求到達service后由service先把它轉為本地監聽在某個套接字上的用戶空間的kube-proxy,它來負責處理,處理完后再轉給service IP,最終代理至於service相關聯的各個pod實現調度。可以發現請求由client pod發給service,service還要回到監聽在這個端口上的kube-proxy,由kube-proxy來進行分發,所以kube-proxy是工作在用戶空間的進程。所以其被稱之為userspace。這種方式效率很低,原因在於先要到內核空間然后再到當前主機的用戶空間kube-proxy,由kube-proxy封裝其報文代理完以后再回到內核空間然后由iptables規則進行分發。

    

    b、iptables,后來就到了第二種方式,方法是,客戶端ip請求時直接請求service的ip,這個請求報文被本地內核空間中的service規則所截取,進而直接調度給server pod,這種方式直接工作在內核空間由iptables規則直接負責調度。

    c、ipvs,client pod請求到達內核空間后直接由ipvs規則來調度,直接調度給pod網絡地址范圍內的相關Pod資源。

  6、我們在安裝並配置k8s的時候設定service工作在什么模式下他就會生成對應的什么模式的規則。1.10及之前的版本用的是iptables,再往前是1.1之前用的是userspace,1.11默認使用的是ipvs,若ipvs未被激活則默認為iptables。如果某個服務背后的Pod資源發生改變,比如service的標簽選擇器適用的版本又多一個那么這個pod適用的信息會立即反應到apiserver上,因為多個pod信息是會存在apiserver的etcd中,而后kube-proxy能夠檢測到這種變化並將其立即轉化為service規則。所以他的轉化是動態實時的,如果刪除了一個pod並且這個pod沒有被重構,這個狀態結果會反饋至apiserver的etcd中,這種變化被kube-proxy watch到了,然后立即將其轉換成iptables規則。

  7、service到pod是有一個中間層的,service不會直接到pod,service會先到endpoints ,endpoints也是一個標准的k8s對象。其相當於是pod 地址 + 端口,然后再由endpoint關聯至后端的pod,但是我們理解的話可以直接理解為從service直接到pod就行,但事實上我們可以為service手動創建endpoints資源。

    

 

二、service創建

  1、使用清單創建service資源,以前創建service都是通過expose命令來創建,現在通過使用清單來創建。

[root@k8smaster ~]# kubectl explain svc
KIND:     Service
VERSION:  v1 #核心資源v1

DESCRIPTION:
     Service is a named abstraction of software service (for example, mysql)
     consisting of local port (for example 3306) that the proxy listens on, and
     the selector that determines which pods will answer requests sent through
     the proxy.

FIELDS:
   apiVersion    <string>
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#resources

   kind    <string>
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds

   metadata    <Object>
     Standard object's metadata. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata

   spec    <Object>
     Spec defines the behavior of a service.
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

   status    <Object>
     Most recently observed status of the service. Populated by the system.
     Read-only. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

[root@k8smaster ~]# kubectl explain svc.spec
KIND:     Service
VERSION:  v1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec defines the behavior of a service.
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

     ServiceSpec describes the attributes that a user creates on a service.

FIELDS:
   clusterIP    <string> #默認是自動分配,也可自己指定
     clusterIP is the IP address of the service and is usually assigned randomly
     by the master. If an address is specified manually and is not in use by
     others, it will be allocated to the service; otherwise, creation of the
     service will fail. This field can not be changed through updates. Valid
     values are "None", empty string (""), or a valid IP address. "None" can be
     specified for headless services when proxying is not required. Only applies
     to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is
     ExternalName. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   externalIPs    <[]string>
     externalIPs is a list of IP addresses for which nodes in the cluster will
     also accept traffic for this service. These IPs are not managed by
     Kubernetes. The user is responsible for ensuring that traffic arrives at a
     node with this IP. A common example is external load-balancers that are not
     part of the Kubernetes system.

   externalName    <string>
     externalName is the external reference that kubedns or equivalent will
     return as a CNAME record for this service. No proxying will be involved.
     Must be a valid RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) and
     requires Type to be ExternalName.

   externalTrafficPolicy    <string>
     externalTrafficPolicy denotes if this Service desires to route external
     traffic to node-local or cluster-wide endpoints. "Local" preserves the
     client source IP and avoids a second hop for LoadBalancer and Nodeport type
     services, but risks potentially imbalanced traffic spreading. "Cluster"
     obscures the client source IP and may cause a second hop to another node,
     but should have good overall load-spreading.

   healthCheckNodePort    <integer>
     healthCheckNodePort specifies the healthcheck nodePort for the service. If
     not specified, HealthCheckNodePort is created by the service api backend
     with the allocated nodePort. Will use user-specified nodePort value if
     specified by the client. Only effects when Type is set to LoadBalancer and
     ExternalTrafficPolicy is set to Local.

   loadBalancerIP    <string>
     Only applies to Service Type: LoadBalancer LoadBalancer will get created
     with the IP specified in this field. This feature depends on whether the
     underlying cloud-provider supports specifying the loadBalancerIP when a
     load balancer is created. This field will be ignored if the cloud-provider
     does not support the feature.

   loadBalancerSourceRanges    <[]string>
     If specified and supported by the platform, this will restrict traffic
     through the cloud-provider load-balancer will be restricted to the
     specified client IPs. This field will be ignored if the cloud-provider does
     not support the feature." More info:
     https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/

   ports    <[]Object>  #我們打算把哪個端口與后端容器端口建立關聯關系
     The list of ports that are exposed by this service. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   publishNotReadyAddresses    <boolean>
     publishNotReadyAddresses, when set to true, indicates that DNS
     implementations must publish the notReadyAddresses of subsets for the
     Endpoints associated with the Service. The default value is false. The
     primary use case for setting this field is to use a StatefulSet's Headless
     Service to propagate SRV records for its Pods without respect to their
     readiness for purpose of peer discovery.

   selector    <map[string]string> #關聯到哪些pod資源上
     Route service traffic to pods with label keys and values matching this
     selector. If empty or not present, the service is assumed to have an
     external process managing its endpoints, which Kubernetes will not modify.
     Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if
     type is ExternalName. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/

   sessionAffinity    <string>
     Supports "ClientIP" and "None". Used to maintain session affinity. Enable
     client IP based session affinity. Must be ClientIP or None. Defaults to
     None. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   sessionAffinityConfig    <Object>
     sessionAffinityConfig contains the configurations of session affinity.

   type    <string>
     type determines how the Service is exposed. Defaults to ClusterIP. Valid
     options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
     "ExternalName" maps to the specified externalName. "ClusterIP" allocates a
     cluster-internal IP address for load-balancing to endpoints. Endpoints are
     determined by the selector or if that is not specified, by manual
     construction of an Endpoints object. If clusterIP is "None", no virtual IP
     is allocated and the endpoints are published as a set of endpoints rather
     than a stable IP. "NodePort" builds on ClusterIP and allocates a port on
     every node which routes to the clusterIP. "LoadBalancer" builds on NodePort
     and creates an external load-balancer (if supported in the current cloud)
     which routes to the clusterIP. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
[root@k8smaster ~]# kubectl explain svc.spec.ports
KIND:     Service
VERSION:  v1

RESOURCE: ports <[]Object>

DESCRIPTION:
     The list of ports that are exposed by this service. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

     ServicePort contains information on service's port.

FIELDS:
   name    <string> #ports的名稱
     The name of this port within the service. This must be a DNS_LABEL. All
     ports within a ServiceSpec must have unique names. This maps to the 'Name'
     field in EndpointPort objects. Optional if only one ServicePort is defined
     on this service.

   nodePort    <integer> #指定節點上的端口,只有類型為NodePort時才生效。
     The port on each node on which this service is exposed when type=NodePort
     or LoadBalancer. Usually assigned by the system. If specified, it will be
     allocated to the service if unused or else creation of the service will
     fail. Default is to auto-allocate a port if the ServiceType of this Service
     requires one. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport

   port    <integer> -required-  #這個服務對外提供服務的端口
     The port that will be exposed by this service.

   protocol    <string> #協議,默認tcp
     The IP protocol for this port. Supports "TCP" and "UDP". Default is TCP.

   targetPort    <string> #容器的端口
     Number or name of the port to access on the pods targeted by the service.
     Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If
     this is a string, it will be looked up as a named port in the target Pod's
     container ports. If this is not specified, the value of the 'port' field is
     used (an identity map). This field is ignored for services with
     clusterIP=None, and should be omitted or set equal to the 'port' field.
     More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service

  2、kubectl explain svc.spec 中的type屬性有四種

    a、默認為ClusterIP表示給其分配一個集群ip地址僅用於集群內通信,使用此類型時只有兩個端口有用

      1)、port,service地址上的端口

      2)、targetPort,pod ip上的端口

[root@k8smaster manifests]# cat redis-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  slector:
    app: redis
    role: logstor
  clusterIP: 10.97.97.97 #指定固定ClusterIP
  type: ClusterIP
  ports:
  - port: 6379 #Service上的端口
    targetPort: 6379 #pod IP上的端口

[root@k8smaster manifests]# kubectl apply -f redis-svc.yaml 
service/redis created

[root@k8smaster manifests]# kubectl get svc -o wide --show-labels
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE       SELECTOR                 LABELS
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    11d       <none>                   component=apiserver,provider=kubernetes
redis        ClusterIP   10.97.97.97   <none>        6379/TCP   14s       app=redis,role=logstor   <none>

[root@k8smaster manifests]# kubectl describe svc redis
Name:              redis
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP
":"10.97.97.97","ports":[{"por...Selector:          app=redis,role=logstor
Type:              ClusterIP
IP:                10.97.97.97 #集群ip
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.1.45:6379  #匹配到的pod IP
Session Affinity:  None
Events:            <none>

      service創建完只要k8s上的集群的dns服務是存在的那么我們在這兒就可以直接解析他的服務名,服務名的解析方式為每一個服務創建完以后都會在集群的dns中自動動態添加一個資源記錄。不止一個,還會包含服務層svc記錄,A記錄等,添加完后就可以解析,資源記錄的格式為 SVC_NAME(服務名).NS_NAME(名稱空間名).DOMAIN.LTD.(域名后綴),而集群的默認域名后綴是svc.cluster.local. 因此如果我們沒改域名后綴,那么我們每一個服務創建完就是這種域名格式的,比如上面的資源記錄為  redis.default.svc.cluster.local

    b、NodePort 接入集群外部的流量,只有使用這種類型時才能使用nodePort,否則是沒用的

[root@k8smaster manifests]# kubectl get pods -o wide --show-labels
NAME                            READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
filebeat-ds-f5drs               1/1       Running   1          3d        10.244.1.44   k8snode1   app=filebeat,controller-revision-hash=2004607620,pod-template-generation=2,release=stable
filebeat-ds-n9hgz               1/1       Running   1          3d        10.244.2.34   k8snode2   app=filebeat,controller-revision-hash=2004607620,pod-template-generation=2,release=stable
liveness-httpget-pod            1/1       Running   2          6d        10.244.2.38   k8snode2   <none>
myapp-deploy-69b47bc96d-6x987   1/1       Running   1          4d        10.244.2.35   k8snode2   app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-f2cjq   1/1       Running   1          4d        10.244.1.47   k8snode1   app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-tlq6v   1/1       Running   1          4d        10.244.1.48   k8snode1   app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-vx46z   1/1       Running   1          4d        10.244.1.46   k8snode1   app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-vzdpt   1/1       Running   1          4d        10.244.2.36   k8snode2   app=myapp,pod-template-hash=2560367528,release=canary
nginx-deploy-5b595999-zgjgz     1/1       Running   0          3d        10.244.1.52   k8snode1   pod-template-hash=16151555,run=nginx-deploy
poststart-pod                   1/1       Running   30         6d        10.244.2.37   k8snode2   <none>
readiness-httpget-pod           1/1       Running   1          6d        10.244.2.39   k8snode2   <none>
redis-5b5d6fbbbd-kk782          1/1       Running   1          3d        10.244.1.45   k8snode1   app=redis,pod-template-hash=1618296668,role=logstor
[root@k8smaster manifests]# cat myapp.svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: 10.99.99.99 #指定固定ClusterIP
  type: NodePort
  ports:
  - port: 80 #Service上的端口
    targetPort: 80 #pod IP上的端口
    nodePort: 30080 #節點端口,也可以不指定讓系統動態分配
  
[root@k8smaster manifests]# kubectl apply -f myapp.svc.yaml 
service/myapp configured
[root@k8smaster manifests]# kubectl get svc -o wide --show-labels
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE       SELECTOR                   LABELS
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        12d       <none>                     component=apiserver,provider=kubernetes
myapp        NodePort    10.99.99.99   <none>        80:30080/TCP   13m       app=myapp,release=canary   <none>
redis        ClusterIP   10.97.97.97   <none>        6379/TCP       22h       app=redis,role=logstor     <none>
[root@k8smaster manifests]# kubectl describe svc myapp
Name:                     myapp
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"cl
usterIP":"10.99.99.99","ports":[{"nod...Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.99.99.99
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                10.244.1.46:80,10.244.1.47:80,10.244.1.48:80 + 2 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

      重新打開一個shell訪問集群任意一個節點,可以看到其還有負載均衡的效果,並且流量是經過了好幾級轉換,首先由nodeport轉換為service port,再由service轉成pod port。

[root@k8smaster ~]# while true; do curl http://192.168.10.10:30080/hostname.html; sleep 5; done
myapp-deploy-69b47bc96d-6x987
myapp-deploy-69b47bc96d-6x987
myapp-deploy-69b47bc96d-vx46z
myapp-deploy-69b47bc96d-f2cjq
myapp-deploy-69b47bc96d-6x987
myapp-deploy-69b47bc96d-vzdpt
myapp-deploy-69b47bc96d-vzdpt
^C

    c、LoadBalance(負載均衡及服務(LBaas)的一鍵調用):表示我們把k8s部署在虛擬機上而虛擬機是工作在雲環境中,而我們雲環境支持lb負載均衡器時使用。自動觸發在外部創建一個負載均衡器。 比如在阿里雲上買了四個虛擬主機,同時又買了阿里雲的LBaas的服務,在這四個vps上部署了k8s集群,然后這個k8s集群可以與其底層的公有雲IaaS公有雲的api相交互。其自身有這個能力,其能去調底層的IAAS雲計算層中的API,調的時候其能夠請求去創建一個外置的負載均衡器,比如我們有四個節點,一個master,正常工作的是三個節點,在這三個節點上都使用的是同一個nodePort對集群外提供服務,它會自動請求底層IAAS用純軟件的方式做一個負載均衡器並且為這個負載均衡器提供的配置信息是我們本機這三個節點的(注意是節點IP)節點端口上提供的相應服務,可以自動通過底層IAAS的api創建這個軟負載均衡器的時候提供后端有哪幾個節點,因此,回頭用戶通過雲計算環境之外的客戶端來訪問阿里雲的內部的LBAAS生成的負載均衡器時由該負載均衡器來調度到后端幾個節點的nodePort上,然后由nodeport轉發給service,再由service在集群內部負載均衡至pod上,因此可以發現其有兩級負載均衡,第一級是將用戶請求負載給多個node中的某一個,再由node通過service反代給集群內部的多個pod中的某一個。

      

    d、ExternalName :將集群外部的服務引入至集群內部在集群內部直接使用。假如我們有個k8s集群,有三個工作節點,三個節點上有一些節點上的pod資源是作為客戶端使用的,當此客戶端訪問某一服務時,此服務應該是由其它pod提供的,但有這種可能性,我們pod訪問服務集群中沒有,但是集群外有個服務,比如在我們的本地局域網環境中,但是是在k8s集群之外,或者在互聯網上有一個服務,比如dns等,我們期望這個服務讓集群內能夠訪問到,集群內一般用的都是私網地址,就算我們能夠將請求報文路由出去離開本地網絡到外部去那么外部響應報文也回不來,這樣干是沒法正常通信的,因此,ExternalName就是用來實現我們在集群中建一個服務(service),這個service的端點不是本地port而是service關聯到外部服務上去了因此我們客戶端訪問service時由service通過層級轉換,包括nodePort轉換請求到外部的服務中,外部服務先回給nodeIP,再由nodeIP轉交給service,再由service轉交給pod client,從而讓pod能夠訪問集群外部的服務。這樣就能讓我們集群內的pod像使用集群內部的服務一樣來使用集群外部的服務。對此種服務來講我們的cluster IP作用在於pod client內部解析時使用,更重要的是ExternalName此時很關鍵,因為ExternalName確實應該是一個name而不是一個IP,並且此name還必須要被我們dns服務所解析才能夠被訪問,所以ExternalName引入時有這么一個基本限制(了解一下就好),在svc.spec.中有如下字段

[root@k8smaster /]# kubectl explain svc.spec
KIND:     Service
VERSION:  v1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec defines the behavior of a service.
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

     ServiceSpec describes the attributes that a user creates on a service.

FIELDS:
   clusterIP    <string>
     clusterIP is the IP address of the service and is usually assigned randomly
     by the master. If an address is specified manually and is not in use by
     others, it will be allocated to the service; otherwise, creation of the
     service will fail. This field can not be changed through updates. Valid
     values are "None", empty string (""), or a valid IP address. "None" can be
     specified for headless services when proxying is not required. Only applies
     to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is
     ExternalName. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   externalIPs    <[]string>
     externalIPs is a list of IP addresses for which nodes in the cluster will
     also accept traffic for this service. These IPs are not managed by
     Kubernetes. The user is responsible for ensuring that traffic arrives at a
     node with this IP. A common example is external load-balancers that are not
     part of the Kubernetes system.

   externalName    <string> #這個類型也只有類型為externalName時才有用,這個name解析出來應該是一個記錄,這個CNAME能夠被我們真正的互聯網上的dns服務器或者能被我們本地服務器在根域解析為A記錄進行互相通信
     externalName is the external reference that kubedns or equivalent will
     return as a CNAME record for this service. No proxying will be involved.
     Must be a valid RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) and
     requires Type to be ExternalName.

   externalTrafficPolicy    <string>
     externalTrafficPolicy denotes if this Service desires to route external
     traffic to node-local or cluster-wide endpoints. "Local" preserves the
     client source IP and avoids a second hop for LoadBalancer and Nodeport type
     services, but risks potentially imbalanced traffic spreading. "Cluster"
     obscures the client source IP and may cause a second hop to another node,
     but should have good overall load-spreading.

   healthCheckNodePort    <integer>
     healthCheckNodePort specifies the healthcheck nodePort for the service. If
     not specified, HealthCheckNodePort is created by the service api backend
     with the allocated nodePort. Will use user-specified nodePort value if
     specified by the client. Only effects when Type is set to LoadBalancer and
     ExternalTrafficPolicy is set to Local.

   loadBalancerIP    <string>
     Only applies to Service Type: LoadBalancer LoadBalancer will get created
     with the IP specified in this field. This feature depends on whether the
     underlying cloud-provider supports specifying the loadBalancerIP when a
     load balancer is created. This field will be ignored if the cloud-provider
     does not support the feature.

   loadBalancerSourceRanges    <[]string>
     If specified and supported by the platform, this will restrict traffic
     through the cloud-provider load-balancer will be restricted to the
     specified client IPs. This field will be ignored if the cloud-provider does
     not support the feature." More info:
     https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/

   ports    <[]Object>
     The list of ports that are exposed by this service. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   publishNotReadyAddresses    <boolean>
     publishNotReadyAddresses, when set to true, indicates that DNS
     implementations must publish the notReadyAddresses of subsets for the
     Endpoints associated with the Service. The default value is false. The
     primary use case for setting this field is to use a StatefulSet's Headless
     Service to propagate SRV records for its Pods without respect to their
     readiness for purpose of peer discovery.

   selector    <map[string]string>
     Route service traffic to pods with label keys and values matching this
     selector. If empty or not present, the service is assumed to have an
     external process managing its endpoints, which Kubernetes will not modify.
     Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if
     type is ExternalName. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/

   sessionAffinity    <string>
     Supports "ClientIP" and "None". Used to maintain session affinity. Enable
     client IP based session affinity. Must be ClientIP or None. Defaults to
     None. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

   sessionAffinityConfig    <Object>
     sessionAffinityConfig contains the configurations of session affinity.

   type    <string>
     type determines how the Service is exposed. Defaults to ClusterIP. Valid
     options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
     "ExternalName" maps to the specified externalName. "ClusterIP" allocates a
     cluster-internal IP address for load-balancing to endpoints. Endpoints are
     determined by the selector or if that is not specified, by manual
     construction of an Endpoints object. If clusterIP is "None", no virtual IP
     is allocated and the endpoints are published as a set of endpoints rather
     than a stable IP. "NodePort" builds on ClusterIP and allocates a port on
     every node which routes to the clusterIP. "LoadBalancer" builds on NodePort
     and creates an external load-balancer (if supported in the current cloud)
     which routes to the clusterIP. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types

      另外,在我們svc實現負載均衡時還支持sessionAffinity(會話聯系,上述explain中有),默認值為None,因此其是隨機基於iptables來調度的,若我們將其值定義成ClientIP則表示把來自同一個客戶端IP的請求始終調度到同一個后端pod上去。

[root@k8smaster manifests]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/myapp patched

[root@k8smaster ~]# while true; do curl http://192.168.10.10:30080/hostname.html; sleep 3; done
myapp-deploy-67f6f6b4dc-tf2zm
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-tf2zm
myapp-deploy-67f6f6b4dc-tr4sn
myapp-deploy-67f6f6b4dc-lqpxm
myapp-deploy-67f6f6b4dc-lqpxm
#這是打補丁后后的結果
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
myapp-deploy-67f6f6b4dc-g694w
^C
[root@k8smaster manifests]# kubectl describe svc myapp
Name:                     myapp
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"cl
usterIP":"10.99.99.99","ports":[{"nod...Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.99.99.99
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                10.244.1.53:80,10.244.1.54:80,10.244.1.55:80 + 2 more...
Session Affinity:         ClientIP #可以看到我們打的補丁已經生效
External Traffic Policy:  Cluster
Events:                   <none>

三、還有一種service叫無頭service(headless),我們此前使用service一直是客戶端pod訪問service時解析的應該是service的名稱,每一個service應該有其名稱,並且其解析結果應該是其ClusterIP,一般解析ClusterIP一般只有一個。但是我們也可以這樣干,把中間層去掉,每一個pod也有其自己名稱,我們可以在解析service IP時,將其解析給后端的pod IP,這種service就叫無頭service。創建這種service時我們一樣只需要指定明確定義clusterIP,並且指定其值為None。

[root@k8smaster manifests]# cat myapp-svc-headless.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: "None"
  ports:
  - port: 80 #Service上的端口
    targetPort: 80 #pod IP上的端口


[root@k8smaster manifests]# kubectl apply -f myapp-svc-headless.yaml 
service/myapp-svc created
[root@k8smaster manifests]# kubectl get svc -o wide --show-labels
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE       SELECTOR                   LABELS
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        16d       <none>                     component=apiserver,provider=kubernetes
myapp        NodePort    10.99.99.99   <none>        80:30080/TCP   3d        app=myapp,release=canary   <none>
myapp-svc    ClusterIP   None          <none>        80/TCP         16s       app=myapp,release=canary   <none>
redis        ClusterIP   10.97.97.97   <none>        6379/TCP       4d        app=redis,role=logstor     <none>

#首先我們查看我們pod 的ip
[root@k8smaster manifests]# kubectl get pods -o wide
NAME                            READY     STATUS    RESTARTS   AGE       IP            NODE
filebeat-ds-f5drs               1/1       Running   1          7d        10.244.1.44   k8snode1
filebeat-ds-n9hgz               1/1       Running   1          7d        10.244.2.34   k8snode2
liveness-httpget-pod            1/1       Running   2          10d       10.244.2.38   k8snode2
myapp-deploy-67f6f6b4dc-g694w   1/1       Running   0          49m       10.244.1.55   k8snode1
myapp-deploy-67f6f6b4dc-k6rbp   1/1       Running   0          51m       10.244.1.54   k8snode1
myapp-deploy-67f6f6b4dc-lqpxm   1/1       Running   0          51m       10.244.2.40   k8snode2
myapp-deploy-67f6f6b4dc-tf2zm   1/1       Running   0          49m       10.244.2.41   k8snode2
myapp-deploy-67f6f6b4dc-tr4sn   1/1       Running   0          51m       10.244.1.53   k8snode1
nginx-deploy-5b595999-zgjgz     1/1       Running   0          7d        10.244.1.52   k8snode1
poststart-pod                   1/1       Running   54         10d       10.244.2.37   k8snode2
readiness-httpget-pod           1/1       Running   1          10d       10.244.2.39   k8snode2
redis-5b5d6fbbbd-kk782          1/1       Running   1          7d        10.244.1.45   k8snode1

#我們通過dig解析
[root@k8smaster ~]# dig -t A myapp-svc.default.svc.cluster.local. #這是我們svc的名字 @10.96.0.10 #這是我們coredns pod 的IP

; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7 <<>> -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41276
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION: #可以看到解析出了5條A記錄
myapp-svc.default.svc.cluster.local. 5 IN A    10.244.1.53
myapp-svc.default.svc.cluster.local. 5 IN A    10.244.1.54
myapp-svc.default.svc.cluster.local. 5 IN A    10.244.1.55
myapp-svc.default.svc.cluster.local. 5 IN A    10.244.2.40
myapp-svc.default.svc.cluster.local. 5 IN A    10.244.2.41

;; Query time: 75 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Sat May 25 10:26:14 CST 2019
;; MSG SIZE  rcvd: 319

  但是可以發現service有個問題,當我們定義完service后,我們要訪問service后端的pod需要多級調度或代理,因此如果我們要建一個https服務的話我們會發現我們每一個myapp都要配置為https的主機,事實上k8s還有一種引入集群外部流量的方式叫做 ingress ,我們service是4層調度,但是ingress是七層調度器,它利用一種七層pod實現將外部流量引入到內部來,但是事實上他也脫離不了service的工作。作為ingress作為七層調度時我們必須要用Pod中的運行的七層服務功能的應用來調度,可以用nginx,haproxy等等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM