docker+k8s基礎篇五


Docker+K8s基礎篇(五)

 


 

  • service資源介紹
    • A:service資源的工作特性
  • service的使用
    • A:service字段介紹
    • B:ClusterIP的簡單使用
    • C:NodePort的簡單使用
    • D:LoadBalancer和ExternalName
    • E:無頭service

♣一:service資源介紹

A:service資源的工作特性:

kubernetes的service資源:
在整個k8s集群的節點中pods資源是最小的對象,這些對象是提供真正服務的重要組成部分,當我們需要通過外部進行訪問的時候因各pod資源提供的訪問端點是不一致的,我們就需要設定一個固定的訪問端點來提供訪問,這個訪問端點,是存在pod至上和控制器之下的中間層,這個中間層將叫service,service會嚴格依賴k8s上的一個重要組件叫coredns(新版本)和kube-dns(老版本1.11之前的版本),所以我們在部署的時候必需要部署coredes或者kube-dns。
kubernetes要想給客戶端提供網絡功能,需要依賴於第三方方案,這種方案在新版本中可以通過cni(容器網絡插件標准接口)來接入任何遵循這種標准的第三方方案,例如我們使用到的flannel。
kubernetes的三類ip地址:
1:node網絡
2:pod網絡
node和pod的地址是實際存在且配置了。
3:cluater(集群地址)或者叫做service地址,這種地址是虛擬的地址(virtual ip),這些地址沒有出現在接口之上,僅僅只是出現在service的規則當中。
在每個節點之上都工作了kube-proxy組件,這個組件將會實時監視service資源中的變動信息,這個監視是由kube-proxy通過一種固有的方式(watch)請求方式來實現的,一旦service的資源發生變動,kube-proxy都要將其轉換為當前節點之上的能夠被service調度的規則之上(這個規則可能是iptables或者ipvs規則,取決於service的實現方式)
service的實現方式在k8s上有三種模型:

        
1:userspace(用戶空間)
  當用戶的訪問請求會先到達service上,由service將其轉換監聽在某個套接字上的用戶空間內的kube-proxy,接下來kube-proxy處理完成之后再轉給service代理至這個service各個相          關聯的pod之上,實現調度。

  這種模型效率不高,因為用戶請求要進過工作在內核上的service轉給工作各個“主機”之上用戶空間的kube-proxy,kube-proxy將其封裝成請求報文發送給內核空間的service資源,         有service的規則在調度至各個pod資源上。

        
2:iptabeles:
   當前用戶請求直接請求service的IP,這個請求會被工作在本地內核空間中的service所截取,然后直接調度給相關聯的pod,而整個調度都是基於iptables規則來完成的。

        
3:ipvs:
      和iptables一樣,只不過規則換成了ipvs規則。
在配置k8s的時候設定k8s工作在什么模式之下,就會生成對應模式的規則,1.1之前默認是userspace,1.11默認使用的ipvs,如果ipvs沒有激活,就會降級為iptables。
當集群中的pods資源發生了改變,這個信息會立馬反應到apiservice之上,因為這個改變會直接存儲在apiservice的ectd當中,這種變化也會立即觸發kube-proxy並發送給service資源中將其轉換為iptables或者ipvs規則,這些轉換都是動態且實時的。

♣二:service的使用:

A:service字段介紹:

[root@www kubeadm]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   77m
在我們初始化集群的時候已然幫忙創建了一個名稱叫kubernetes的service資源,這個資源很重要,是保證我們service和集群節點之間聯系的,而且10.96.0.1是面向集群內部的地址。
[root@www kubeadm]# kubectl explain svc  也是包含5個一級字段
KIND:     Service
VERSION:  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@www kubeadm]# kubectl explain svc.spec.ports(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>
     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>
     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-  service的端口
     The port that will be exposed by this service.

   protocol     <string>   node端口    
     The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default
     is TCP.
 
   targetPort   <string>   pods端口
     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

[root@www kubeadm]# kubectl explain svc.spec.selector (我們需要關聯到哪些pods資源上)
KIND:     Service
VERSION:  v1

FIELD:    selector <map[string]string>

DESCRIPTION:
     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/


spec.clusterIP(指定固定的ip,創建之后無法改變)

[root@www kubeadm]# kubectl explain svc.spec.type  (service的類型)
KIND:     Service
VERSION:  v1

FIELD:    type <string>

DESCRIPTION:
     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
service資源的字段介紹

svc.spec.type字段類型:

類型一共分為4種:
1:ExternalName(把集群外部的服務引入到集群內部直接使用);

2:ClusterIP;

3:NodePort(接入外部);

4:LoadBalancer(支持lbaas負載均衡的一鍵調度)

B:ClusterIP的簡單使用:

[root@www TestYaml]# cat redis-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:
    app: redis
  clusterIP: 10.98.98.98  (指定ip創建的時候需要注意網段和地址沖突問題)
  type: ClusterIP
  ports:
  - port: 6379  
    targetPort: 6379
[root@www TestYaml]# kubectl apply -f redis-svc.yaml
service/redis created
[root@www TestYaml]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    102m
redis        ClusterIP   10.98.98.98   <none>        6379/TCP   14s  可以看到redis的ip和端口是配置文件指定的ip和端口
[root@www TestYaml]# 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.98.98.98","...
Selector:          app=redis
Type:              ClusterIP
IP:                10.98.98.98
Port:              <unset>  6379/TCP  指定的service端口
TargetPort:        6379/TCP   指定的pod端口
Endpoints:         <none>
Session Affinity:  None
Events:            <none>
這里需要說明的是service不會直接到pod,而是需要進過中間層Endpoints的,Endpoints也是k8s上標准的對象,再由Endpoints關聯至pods資源上。
ClusterIP案例

C:NodePort的簡單使用:

[root@www TestYaml]# cat NodePort.svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
  clusterIP: 10.99.99.99
  type: NodePort
  ports:
  - port: 8088
    targetPort: 8088
    nodePort: 30008  從30000到32767之間的都可以,默認是動態分配的
[root@www TestYaml]# kubectl apply -f NodePort.svc.yaml
service/myapp created
[root@www TestYaml]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP          125m
myapp        NodePort    10.99.99.99   <none>        8088:30008/TCP   22s  service的8088端口映射成node上的30008
redis        ClusterIP   10.98.98.98   <none>        6379/TCP         23m
通過此種方式創建的pod就可以在外部直接訪問了,只不過要進過好幾級轉換,先是port,再是protocol,在轉換到targetPort上。
NodePort案例

D:LoadBalancer和ExternalName:

        

如果購買了阿里雲平台的環境虛擬機(帶ibaas負載均衡服務),你在上面搭建了一共k8s的集群服務,k8s會自動去調用雲平台的ibaas服務,用軟件的方式去把用戶的訪問請求負載調度至后端的任意一個node節點上,在由節點上的service服務再負載調度至后端的任意一個pod之上,整個過程都是自動的,而且是兩級負載均衡調度。

ExternalName:

我們在構建pods的時候本來就是層級關系的,例如db被tomcat訪問,tomcat被nginx訪問,這種被訪問的形式本身就是一種client的存在,那如果是我們的nginx服務在集群外部的某台集群上,想nginx能訪問到集群內部的tomcat就需要使用ExternalName,在創建yaml文件的時候ExternalName是一個真實有效且能被dns所解析的服務名,然后用戶的訪問請求走外部的nginx,nginx在發送請求報文給集群內部的nodeIP到service,有service調度到后端的pod(tomcat),pod在返回給service,最后返回到nginx上,實現訪問,但是此種方式用的不多。

[root@www kubeadm]# kubectl explain svc.spec.externalName (externalName只能是類型為ExternalName的時候才有效)
KIND:     Service
VERSION:  v1

FIELD:    externalName <string>

DESCRIPTION:
     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.
[root@www kubeadm]#
externalName字段說明
[root@www kubeadm]# kubectl explain svc.spec.sessionAffinity(svc還支持sessionAffinity)
KIND:     Service
VERSION:  v1

FIELD:    sessionAffinity <string>

DESCRIPTION:
     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
     這里的session支持兩種,一個是ClientIP,將來自同一個ip訪問的請求始終調度到同一個pod上。
     None就是默認的隨機調度。
sessionAffinity字段說明

E:無頭service:

無頭service,即值創建service的時候不指定clusterIP,此時用戶的訪問請求不再是訪問clusterIP而是轉而訪問pod上的ip

[root@www TestYaml]# kubectl explain svc.spec.clusterIP
KIND:     Service
VERSION:  v1

FIELD:    clusterIP <string>

DESCRIPTION:
     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
     在指定clusterIP的時候可以指定為none(格式是""即可)
案例:
[root@www TestYaml]# cat NodePort.svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
  clusterIP: None  不指定ip
  ports:
  - port: 8088
    targetPort: 8088
[root@www TestYaml]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP    81m
myapp        ClusterIP   None         <none>        8088/TCP   9s  可以看到ip是none標記
[root@www TestYaml]# kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   83m   我們直接去解析coredns的ip就能直接看到pod ip的解析記錄
[root@www TestYaml]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10  我們直接解析coredns的ip看看下解析記錄

; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> -t A myapp.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60422
;; 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:
;myapp.default.svc.cluster.local. IN    A

;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN   A       10.244.2.9   可以看到這里有三個記錄,ip分別是2.9,2.8,1.8
myapp.default.svc.cluster.local. 5 IN   A       10.244.2.8
myapp.default.svc.cluster.local. 5 IN   A       10.244.1.8

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 7月 14 11:29:23 CST 2019
;; MSG SIZE  rcvd: 201

[root@www TestYaml]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE    IP           NODE                       NOMINATED NODE   READINESS GATES
myapp-9758dcb6b-hl957   1/1     Running   0          4m6s   10.244.2.8   www.kubernetes.node1.com   <none>           <none>
myapp-9758dcb6b-z8rk6   1/1     Running   0          4m6s   10.244.2.9   www.kubernetes.node1.com   <none>           <none>
myapp-9758dcb6b-zl5jt   1/1     Running   0          4m6s   10.244.1.8   www.kubernetes.node2.com   <none>           <none>
上面的2.9,2.8,1.8對應的ip就是pod的ip,這樣我們得出的結論就是當service沒有clusterip的時候就會通過coredns來解析並轉發到后端的pod之上。
無頭service案例

service很好用,但是也是存在缺陷的,當面我們創建了service的時候,用戶訪問需要進行兩級轉換,如果是阿里雲的lbaas則是兩級調度,其實我們看到的是兩級轉換,但是落到ipvs或者iptebles之上就是四層調度。因為ipvs和iptables都是四層的,如果我們建立的是https服務的話,例如https對應的名稱是myapp,那么你的每一個myapp都要配置成htpps的主機,因為ipvs或者iptables自身是無法卸載https會話的。
kubernetes還有一種引入外部流量的方式,叫ingress(是一種7層調度器)將外部的流量引入到內部來,但是也是無法脫離service的工作,必需要用pod7層功能的應用來調度,起能提供的應用有nginx,haprxoy等。在kubernetes之上應用比較多的是nginx,當然還有別的應用有各自相應的優勢。


免責聲明!

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



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