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上有三種模型:html
1:userspace(用戶空間)
當用戶的訪問請求會先到達service上,由service將其轉換監聽在某個套接字上的用戶空間內的kube-proxy,接下來kube-proxy處理完成以後再轉給service代理至這個service各個相 關聯的pod之上,實現調度。node
這種模型效率不高,由於用戶請求要進過工做在內核上的service轉給工做各個「主機」之上用戶空間的kube-proxy,kube-proxy將其封裝成請求報文發送給內核空間的service資源, 有service的規則在調度至各個pod資源上。mysql
2:iptabeles:
當前用戶請求直接請求service的IP,這個請求會被工做在本地內核空間中的service所截取,而後直接調度給相關聯的pod,而整個調度都是基於iptables規則來完成的。nginx
3:ipvs:
和iptables同樣,只不過規則換成了ipvs規則。
在配置k8s的時候設定k8s工做在什麼模式之下,就會生成對應模式的規則,1.1以前默認是userspace,1.11默認使用的ipvs,若是ipvs沒有激活,就會降級爲iptables。
當集羣中的pods資源發生了改變,這個信息會立馬反應到apiservice之上,由於這個改變會直接存儲在apiservice的ectd當中,這種變化也會當即觸發kube-proxy併發送給service資源中將其轉換爲iptables或者ipvs規則,這些轉換都是動態且實時的。git
[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
svc.spec.type字段類型:redis
類型一共分爲4種:
1:ExternalName(把集羣外部的服務引入到集羣內部直接使用);sql
2:ClusterIP;後端
3:NodePort(接入外部);api
4:LoadBalancer(支持lbaas負載均衡的一鍵調度)tomcat
[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資源上。
[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上。
若是購買了阿里雲平臺的環境虛擬機(帶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]#
[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就是默認的隨機調度。
無頭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的時候,用戶訪問須要進行兩級轉換,若是是阿里雲的lbaas則是兩級調度,其實咱們看到的是兩級轉換,可是落到ipvs或者iptebles之上就是四層調度。由於ipvs和iptables都是四層的,若是咱們創建的是https服務的話,例如https對應的名稱是myapp,那麼你的每個myapp都要配置成htpps的主機,由於ipvs或者iptables自身是沒法卸載https會話的。
kubernetes還有一種引入外部流量的方式,叫ingress(是一種7層調度器)將外部的流量引入到內部來,可是也是沒法脫離service的工做,必須要用pod7層功能的應用來調度,起能提供的應用有nginx,haprxoy等。在kubernetes之上應用比較多的是nginx,固然還有別的應用有各自相應的優點。