1. 程式人生 > >Kubernetes學習筆記(四):服務

Kubernetes學習筆記(四):服務

## 服務介紹 服務是一種為一組相同功能的pod提供單一不變接入點的資源。當服務存在時,他的IP和埠不會改變。客戶端通過IP和埠建立連線,這些連線會被路由到任何一個pod上。如此,客戶端不需要知道每個單獨提供服務的pod地址,這些pod也可以隨時被建立、刪除。 服務通過標籤選擇器決定選擇哪些pod。 ### 準備映象 首先要準備一個能夠提供web服務的映象,作者將映象儲存到了阿里雲的映象倉庫。 #### web.go 監聽8000埠,接到請求輸出當前hostname ``` package main import ( "fmt" "log" "net/http" "os" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { hostname,_ := os.Hostname(); fmt.Fprintf(w,"this is %v\n",hostname) }) log.Fatal(http.ListenAndServe(":8000",nil)) } ``` #### Dockerfile 多步驟構建,有關與此以及Dockerfile的文章請見:Docker學習筆記(三):Dockerfile及多步驟構建映象 ``` FROM golang:1.14-alpine COPY goweb.go /src/ RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/goweb /src/goweb.go FROM alpine COPY --from=0 /bin/goweb /usr/local/bin/ RUN apk add --no-cache curl EXPOSE 8000 CMD ["/usr/local/bin/goweb"] ``` #### 構建、測試、推送 構建完成 ``` -> [[email protected]] [~/work/service] docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/goweb . Sending build context to Docker daemon 3.072kB ...... Successfully built 3db4b643ba0a Successfully tagged registry.cn-hangzhou.aliyuncs.com/orzi/goweb:latest ``` 執行映象,本地8001對映到容器的8000 ``` -> [[email protected]] [~] docker run --rm -d -p 8001:8000 registry.cn-hangzhou.aliyuncs.com/orzi/goweb 6241a412caeacfe5f025d20af154b2eba98555fcb2b2f55742154a9e6fa46817 ``` 請求本地的8001埠 ``` -> [[email protected]] [~] curl http://localhost:8001 this is 6241a412caea ``` 沒有問題,推送 ``` -> [[email protected]] [~] docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb The push refers to repository [registry.cn-hangzhou.aliyuncs.com/orzi/goweb] 8c5325633e9a: Pushed 3e207b409db3: Pushed latest: digest: sha256:2704d806836060237169ea59cfda238c50fc5e5881e15cb1230200b5c8b2f5a0 size: 739 ``` ### 建立服務 #### goweb-rs.yaml ``` apiVersion: apps/v1 kind: ReplicaSet metadata: name: goweb-rs spec: replicas: 2 selector: matchLabels: app: goweb template: metadata: labels: app: goweb spec: containers: - name: goweb image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb ports: - containerPort: 8000 ``` #### goweb-svc.yaml ``` apiVersion: v1 kind: Service metadata: name: goweb-svc spec: ports: - port: 80 # 服務的埠 targetPort: 8000 # 服務將連線轉發到容器的埠 selector: # 匹配此選擇器的都屬於這個服務 app: goweb ``` **建立一個名為goweb-svc的服務,它將在80埠接收請求並將連線路由到具有標籤app=goweb的pod的8000埠上。** #### 建立 ``` -> [[email protected]] [~] k create -f goweb-svc.yaml service/goweb-svc created -> [[email protected]] [~] k create -f goweb-rs.yaml replicaset.apps/goweb-rs created -> [[email protected]] [~] k get all NAME READY STATUS RESTARTS AGE pod/goweb-rs-6n6fw 1/1 Running 0 14m pod/goweb-rs-vkwqb 1/1 Running 0 14m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/goweb-svc ClusterIP 10.104.46.76 80/TCP 9s service/kubernetes ClusterIP 10.96.0.1 443/TCP 40h NAME DESIRED CURRENT READY AGE replicaset.apps/goweb-rs 2 2 2 14m ``` #### kubectl exec 訪問服務可以在叢集節點上直接訪問,如: ``` -> [[email protected]] [~] curl http://10.104.46.76 this is goweb-rs-vkwqb -> [[email protected]] [~] curl http://10.104.46.76 this is goweb-rs-6n6fw ``` 或者通過`kubectl exec`命令在已存在的pod上執行curl ``` -> [[email protected]] [~] k exec goweb-rs-vkwqb -- curl -s http://10.104.46.76 this is goweb-rs-vkwqb -> [[email protected]] [~] k exec goweb-rs-vkwqb -- curl -s http://10.104.46.76 this is goweb-rs-6n6fw ``` **雙橫槓表示kubectl命令項的結束,在此之後的是指要在pod內部執行的命令。這是為了避免異常和歧義,如果需要執行的指令中沒有橫槓,那麼可以不用雙橫槓。** #### sessionAffinity 使用`svc.spec.sessionAffinity`設定會話親和性,預設是None。指定為ClientIP會使來自同一個Client IP的請求轉發到同一個Pod上。 Kubernetes只支援這兩種親和性設定,不支援cookie,因為Kubernetes不在HTTP層面工作。服務處理TCP和UDP包,不關心其中的內容。 ### 一個服務暴露多個埠 建立一個多埠服務時,必須給每個埠指定名字。 #### 為服務指定多個埠 ``` apiVersion: v1 kind: Service metadata: name: goweb-svc spec: ports: - name: http port: 80 targetPort: 8000 - name: https port: 443 targetPort: 8443 selector: app: goweb ``` #### 使用命名的埠 使用方法是:在Pod(或其他資源的Pod模板)的`spec.containers.ports.name`配置中指定埠名稱,然後Service中的`spec.ports.targetPort`引用。 使用命名埠的好處在於,當Pod更改埠號時,不會影響到Service,因為Service引用的是埠名。 Pod中指定埠名: ``` spec: containers: - name: goweb ports: - name: http # 命名8000埠為http containerPort: 8000 - name: https # 命名8443埠為https containerPort: 8443 ``` Service中引用: ``` apiVersion: v1 kind: Service metadata: name: goweb-svc spec: ports: - name: http # 將80埠對映到容器中名為http的埠 port: 80 targetPort: http - name: https # 將443埠對映到容器中名為https的埠 port: 443 targetPort: https selector: app: goweb ``` ### 服務發現 #### 通過環境變數發現服務 在容器中執行env,列出一部分結果。 **服務名稱中的橫線被轉換為下劃線,並且全部轉為大寫** ``` -> [[email protected]] [~] k exec goweb-rs-hztlt env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=goweb-rs-hztlt KUBERNETES_SERVICE_HOST=10.96.0.1 KUBERNETES_SERVICE_PORT=443 GOWEB_SVC_SERVICE_HOST=10.98.92.202 GOWEB_SVC_SERVICE_PORT=80 ......... ``` #### 通過DNS發現服務 Kubernetes叢集運行了一個名為kube-dns的服務,提供DNS解析。 ``` -> [[email protected]] [~] k get svc -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 2d17h ``` 檢視容器內的`/etc/resolv.conf`檔案 ``` -> [[email protected]] [~] k exec goweb-rs-hztlt cat /etc/resolv.conf nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local lan vm options ndots:5 ``` 沒有錯,nameserver指定的IP就是kube-dns服務的地址! #### 通過FQDN連線服務 FQDN(Fully Qualified Domain Name):全限定域名 比如:goweb-svc.default.svc.cluster.local,goweb-svc是Service名稱,default是名稱空間,svc表示資源型別,cluster.local表示本地集群后綴。 根據情況,可以省略名稱空間(請求方與Service在相同名稱空間下)和 svc.cluster.local,也就是說下列情況都是可以的: ``` -> [[email protected]] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc this is goweb-rs-dknjv -> [[email protected]] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc.default -> [[email protected]] [~] k exec goweb-rs-dknjv -- curl -s http://goweb-svc.default.svc.cluster.local ``` #### 無法ping通服務IP的原因 因為服務的叢集IP是一個虛擬IP,並且只有在與服務埠結合時才有意義。 ## Endpoint Service與Pod不是直接相連的,有一種資源介於兩者之間,他就是Endpoint。 Endpoint暴露一個服務的IP和埠列表。 檢視Service ``` -> [[email protected]] [~] k describe svc goweb-svc Name: goweb-svc Namespace: default ....... Endpoints: 10.244.1.58:8000,10.244.2.61:8000 ....... ``` 檢視Endpoint資源 ``` -> [[email protected]] [~] k get ep NAME ENDPOINTS AGE goweb-svc 10.244.1.58:8000,10.244.2.61:8000 7h58m kubernetes 192.168.199.117:6443 8h ``` ### 手動配置服務的Endpoint **如果建立了不包含Pod選擇器的服務,Kubernetes將不會建立Endpoint資源。** #### 建立沒有Pod選擇器的Service external-service.yaml ``` apiVersion: v1 kind: Service metadata: name: external-svc spec: ports: - port: 80 ``` 檢視external-svc ``` -> [[email protected]] [~] k describe svc external-svc Name: external-svc Namespace: default Labels: Annotations: Selector: Type: ClusterIP IP: 10.108.251.192 Port: 80/TCP TargetPort: 80/TCP Endpoints: Session Affinity: None Events: ``` #### 為沒有選擇器的服務建立Endpoint **Endpoint物件需要與服務具有相同的名字,幷包含該服務的目標IP和埠列表**。 Service和Endpoint都提交到伺服器後,Service就又可以像具有Pod選擇器那樣了。 external-service-endpoint.yaml ``` apiVersion: v1 kind: Endpoints metadata: name: external-svc # 名字必須與相應服務的名字相同 subsets: - addresses: # IP、埠列表 - ip: 11.11.11.11 - ip: 22.22.22.22 ports: - port: 80 ``` 建立Endpoint ``` -> [[email protected]] [~] k create -f external-svc-endpoint.yaml endpoints/external-svc created ``` 檢視external-svc服務 ``` -> [[email protected]] [~] k describe svc external-svc Name: external-svc Namespace: default Labels: Annotations: Selector: Type: ClusterIP IP: 10.108.251.192 Port: 80/TCP TargetPort: 80/TCP Endpoints: 11.11.11.11:80,22.22.22.22:80 Session Affinity: None Events: ``` ### 為外部服務建立別名 建立一個具有別名的外部服務時,需要指定`service.spec.type`的值為`ExternalName`;並且指定`service.spec. externalName`的值為外部服務的完整域名。因此連線到服務的客戶端將直接連線到外部服務,完全繞過服務代理。出於這個原因,這些型別的服務也就沒有叢集IP external-svc-externalname.yaml ``` apiVersion: v1 kind: Service metadata: name: external-svc-externalname spec: type: ExternalName # 服務型別 externalName: www.baidu.com # 外部服務的完整域名 ports: - port: 80 ``` 建立、檢視別名外部服務,可以看到external-svc-externalname確實沒有叢集IP ``` -> [[email protected]] [~] k create -f external-svc-externalname.yaml service/external-svc-externalname created -> [[email protected]] [~] k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE external-svc ClusterIP 10.108.251.192 80/TCP 57m external-svc-externalname ExternalName www.baidu.com 80/TCP 18s kubernetes ClusterIP 10.96.0.1 443/TCP 9h ``` 通過`external-svc-externalname.default.svc.cluster.local`甚至是`external-svc-externalname`可以訪問服務。 ## NodePort與LoadBalancer 以下幾種方式可在外部訪問服務: - 將服務的型別設定成NodePort: 每個叢集節點都會開啟一個相同的埠,並將該埠的流量重定向到服務。 - 將服務的型別設定成LoadBalancer: LoadBalancer是NodePort的一種擴充套件,這種型別需要雲基礎設施提供專用的負載均衡器,負載均衡器將流量轉發到叢集的節點埠。 如果不支援LoadBalancer,那麼它會變得和NodePort一樣。 - 建立一個Ingress資源: 通過一個IP地址公開多個服務,它執行在第七層。 ### NodePort goweb-nodeport.yaml ``` apiVersion: v1 kind: Service metadata: name: goweb-nodeport spec: type: NodePort # Service型別 ports: - port: 80 # Service的埠 targetPort: 8000 # Pod的埠 nodePort: 31234 # 通過任意Node的此埠訪問服務 selector: app: goweb ``` 建立、檢視這個型別為NodePort的服務 ``` -> [[email protected]] [~] k create -f goweb-nodeport.yaml service/goweb-nodeport created -> [[email protected]] [~] k get svc goweb-nodeport NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE goweb-nodeport NodePort 10.105.234.226 80:31234/TCP 10s ``` 檢視節點IP ``` -> [[email protected]] [~] k get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME kube0.vm Ready master 3d5h v1.17.3 192.168.199.117 CentOS Linux 7 (Core) 5.6.14-1.el7.elrepo.x86_64 docker://19.3.6 kube1.vm Ready 3d5h v1.17.3 192.168.199.231 CentOS Linux 7 (Core) 5.6.14-1.el7.elrepo.x86_64 docker://19.3.6 kube2.vm Ready 3d5h v1.17.3 192.168.199.212 CentOS Linux 7 (Core) 5.6.14-1.el7.elrepo.x86_64 docker://19.3.6 ``` 使用不同節點IP訪問服務 ``` -> [[email protected]] [~] curl http://192.168.199.231:31234 this is goweb-rs-pbxvx -> [[email protected]] [~] curl http://192.168.199.212:31234 this is goweb-rs-6wc2f ``` 搞個圖 ![](https://img2020.cnblogs.com/blog/365378/202005/365378-20200523010020621-554764198.png) ### LoadBalancer goweb-loadbalancer.yaml ``` apiVersion: v1 kind: Service metadata: name: goweb-loadbalancer spec: type: LoadBalancer # 更改了型別 ports: # 去掉了nodePort、隨機分配 - port: 80 targetPort: 8000 selector: app: goweb ``` 建立、檢視這個型別為LoadBalancer的服務 ``` -> [[email protected]] [~] k create -f goweb-loadbalancer.yaml service/goweb-loadbalancer created -> [[email protected]] [~] k get svc goweb-loadbalancer NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE goweb-loadbalancer LoadBalancer 10.106.251.246 80:31141/TCP 21m ``` EXTERNAL-IP欄位一直是``,是作者的環境不支援LoadBalancer。退而求其次,將其作為NodePort使用: ``` -> [[email protected]] [~] curl http://192.168.199.212:31141 this is goweb-rs-pbxvx -> [[email protected]] [~] curl http://192.168.199.231:31141 this is goweb-rs-6wc2f ``` 搞個圖 ![](https://img2020.cnblogs.com/blog/365378/202005/365378-20200523013021265-1361189999.png) ### 外部連線的特性 #### externalTrafficPolicy `sservice.spec.externalTrafficPolicy`設定為`local`,則服務代理會選擇執行本地的Pod。如果本地Node沒有Pod,則連線將掛起。 #### 客戶端IP是不記錄的 節點埠接收到連線是,會對包的源地址進行轉換(SNAT),因此資料包的源IP將發生改變。 但是externalTrafficPolicy為local的不會進行SNAT ## Ingress 因為每個LoadBalancer服務都需要自己的負載均衡器,以及獨有的共有IP地址。而Ingress只需要一個地址就可以為多個服務提供訪問。**當客戶端向Ingress傳送Http請求時,Ingress會根據請求的主機名和路徑決定請求轉發到那個服務。** ![](https://img2020.cnblogs.com/blog/365378/202005/365378-20200523105608447-2115418719.png) ### 部署Ingress控制器 只有Ingress控制器在叢集中執行,Ingress資源才能正常工作。所以我們要先部署Ingress控制器,需要做的工作非常簡單: 進入ingress-nginx官網,複製貼上以下內容,然後執行就可以了。 ``` kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/baremetal/deploy.yaml ``` 這時候檢視Namespace,會發現多出一個ingress-nginx,具體內容就不細述了。 ``` -> [[email protected]] [~] k get ns NAME STATUS AGE default Active 3d15h ingress-nginx Active 15m kube-node-lease Active 3d15h kube-public Active 3d15h kube-system Active 3d15h ``` 除此之外還要做個小改動,執行`k edit -n ingress-nginx service/ingress-nginx-controller`,在spec下新增工作節點的IP。出處請見官網 ``` externalIPs: - 192.168.199.231 - 192.168.199.212 ``` 然後刪除其管理的Pod,使其重建。 ``` -> [[email protected]] [~] k delete -n ingress-nginx pod/ingress-nginx-controller-f8d756996-8prk2 pod "ingress-nginx-controller-f8d756996-8prk2" deleted ``` ### goweb-ingress.yaml ``` apiVersion: extensions/v1beta1 kind: Ingress metadata: name: goweb-ingress spec: rules: - host: www.goweb.com http: paths: - path: / backend: serviceName: goweb-svc servicePort: 80 ``` 建立、檢視goweb-ingress ``` -> [[email protected]] [~] k create -f goweb-ingress.yaml ingress.extensions/goweb-ingress created -> [[email protected]] [~] k get ing NAME HOSTS ADDRESS PORTS AGE goweb-ingress www.goweb.com 192.168.199.212 80 61s ``` 在host檔案中新增` 192.168.199.212 www.goweb.com`。然後訪問 ``` -> [[email protected]] [~] curl http://www.goweb.com this is goweb-rs-mhvj4 -> [[email protected]] [~] curl http://www.goweb.com this is goweb-rs-88k9t ``` ### 暴露多個服務 需要暴露多個服務,參照goweb-ingress.yaml: - 將多個服務對映到同一個域名只要在`pahts`下再配置一個`path`即可。 - 將多個服務對映到不同域名則配置多個`host`即可。 ### Ingress工作原理 從表面上看請求的流程是:client->ingress->service->pod,但實際上是client->ingress->pod。 在Ingress收到客戶端的請求後,會根據域名和路徑來確定服務,通過與該服務關聯的Endpoint物件檢視Pod IP,並將客戶端的請求轉發給其中一個pod。也就是說,請求不會轉發給服務,服務只是被用來選擇pod。 ![](https://img2020.cnblogs.com/blog/365378/202005/365378-20200523145749008-85860000.png) ### 處理TLS傳輸 佔個位置,以後補上。 ## 就緒探針 就緒探針(readinessProbe)的型別與存活探針(livenessProbe)一樣,請見此文。**它與存活探針的不同在於:如果容器未通過檢查,則不會被終止或重新啟動,但Pod會被從服務的Endpoint中移除,它確保了客戶端只與正常的Pod互動。** 在眾多的微服務中存在很多依賴關係,被依賴服務只有在準備就緒後,才能接收請求。所以就緒探針務必要定義。 ### goweb-readiness.yaml ``` apiVersion: apps/v1 kind: ReplicaSet metadata: name: goweb-readiness spec: replicas: 2 selector: matchLabels: app: goweb template: metadata: labels: app: goweb spec: containers: - name: goweb image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb ports: - name: http containerPort: 8000 readinessProbe: exec: command: ["ls","/var/ready"] ``` ### 執行檢視goweb-readiness 建立之後等了一段時間,可以看到兩個Pod都處於為就緒狀態,goweb-svc的Endpoints也是空的。 ``` -> [[email protected]] [~] k create -f goweb-readiness.yaml replicaset.apps/goweb-rs created -> [[email protected]] [~] k get po NAME READY STATUS RESTARTS AGE goweb-readiness-9k9kv 0/1 Running 0 11s goweb-readiness-x2gfb 0/1 Running 0 11s -> [[email protected]] [~] k describe svc goweb-svc Port: http 80/TCP TargetPort: http/TCP Endpoints: Session Affinity: None Events: ``` 讓我們來給 goweb-readiness-9k9kv 建立一個/var/ready檔案,使其準備就緒。 ``` -> [[email protected]] [~] k exec goweb-readiness-9k9kv touch /var/ready ``` 再來檢視、可以看到已經有一個Pod就緒了,Endpoints也有內容了。 ``` -> [[email protected]] [~] k get po NAME READY STATUS RESTARTS AGE goweb-readiness-9k9kv 1/1 Running 0 89s goweb-readiness-x2gfb 0/1 Running 0 89s -> [[email protected]] [~] k describe svc goweb-svc Endpoints: 10.244.2.74:8000 ``` ## headless 將服務的`spec.clusterIP`設定為`None`會使服務成為headless服務。它不會被分配叢集IP,DNS對其解析時就會返回Pod IP。 預設情況下,DNS對headless服務名解析只會返回已經就緒的Pod的IP。 ### goweb-headless.yaml ``` apiVersion: v1 kind: Service metadata: name: goweb-headless spec: clusterIP: None ports: - name: http port: 80 targetPort: 8000 selector: app: goweb ``` ### 建立、檢視 ReplicaSet是使用前面的goweb-readiness.yaml建立的。 ``` -> [[email protected]] [~] k create -f goweb-headless.yaml service/goweb-headless created -> [[email protected]] [~] k get all -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/goweb-readiness-2jj49 0/1 Running 0 10m 10.244.2.4 kube2.vm pod/goweb-readiness-5h5sg 0/1 Running 0 10m 10.244.1.5 kube1.vm NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/goweb-headless ClusterIP None 80/TCP 9m54s app=goweb service/kubernetes ClusterIP 10.96.0.1 443/TCP 79m NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR replicaset.apps/goweb-readiness 2 2 1 10m goweb registry.cn-hangzhou.aliyuncs.com/orzi/goweb app=goweb ``` 使用nslookup解析goweb-headless,沒有返回任何Pod的IP,這是因為兩個Pod都未就緒。 ``` -> [[email protected]] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless Server: 10.96.0.10 Address: 10.96.0.10:53 ** server can't find goweb-headless.default.svc.cluster.local: NXDOMAIN ** server can't find goweb-headless.svc.cluster.local: NXDOMAIN ........ ``` 為goweb-readiness-2jj49建立/var/ready使其滿足就緒條件 ``` k exec goweb-readiness-2jj49 touch /var/ready ``` 再使用nslookup檢視,可以看到返回了goweb-readiness-2jj49 的 IP ``` -> [[email protected]] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless Server: 10.96.0.10 Address: 10.96.0.10:53 ...... Name: goweb-headless.default.svc.cluster.local Address: 10.244.2.4 ...... ``` 如法炮製,使另一個Pod生效,就能看到兩個Pod的IP了 ### publishNotReadyAddresses 將`service.spec.publishNotReadyAddresses`設定為`true`,允許DNS解析headless服務是發現未就緒的Pod。 將goweb-readiness的Pod副本變成3個 ``` -> [[email protected]] [~] k scale --replicas=3 rs goweb-readiness replicaset.apps/goweb-readiness scaled -> [[email protected]] [~] k get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES goweb-readiness-2jj49 1/1 Running 0 24m 10.244.2.4 kube2.vm goweb-readiness-5h5sg 1/1 Running 0 24m 10.244.1.5 kube1.vm goweb-readiness-jb74c 0/1 Running 0 31s 10.244.1.6 kube1.vm ``` 然後編輯goweb-headless,寫入`publishNotReadyAddresses: true`。 ``` -> [[email protected]] [~] k edit svc goweb-headless service/goweb-headless edited ``` nslookup檢視,雖然有未就緒的,但IP還是全都返回了。 ``` -> [[email protected]] [~] k exec goweb-readiness-2jj49 nslookup goweb-headless Server: 10.96.0.10 Address: 10.96.0.10:53 Name: goweb-headless.default.svc.cluster.local Address: 10.244.2.4 Name: goweb-headless.default.svc.cluster.local Address: 10.244.1.5 Name: goweb-headless.default.svc.cluster.local Address: 10.244.1.6 ``` ## 注意事項 - 雙橫槓表示kubectl命令項的結束,在此之後的是指要在pod內部執行的命令 - 建立一個多埠服務時,必須給每個埠指定名字。 - 服務的IP無法ping通:因為服務的叢集IP是一個虛擬IP,並且只有在與服務埠結合時才有意義。 - `sservice.spec.sessionAffinity`設定會話親和性,預設為None,可以設定為ClientIP - 建立ExternalService需要將`spec.type`設定為`ExternalName`,此類服務只在DNS級別實施(為服務建立了CNAME DNS),也因此不會獲得叢集IP。 - `service.spec.externalTrafficPolicy`設定為`local`,則服務代理會選擇執行本地的Pod。如果本地Node沒有Pod,則連線將掛起。 - `service.spec.publishNotReadyAddresses`設定為`true`,允許DNS解析headless服務是發現未就緒的Pod。 ## 小結 - 服務是一種為一組相同功能的pod提供單一不變接入點的資源 - 建立了不包含Pod選擇器的服務,Kubernetes將不會建立Endpoints資源。 - 服務對外暴露的方法:NodePort、LoadBalancer、Ingress - Ingress的的工作原理是:client->ingress->pod,而不是client->ingress->service->pod。 - 就緒探針與存活探針: - 就緒探針:作用確保客戶端只與正常的Pod互動。如果檢查未通過,不會終止或重啟容器,但Pod會被從服務的Endpoint中移除。 - 存活探針:作榮是讓叢集知道Pod是否正常執行。如果檢查未通過,則終止異常容器並重新啟動。 - 一些概念:Service、Endpoint、對外暴露、就緒探針,服務