Kubernetes(k8s)服務service:service的發現和service的釋出

2023-06-06 18:00:32

一.系統環境

本文主要基於Kubernetes1.21.9和Linux作業系統CentOS7.4。

伺服器版本 docker軟體版本 Kubernetes(k8s)叢集版本 CPU架構
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 x86_64

Kubernetes叢集架構:k8scloude1作為master節點,k8scloude2,k8scloude3作為worker節點。

伺服器 作業系統版本 CPU架構 程序 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master節點
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點

二.前言

Kubernetes 是一個強大的容器編排平臺,它可以幫助開發者快速、可靠地部署和管理容器化應用程式。其中一個重要的概念就是 service(服務)。在 Kubernetes 中,service 是一組 Pod 的抽象,用於提供穩定的網路端點以便其他應用程式存取。本文將介紹 Kubernetes service 的相關知識,包括服務的發現和服務的釋出。

使用service服務的前提是已經有一套可以正常執行的Kubernetes叢集,關於Kubernetes(k8s)叢集的安裝部署,可以檢視部落格《Centos7 安裝部署Kubernetes(k8s)叢集》https://www.cnblogs.com/renshengdezheli/p/16686769.html。

三.Kubernetes service簡介

Kubernetes 中的 service 是一種可以提供內部負載均衡的抽象,用於將應用程式暴露為一個穩定的網路端點。Kubernetes service 可以通過一個虛擬 IP 地址或者 DNS 來暴露一個應用程式。當需要存取這個應用程式時,只需要使用這個虛擬 IP 地址或者 DNS 就可以了,而不需要知道實際執行這個應用程式的節點的 IP 地址。這種方式可以幫助我們解耦應用程式和底層網路架構,從而使應用程式能夠更加靈活地執行在不同的環境中。

Kubernetes 中的 service 還有一些重要的特性,包括:

  • 內部負載均衡:Kubernetes service 提供了內部負載均衡的功能,可以將請求均勻地分配給後端 Pod,從而提高應用程式的可用性和響應速度。
  • 服務發現:Kubernetes service 允許我們使用標準的 DNS 解析或者環境變數來查詢其他服務。這種方式可以使得不同的服務之間能夠更加方便地進行通訊。
  • 線上升級:Kubernetes service 支援線上升級,可以在不影響現有的服務的情況下進行版本升級。

四.使用hostPort向外界暴露應用程式

service簡寫為svc。建立svc存放yaml檔案的目錄。

[root@k8scloude1 ~]# mkdir svc

[root@k8scloude1 ~]# cd svc/

[root@k8scloude1 svc]# pwd
/root/svc

建立svc的namespace

[root@k8scloude1 svc]# kubectl create ns svc
namespace/svc created

切換名稱空間到svc

[root@k8scloude1 svc]# kubens svc
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "svc".

[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.

4.1 建立deploy

deploy控制器能更好的控制pod,我們先建立deploy。關於deploy控制器的詳細內容請檢視部落格《Kubernetes(k8s)控制器(一):deployment》。

生成建立deploy的yaml檔案。

[root@k8scloude1 svc]# kubectl create deploy nginx --image=nginx --dry-run=client -o yaml >nginxdeploy.yaml

[root@k8scloude1 svc]# cat nginxdeploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

修改yaml檔案,表示建立一個名為nginx的deploy,pod副本數為1。

[root@k8scloude1 svc]# vim nginxdeploy.yaml 

[root@k8scloude1 svc]# cat nginxdeploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  #replicas: 1表示pod副本數為1
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      #terminationGracePeriodSeconds: 0 表示當Pod被終止時,不需要等待額外的時間。
      terminationGracePeriodSeconds: 0
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: nginx
        resources: {}
status: {}

建立deploy,可以看到1個pod。

[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml 
deployment.apps/nginx created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6cf858f6cf-5wh5s   1/1     Running   0          7s    10.244.112.155   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   1/1     1            1           23s   nginx        nginx    app=nginx

pod的地址為10.244.112.155,對於pod的地址,在kubernetes叢集的任何節點都可以存取,但是外界存取不了。

[root@k8scloude1 svc]# ping 10.244.112.155
PING 10.244.112.155 (10.244.112.155) 56(84) bytes of data.
64 bytes from 10.244.112.155: icmp_seq=1 ttl=63 time=0.430 ms
64 bytes from 10.244.112.155: icmp_seq=2 ttl=63 time=0.516 ms
64 bytes from 10.244.112.155: icmp_seq=3 ttl=63 time=0.595 ms
^C
--- 10.244.112.155 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.430/0.513/0.595/0.072 ms

4.2 使用hostPort向外界暴露pod的埠

為了讓kubernetes叢集以外的機器可以存取pod,可以使用hostPort欄位把容器的埠對映到物理機的埠,這樣外界就可以存取pod了,類似於docker容器埠對映,關於docker容器埠對映可以檢視部落格《一文搞懂docker容器基礎:docker映象管理,docker容器管理》。

檢視hostPort欄位的解釋

[root@k8scloude1 svc]# kubectl explain pod.spec.containers.ports.hostPort
KIND:     Pod
VERSION:  v1

FIELD:    hostPort <integer>

DESCRIPTION:
     Number of port to expose on the host. If specified, this must be a valid
     port number, 0 < x < 65536. If HostNetwork is specified, this must match
     ContainerPort. Most containers do not need this.

修改deploy的yaml檔案,新增hostPort引數,把容器80埠對映到物理機的6554埠。

[root@k8scloude1 svc]# vim nginxdeploy.yaml 

[root@k8scloude1 svc]# cat nginxdeploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      #terminationGracePeriodSeconds: 0 表示Pod終止時不需要等待額外時間。
      terminationGracePeriodSeconds: 0
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        #把容器80埠對映到物理機的6554埠
        ports:
        - name: http
          containerPort: 80
          hostPort: 6554
        name: nginx
        resources: {}
status: {}

刪除舊的deploy並建立新的deploy

[root@k8scloude1 svc]# kubectl delete deploy nginx 
deployment.apps "nginx" deleted

[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml 
deployment.apps/nginx created

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           8s

檢視pod,發現pod執行在k8scloude2上,存取k8scloude2的6554埠即可存取pod。

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6f64cc5884-kkqmf   1/1     Running   0          15s   10.244.112.158   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   1/1     1            1           25s   nginx        nginx    app=nginx

nginx-6f64cc5884-kkqmf 這個pod執行在k8scloude2上,存取k8scloude2地址加埠,即可存取pod的nginx服務。

[root@k8scloude1 svc]# curl http://192.168.110.129:6554
<!DOCTYPE html>
......
<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><em>Thank you for using nginx.</em></p>
</body>
</html>

把deploy的副本數變為2

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2
deployment.apps/nginx scaled

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           6m23s

現在有2個pod了,pod分別執行在兩個worker上

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6f64cc5884-h78tv   1/1     Running   0          17s     10.244.251.252   k8scloude3   <none>           <none>
nginx-6f64cc5884-kkqmf   1/1     Running   0          6m30s   10.244.112.158   k8scloude2   <none>           <none>

此時k8scloude3也可以存取成功

[root@k8scloude1 svc]# curl 192.168.110.128:6554
<!DOCTYPE html>
<html>
......
<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><em>Thank you for using nginx.</em></p>
</body>
</html>

把deploy的副本數變為3

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3
deployment.apps/nginx scaled

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/3     3            2           8m29s

這時候問題就來了!可以發現通過hostPort把容器埠對映到物理機埠這種方法不太好,因為如果一個worker上有兩個pod,每個pod都要對映物理機埠,就會造成埠衝突,pod建立失敗

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-6f64cc5884-h78tv   1/1     Running   0          2m23s   10.244.251.252   k8scloude3   <none>           <none>
nginx-6f64cc5884-kkqmf   1/1     Running   0          8m36s   10.244.112.158   k8scloude2   <none>           <none>
nginx-6f64cc5884-msdqx   0/1     Pending   0          14s     <none>           <none>       <none>           <none>

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES   SELECTOR
nginx   2/3     3            2           8m43s   nginx        nginx    app=nginx

刪除deploy

[root@k8scloude1 svc]# kubectl delete deploy nginx 
deployment.apps "nginx" deleted

[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get deploy
No resources found in svc namespace.

五.使用service服務向外界暴露應用程式

修改deploy的yaml檔案,給pod指定多個標籤,但是deploy只匹配其中一個標籤matchLabels:app1: nginx1。

[root@k8scloude1 svc]# vim nginxdeploy.yaml 

[root@k8scloude1 svc]# cat nginxdeploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  #pod副本數為2個
  replicas: 2
  #deploy只匹配其中一個標籤
  selector:
    matchLabels:
      app1: nginx1
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      #pod有3個標籤
      labels:
        app1: nginx1
        app2: nginx2
        app3: nginx3
    spec:
      ##當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
      terminationGracePeriodSeconds: 0
      containers:
      - image: nginx
        ##imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
        imagePullPolicy: IfNotPresent
        name: nginx
        resources: {}
status: {}

建立deploy

[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml 
deployment.apps/nginx created

deploy根據標籤進行匹配

[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx   2/2     2            2           7s    nginx        nginx    app1=nginx1

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          12s   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          12s   10.244.112.159   k8scloude2   <none>           <none>

可以看到pod有三個標籤

[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELS
nginx-75b9846bd7-22btx   1/1     Running   0          30s   10.244.112.157   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq   1/1     Running   0          30s   10.244.112.159   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7

5.1 使用service服務向外界暴露pod

5.1.1 建立service服務

檢視service,服務service簡寫為svc

[root@k8scloude1 svc]# kubectl get svc
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get service
No resources found in svc namespace.

建立service服務建議使用命令列,而不是使用yaml檔案。

svc建立語法如下:

  • kubectl expose --name=名字 資源型別/名字 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 deploy/web1 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 deploy web1 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 pod/web1 --port=xxx --target-port=yyy
  • kubectl expose --name=名字 pod web1 --port=xxx --target-port=yyy

svc具有一個負載均衡器的作用,svc本身的埠(--port=xxx)可以隨意定義,svc轉發到pod的埠(--target-port=yyy)不可以隨意定義,需要根據容器的實際情況來定義,svc通過標籤選擇後端的pod。

為deploy建立一個service服務

[root@k8scloude1 svc]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           46m

[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80 
service/nginxsvc exposed

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginxsvc   ClusterIP   10.98.213.102   <none>        80/TCP    15s   app1=nginx1

如果svc沒有指定使用哪個標籤定位pod時,使用的標籤和deploy一樣

[root@k8scloude1 svc]# kubectl get svc -o wide --show-labels
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR      LABELS
nginxsvc   ClusterIP   10.98.213.102   <none>        80/TCP    44s   app1=nginx1   app=nginx

[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES   LABELS
nginx-75b9846bd7-22btx   1/1     Running   0          48m   10.244.112.157   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq   1/1     Running   0          48m   10.244.112.159   k8scloude2   <none>           <none>            app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7

刪除svc

[root@k8scloude1 svc]# kubectl delete svc nginxsvc 
service "nginxsvc" deleted

可以手動指定svc選擇的標籤

[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80 --selector=app2=nginx2
service/nginxsvc exposed

[root@k8scloude1 svc]# kubectl get svc nginxsvc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginxsvc   ClusterIP   10.98.95.134   <none>        80/TCP    23s   app2=nginx2

檢視svc的描述資訊,Endpoints表示svc後端定位的pod。

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.159:80
Session Affinity:  None
Events:            <none>

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          57m   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          57m   10.244.112.159   k8scloude2   <none>           <none>

把deploy的副本數變為4

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=4
deployment.apps/nginx scaled

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          58m   10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          10s   10.244.251.248   k8scloude3   <none>           <none>
nginx-75b9846bd7-kzx7h   1/1     Running   0          10s   10.244.251.249   k8scloude3   <none>           <none>
nginx-75b9846bd7-m2pdq   1/1     Running   0          58m   10.244.112.159   k8scloude2   <none>           <none>

Endpoints定位的pod自動變為4個

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.159:80,10.244.251.248:80 + 1 more...
Session Affinity:  None
Events:            <none>

把deploy的副本數再次變為2

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2
deployment.apps/nginx scaled

Endpoints定位的pod自動變為2個

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.251.248:80
Session Affinity:  None
Events:            <none>

現在手動生成一個pod,pod的標籤為app2=nginx2,svc也能自動選擇此pod。

[root@k8scloude1 svc]# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent --labels="app2=nginx2"
pod/pod1 created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          64m     10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          5m58s   10.244.251.248   k8scloude3   <none>           <none>
pod1                     1/1     Running   0          7s      10.244.112.161   k8scloude2   <none>           <none>

svc的Endpoints自動定位到該pod1

[root@k8scloude1 svc]# kubectl describe svc nginxsvc 
Name:              nginxsvc
Namespace:         svc
Labels:            app=nginx
Annotations:       <none>
Selector:          app2=nginx2
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.98.95.134
IPs:               10.98.95.134
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.112.157:80,10.244.112.161:80,10.244.251.248:80
Session Affinity:  None
Events:            <none>

刪除手動建立的pod1

[root@k8scloude1 svc]# kubectl delete pod pod1 --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "pod1" force deleted

把deploy的副本數變為3

[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3
deployment.apps/nginx scaled

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nginx-75b9846bd7-22btx   1/1     Running   0          66m     10.244.112.157   k8scloude2   <none>           <none>
nginx-75b9846bd7-7q7qm   1/1     Running   0          27s     10.244.112.166   k8scloude2   <none>           <none>
nginx-75b9846bd7-bswx2   1/1     Running   0          8m24s   10.244.251.248   k8scloude3   <none>           <none>

5.1.2 測試svc的負載均衡

現在測試svc的負載均衡功能,看看svc能不能把流量均勻的分配給後端pod。

修改3個pod裡的Nginx首頁檔案index.html,這樣能辨別出每一個pod。

[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-22btx -- sh -c "echo 111 >/usr/share/nginx/html/index.html"

[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-7q7qm -- sh -c "echo 222 >/usr/share/nginx/html/index.html"

[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-bswx2 -- sh -c "echo 333 >/usr/share/nginx/html/index.html"

svc的地址在叢集內部可以存取,存取svc,可以看到svc具有負載均衡的作用,分別轉發給了後端三個pod

[root@k8scloude1 svc]# while true ;do curl -s 10.98.95.134:80;sleep 1;done
222
111
111
222
333
333
222

值得注意的是:ping不通svc的地址,但是可以telnet svc地址和80埠,因為svc只開放了埠80。

kube-proxy模式預設是iptables,如果kube-proxy模式為iptables時,在叢集內部,ping不通svc的地址,但是如果kube-proxy模式為ipvs時,則能ping通svc的地址

#ping不通svc的地址
[root@k8scloude1 svc]# ping 10.98.95.134
PING 10.98.95.134 (10.98.95.134) 56(84) bytes of data.
^C
--- 10.98.95.134 ping statistics ---
18 packets transmitted, 0 received, 100% packet loss, time 17001ms

#可以telnet svc的地址
[root@k8scloude1 svc]# telnet 10.98.95.134 80
Trying 10.98.95.134...
Connected to 10.98.95.134.
Escape character is '^]'.

^CConnection closed by foreign host.

刪除deploy

[root@k8scloude1 svc]# ls
nginxdeploy.yaml

[root@k8scloude1 svc]# kubectl delete -f nginxdeploy.yaml 
deployment.apps "nginx" deleted

[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.

六.service服務的發現

什麼是服務的發現?建立了一個svc之後,pod怎麼發現服務svc,這就是服務的發現。

服務的發現有三種方式:1.clusterIP 2.變數的方式 3.DNS。

下面進行逐一講述。

6.1 使用clusterIP的方式進行服務發現

我們之前所建立的應用都比較單一,現在建立多級應用,使用wordpress映象和mysql映象搭建部落格。以往還介紹了使用docker搭建部落格的案例,詳情請檢視部落格《使用docker 5分鐘搭建一個部落格(mysql+WordPress)》。

先在kubernetes叢集的worker節點拉取mysql映象和WordPress映象。

[root@k8scloude2 ~]# docker pull hub.c.163.com/library/wordpress:latest
[root@k8scloude2 ~]# docker pull hub.c.163.com/library/mysql:latest

[root@k8scloude3 ~]# docker pull hub.c.163.com/library/wordpress:latest
[root@k8scloude3 ~]# docker pull hub.c.163.com/library/mysql:latest

生成建立pod的yaml檔案,使用hub.c.163.com/library/mysql:latest映象建立pod。

[root@k8scloude1 svc]# kubectl run mysqlpod --image=hub.c.163.com/library/mysql:latest --image-pull-policy=IfNotPresent --dry-run=client -o yaml > mysqlpod.yaml

修改yaml檔案,設定mysql的環境變數(root密碼,MySQL使用者,MySQL使用者密碼,要使用的MySQL資料庫名)。

[root@k8scloude1 svc]# vim mysqlpod.yaml 

[root@k8scloude1 svc]# cat mysqlpod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mysqlpod
  name: mysqlpod
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - image: hub.c.163.com/library/mysql:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    name: mysqlpod
    resources: {}
    env:
    #root密碼
    - name: MYSQL_ROOT_PASSWORD
      value: rootmima
    #MySQL使用者
    - name: MYSQL_USER
      value: lisi
    #MySQL使用者密碼
    - name: MYSQL_PASSWORD
      value: lisimim
    #要使用的MySQL資料庫名
    - name: MYSQL_DATABASE
      value: wordpress
  #dnsPolicy: ClusterFirst 表示Pod使用叢集的DNS解析服務來解析域名。    
  dnsPolicy: ClusterFirst
  #restartPolicy: Always 表示容器退出後總是重新啟動。
  restartPolicy: Always
status: {}

建立pod

[root@k8scloude1 svc]# kubectl apply -f mysqlpod.yaml 
pod/mysqlpod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   0          8s    10.244.112.163   k8scloude2   <none>           <none>

pod建立好之後,建立pod的svc,--port=3306指定svc埠,--target-port=3306指定mysql容器埠。

[root@k8scloude1 svc]# kubectl expose --name=mysqlsvc pod mysqlpod --port=3306 --target-port=3306
service/mysqlsvc exposed

檢視svc

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTOR
mysqlsvc   ClusterIP   10.104.58.98   <none>        3306/TCP   13s   run=mysqlpod
nginxsvc   ClusterIP   10.98.95.134   <none>        80/TCP     8h    app2=nginx2

接下來建立wordpress。yaml組態檔功能為:建立名為wordpresspod的pod,使用hub.c.163.com/library/wordpress:latest映象,設定wordpress的環境變數,用於連線 MySQL 資料庫,分別指定了MySQL資料庫地址、MySQL資料庫使用者名稱、MySQL資料庫密碼和資料庫名稱。

WORDPRESS_DB_HOST資料庫地址這裡填mysql svc的ClusterIP,這是通過clusterIP進行服務發現

[root@k8scloude1 svc]# vim wordpresspod.yaml 

[root@k8scloude1 svc]# cat wordpresspod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - image: hub.c.163.com/library/wordpress:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    name: wordpresspod
    resources: {}
    #設定wordpress的變數
    env:
    #MySQL資料庫地址,WORDPRESS_DB_HOST資料庫地址這裡填mysql svc的ClusterIP
    - name: WORDPRESS_DB_HOST
      value: 10.104.58.98
    #MySQL資料庫使用者名稱  
    - name: WORDPRESS_DB_USER
      value: lisi
    #MySQL資料庫密碼  
    - name: WORDPRESS_DB_PASSWORD
      value: lisimim
    #資料庫名稱  
    - name: WORDPRESS_DB_NAME
      value: wordpress
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立wordpresspod

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml 
pod/wordpresspod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          13m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          9s    10.244.251.255   k8scloude3   <none>           <none>

給wordpresspod建立一個svc用於外界存取wordpress,--type=NodePort用於服務釋出,這樣外界就可以存取此svc服務。

[root@k8scloude1 svc]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePort
service/wordpresssvc exposed

檢視svc,80:31860/TCP 把pod的80 埠對映到物理機的31860埠,存取物理機的31860埠就可存取wordpress,如下所示:

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       14m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         8h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   8s    run=wordpresspod

瀏覽器存取kubernetes叢集任意節點IP+埠31860,就可存取wordpress頁面,存取http://192.168.110.128:31860,語言選擇簡體中文,點選繼續。

設定站點標題,使用者名稱,密碼,email,安裝WordPress。

WordPress安裝成功之後,點選登入。

根據你設定的賬號進行登入。

此時個人部落格就搭建完畢了。

6.2 使用環境變數的方式進行服務發現

上面是通過clusterIP進行服務發現,下面使用環境變數的方式進行服務發現。

現在有兩個pod

[root@k8scloude1 ~]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          63m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          50m   10.244.251.255   k8scloude3   <none>           <none>

進入wordpresspod裡,使用env檢視pod裡的環境變數,可以看到裡面有很多環境變數。

[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash 

#使用env檢視pod裡的環境變數
root@wordpresspod:/var/www/html# env
NGINXSVC_PORT_80_TCP_PROTO=tcp
......
PWD=/var/www/html
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
NGINXSVC_PORT_80_TCP_ADDR=10.98.95.134
NGINXSVC_SERVICE_PORT=80
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
NGINXSVC_PORT_80_TCP=tcp://10.98.95.134:80
NGINXSVC_PORT=tcp://10.98.95.134:80
WORDPRESS_DB_USER=lisi
......

root@wordpresspod:/var/www/html# exit
exit

pod會以環境變數的方式去記錄服務svc的資訊,格式為:大寫服務名_SERVICE_HOST=服務的IP ; 大寫服務名_SERVICE_PORT=服務的埠,wordpress連線的mysql svc為mysqlsvc。MYSQLSVC_SERVICE_HOST為mysql svc的IP地址。

注意:pod建立之後會自動記錄之前的存在的svc資訊,在pod之後建立的svc資訊不自動記錄。

[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash

root@wordpresspod:/var/www/html# env | grep -i mysqlsvc
MYSQLSVC_SERVICE_HOST=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
MYSQLSVC_SERVICE_PORT=3306
MYSQLSVC_PORT_3306_TCP=tcp://10.104.58.98:3306

root@wordpresspod:/var/www/html# exit
exit

現在一個mysql的pod和svc,一個wordpress的pod和svc

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       71m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         9h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   57m   run=wordpresspod

[root@k8scloude1 ~]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          74m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          61m   10.244.251.255   k8scloude3   <none>           <none>

刪除wordpresspod

[root@k8scloude1 ~]# kubectl delete pod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "wordpresspod" force deleted

[root@k8scloude1 ~]# kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   0          75m   10.244.112.163   k8scloude2   <none>           <none>

修改wordpresspod的yaml檔案,設定wordpress的環境變數,用於連線 MySQL 資料庫,分別指定了MySQL資料庫地址、MySQL資料庫使用者名稱、MySQL資料庫密碼和資料庫名稱。

WORDPRESS_DB_HOST資料庫地址這裡填mysql svc的環境變數WORDPRESS_DB_HOST,這是通過環境變數進行服務發現

[root@k8scloude1 ~]# cd svc/
[root@k8scloude1 svc]# pwd
/root/svc
[root@k8scloude1 svc]# vim wordpresspod.yaml 

[root@k8scloude1 svc]# cat wordpresspod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - image: hub.c.163.com/library/wordpress:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    name: wordpresspod
    resources: {}
    env:
    #MySQL資料庫地址,WORDPRESS_DB_HOST資料庫地址這裡填mysql svc的環境變數
    - name: WORDPRESS_DB_HOST
      #使用變數的方式
      value: $(MYSQLSVC_SERVICE_HOST)
    #MySQL資料庫使用者名稱    
    - name: WORDPRESS_DB_USER
      value: lisi
    #MySQL資料庫密碼    
    - name: WORDPRESS_DB_PASSWORD
      value: lisimim
    #資料庫名稱    
    - name: WORDPRESS_DB_NAME
      value: wordpress
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立wordpresspod,這時候一切又正常了,搭建的部落格又可以正常工作了。

此時瀏覽器存取http://192.168.110.128:31860/,即可存取wordpress。

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml 
pod/wordpresspod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   0          79m   10.244.112.163   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          6s    10.244.112.162   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       76m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         9h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   62m   run=wordpresspod

通過環境變數的方式進行服務發現,存在缺陷如下:

  1. 只能獲取相同namespace裡的變數;
  2. 變數的獲取有先後順序,參照的變數必須要先建立。

6.3 使用DNS的方式進行服務發現(推薦)

Kubernetes 中的 DNS 服務是一個專門的服務,用於為 Pod 提供服務發現功能。當我們建立一個 service 時,Kubernetes 會自動為該 service 建立一個 DNS 記錄。這個 DNS 記錄中包含了該 service 的名稱、IP 地址以及埠資訊。當一個 Pod 需要存取該 service 時,它可以通過該 service 的名稱來查詢該 DNS 記錄,並將該名稱解析為一個 IP 地址。這樣,該 Pod 就可以直接通過該 IP 地址來存取該 service。

kube-dns記錄了叢集的DNS資訊,svc建立好之後會向kube-dns進行註冊,等以後pod想通過服務名直接存取svc時,會向kube-dns查詢svc的IP地址,kube-dns把查到的svc地址返回給pod,pod就可存取svc。

[root@k8scloude1 svc]# 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   32d
metrics-server   ClusterIP   10.97.8.134   <none>        443/TCP                  31d

如何查詢到kube-dns這個svc對應的pod?使用標籤查詢。

先檢視svc選擇的標籤為k8s-app=kube-dns。

[root@k8scloude1 svc]# kubectl get svc -n kube-system -o wide
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
kube-dns         ClusterIP   10.96.0.10    <none>        53/UDP,53/TCP,9153/TCP   32d   k8s-app=kube-dns
metrics-server   ClusterIP   10.97.8.134   <none>        443/TCP                  31d   k8s-app=metrics-server

通過標籤k8s-app=kube-dns定位到pod

[root@k8scloude1 svc]# kubectl get pod -A -o wide -l k8s-app=kube-dns
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
kube-system   coredns-545d6fc579-7wm95   1/1     Running   21         32d   10.244.158.109   k8scloude1   <none>           <none>
kube-system   coredns-545d6fc579-87q8j   1/1     Running   21         32d   10.244.158.110   k8scloude1   <none>           <none>

刪除svc,重新給wordpress建立svc

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       164m   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         11h    app2=nginx2
wordpresssvc   NodePort    10.107.76.238   <none>        80:31860/TCP   151m   run=wordpresspod

[root@k8scloude1 svc]# kubectl delete svc wordpresssvc 
service "wordpresssvc" deleted

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE   SELECTOR
mysqlsvc   ClusterIP   10.104.58.98   <none>        3306/TCP   15h   run=mysqlpod
nginxsvc   ClusterIP   10.98.95.134   <none>        80/TCP     24h   app2=nginx2

[root@k8scloude1 ~]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePort
service/wordpresssvc exposed

[root@k8scloude1 ~]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTOR
mysqlsvc       ClusterIP   10.104.58.98   <none>        3306/TCP       15h   run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134   <none>        80/TCP         24h   app2=nginx2
wordpresssvc   NodePort    10.100.99.82   <none>        80:32729/TCP   9s    run=wordpresspod

使用Nginx映象建立一個nginx pod。

[root@k8scloude1 svc]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

[root@k8scloude1 svc]# kubectl apply -f pod.yaml 
pod/podtest created

檢視pod

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   1          15h   10.244.112.168   k8scloude2   <none>           <none>
podtest        1/1     Running   0          9s    10.244.251.195   k8scloude3   <none>           <none>
wordpresspod   1/1     Running   1          14h   10.244.112.164   k8scloude2   <none>           <none>

修改pod裡的index.html檔案,把index.html內容修改為111。

[root@k8scloude1 svc]# kubectl exec -it podtest -- sh -c "echo 111 > /usr/share/nginx/html/index.html"

給podtest建立svc服務

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 
service/podtestsvc exposed

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE     SELECTOR
mysqlsvc       ClusterIP   10.104.58.98     <none>        3306/TCP       15h     run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134     <none>        80/TCP         24h     app2=nginx2
podtestsvc     ClusterIP   10.108.102.183   <none>        80/TCP         7s      test=podtest
wordpresssvc   NodePort    10.100.99.82     <none>        80:32729/TCP   8m23s   run=wordpresspod

--rm表示建立一個臨時pod,退出pod就會自動刪除pod。

建立名為clientpod的臨時pod作為使用者端,去存取其他svc,首先存取podtestsvc。

[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -- bash
If you don't see a command prompt, try pressing enter.

#直接存取svc就可存取服務
root@clientpod:/# curl podtestsvc
111
root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted

-n default:表示進入pod後,自動切換為default名稱空間,繼續存取podtestsvc。

[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -n default -- bash
If you don't see a command prompt, try pressing enter.

#因為是在default名稱空間裡存取svc名稱空間裡的服務,所以存取失敗
root@clientpod:/# curl podtestsvc
curl: (6) Could not resolve host: podtestsvc

#需要指定svc名稱空間
root@clientpod:/# curl podtestsvc.svc
111

#檢視pod裡DNS資訊:nameserver 10.96.0.10對應的就是kube-dns的IP
root@clientpod:/# cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted

刪除wordpresspod,重新建立。

[root@k8scloude1 svc]# kubectl delete pod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "wordpresspod" force deleted

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod   1/1     Running   1          16h   10.244.112.168   k8scloude2   <none>           <none>
podtest    1/1     Running   0          10m   10.244.251.195   k8scloude3   <none>           <none>

修改wordpresspod的yaml檔案,設定wordpress的環境變數,用於連線 MySQL 資料庫,分別指定了MySQL資料庫地址、MySQL資料庫使用者名稱、MySQL資料庫密碼和資料庫名稱。

WORDPRESS_DB_HOST資料庫地址這裡直接填mysql svc的名稱mysqlsvc,這是通過DNS進行服務發現

[root@k8scloude1 svc]# vim wordpresspod.yaml 

[root@k8scloude1 svc]# cat wordpresspod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: wordpresspod
  name: wordpresspod
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - image: hub.c.163.com/library/wordpress:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    name: wordpresspod
    resources: {}
    #設定wordpress的變數
    env:
    #MySQL資料庫地址,WORDPRESS_DB_HOST資料庫地址這裡直接填mysql svc的名稱mysqlsvc
    - name: WORDPRESS_DB_HOST
      #使用DNS的方式
      value: mysqlsvc
    #MySQL資料庫使用者名稱    
    - name: WORDPRESS_DB_USER
      value: lisi
    #MySQL資料庫密碼    
    - name: WORDPRESS_DB_PASSWORD
      value: lisimim
    #資料庫名稱    
    - name: WORDPRESS_DB_NAME
      value: wordpress
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立wordpresspod,這時候一切又正常了,搭建的部落格又可以正常工作了。

此時瀏覽器存取http://192.168.110.128:32632/,即可存取wordpress。

[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml 
pod/wordpresspod created

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
mysqlpod       1/1     Running   1          16h   10.244.112.168   k8scloude2   <none>           <none>
wordpresspod   1/1     Running   0          10s   10.244.251.198   k8scloude3   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
mysqlsvc       ClusterIP   10.104.58.98    <none>        3306/TCP       16h     run=mysqlpod
nginxsvc       ClusterIP   10.98.95.134    <none>        80/TCP         24h     app2=nginx2
wordpresssvc   NodePort    10.109.31.167   <none>        80:32632/TCP   4m42s   run=wordpresspod

刪除pod和svc

[root@k8scloude1 svc]# kubectl delete pod mysqlpod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "mysqlpod" force deleted
pod "wordpresspod" force deleted

[root@k8scloude1 svc]# kubectl delete svc mysqlsvc nginxsvc wordpresssvc
service "mysqlsvc" deleted
service "nginxsvc" deleted
service "wordpresssvc" deleted

[root@k8scloude1 svc]# kubectl get pod -o wide
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.

七.service服務的釋出

在Kubernetes中,服務釋出是指將應用程式或服務對外部公開,以便其他應用程式或使用者可以存取它們。簡而言之服務釋出就是使外界能存取svc。

Kubernetes叢集中的服務可以使用三種不同的型別進行釋出和暴露:ClusterIP,NodePort以及LoadBalancer:

  • ClusterIP:ClusterIP是最常見的服務釋出型別,它將Pod暴露給叢集內部,並通過叢集內部的DNS進行發現。這意味著只有在同一Kubernetes叢集內的其他Pod才能存取該服務,而外部使用者端無法存取。ClusterIP型別的服務通常用於基於微服務架構的應用程式內部通訊。

  • NodePort:使用NodePort型別的服務可以公開一個Pod,以便從叢集外部存取。當您建立一個NodePort型別的服務時,Kubernetes會在每個節點上公開一個隨機埠。通過此埠,來自叢集外部的使用者端可以存取此服務。NodePort型別的服務通常用於測試、開發和小型生產環境。

  • LoadBalancer:LoadBalancer型別的服務可以公開一個Pod,以便從外部負載平衡器存取。當您建立一個LoadBalancer型別的服務時,Kubernetes會為其分配一個外部IP地址,並設定外部負載平衡器以將流量路由到該地址。LoadBalancer型別的服務通常用於生產環境中需要大規模處理流量的應用程式。

  • 除了這三種型別之外,還有一種稱為ExternalName的特殊型別。使用ExternalName型別的服務可以將一個Kubernetes服務對映到叢集外部的DNS名稱。這種型別的服務通常用於需要存取叢集外部資源的應用程式,例如外部資料庫或Web服務。

注意:service在哪個節點上執行這種說法是錯誤的,service是抽象的,不存在在哪個節點上執行。

7.1 使用nodeport進行服務的釋出

先弄清楚幾個引數:NodePort是svc對映到物理機的埠,port是svc的埠,target-port是pod容器裡的埠,hostport是pod對映到物理機的埠

7.1.1 使用kubectl edit修改服務型別為NodePort

使用Nginx映象建立一個pod。

[root@k8scloude1 svc]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: nginx
    image: nginx
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent

#建立一個nginx pod
[root@k8scloude1 svc]# kubectl apply -f pod.yaml 
pod/podtest created

給pod建立svc

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          26s   10.244.112.169   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80
service/podtestsvc exposed

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
podtestsvc   ClusterIP   10.100.92.123   <none>        80/TCP    6s    test=podtest

直接編輯svc:把type: ClusterIP改為type: NodePort。

[root@k8scloude1 svc]# kubectl edit svc podtestsvc 
service/podtestsvc edited

把type: ClusterIP改為type: NodePort之後,svc型別就變了,此時svc的釋出型別已經改變,在瀏覽器存取物理機IP:30908,即可存取svc服務。

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
podtestsvc   NodePort   10.100.92.123   <none>        80:30908/TCP   3m39s   test=podtest

瀏覽器存取192.168.110.129:30908,即可成功存取Nginx。

要恢復svc的釋出型別,直接把type: NodePort 改為type: ClusterIP即可。

[root@k8scloude1 svc]# kubectl edit svc podtestsvc 
service/podtestsvc edited

此時svc釋出型別又變為ClusterIP了。

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
podtestsvc   ClusterIP   10.100.92.123   <none>        80/TCP    7m28s   test=podtest

刪除svc

[root@k8scloude1 svc]# kubectl delete svc podtestsvc 
service "podtestsvc" deleted

7.1.2 使用type指定服務型別為NodePort

也可以使用命令列的方式指定svc的釋出型別為NodePort。

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=NodePort
service/podtestsvc exposed

現在svc型別為NodePort

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE   SELECTOR
podtestsvc   NodePort   10.97.91.78   <none>        80:31596/TCP   2s    test=podtest

刪除svc

[root@k8scloude1 svc]# kubectl delete svc podtestsvc 
service "podtestsvc" deleted

注意:NodePort的svc釋出型別存在一定問題:

  • NodePort對映的埠越多,漏洞越大
  • NodePort埠太多維護困難

7.2 使用LoadBalancer的方式進行服務的釋出

7.2.1 安裝METALLB

使用LoadBalancer的方式進行服務釋出,需要藉助第三方的工具(METALLB)。

每個svc都有一個私有地址,只能在叢集內部存取,如果我們把svc的型別設定為LoadBalancer,則svc會獲取到一個外部IP,這個外部IP來自地址池,本文使用METALLB設定地址池。

METALLB的官網如下:https://metallb.universe.tf/

檢視MetalLB的安裝方式,Installation MetalLB By Manifest。

建立metallb的namespace

[root@k8scloude1 svc]# kubectl create ns metallb-system
namespace/metallb-system created

下載metallb的安裝檔案

[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml

[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml

[root@k8scloude1 svc]# ls
metallb.yaml  namespace.yaml  

檢視metallb需要的映象

[root@k8scloude1 svc]# grep image metallb.yaml 
        image: quay.io/metallb/speaker:v0.11.0
        image: quay.io/metallb/controller:v0.11.0

修改metallb.yaml 檔案,修改metallb.yaml裡的映象下載策略為IfNotPresent,表示如果本地已經存在該映象,則不重新下載;否則從遠端倉庫下載該映象。

[root@k8scloude1 svc]# vim metallb.yaml 

[root@k8scloude1 svc]# cat metallb.yaml | grep image
        image: quay.io/metallb/speaker:v0.11.0
        imagePullPolicy: IfNotPresent
        image: quay.io/metallb/controller:v0.11.0
        imagePullPolicy: IfNotPresent

在worker節點提前下載speaker和controller映象。

[root@k8scloude2 ~]# docker pull quay.io/metallb/speaker:v0.11.0
[root@k8scloude2 ~]# docker pull quay.io/metallb/controller:v0.11.0

[root@k8scloude2 ~]# docker images | grep metallb
quay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MB
quay.io/metallb/controller                           v0.11.0   85a7890eec45   3 months ago    46.5MB

[root@k8scloude3 ~]# docker pull quay.io/metallb/speaker:v0.11.0
[root@k8scloude3 ~]# docker pull quay.io/metallb/controller:v0.11.0

[root@k8scloude3 ~]# docker images | grep metallb
quay.io/metallb/speaker                              v0.11.0   896b796b12bb   3 months ago    50.2MB
quay.io/metallb/controller                           v0.11.0   85a7890eec45   3 months ago    46.5MB

應用名稱空間檔案,安裝metallb。

[root@k8scloude1 svc]# kubectl apply -f namespace.yaml 
Warning: resource namespaces/metallb-system is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
namespace/metallb-system configured

[root@k8scloude1 svc]# kubectl apply -f metallb.yaml 
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/controller created
podsecuritypolicy.policy/speaker created
......
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
rolebinding.rbac.authorization.k8s.io/controller created
daemonset.apps/speaker created
deployment.apps/controller created

檢視pod,可以看到metallb安裝成功。


[root@k8scloude1 svc]# kubectl get pod -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP                NODE         NOMINATED NODE   READINESS GATES
controller-7dcc8764f4-qdwl2   1/1     Running   0          2m41s   10.244.112.160    k8scloude2   <none>           <none>
speaker-892pm                 1/1     Running   0          2m41s   192.168.110.128   k8scloude3   <none>           <none>
speaker-jfccb                 1/1     Running   0          2m41s   192.168.110.130   k8scloude1   <none>           <none>
speaker-nkrgk                 1/1     Running   0          2m41s   192.168.110.129   k8scloude2   <none>           <none>

7.2.2 設定地址池

檢視設定地址池的yaml檔案。

接下來設定地址池,地址池的IP範圍為:192.168.110.188-192.168.110.250

[root@k8scloude1 svc]# vim ipaddrpool.yaml

[root@k8scloude1 svc]# cat ipaddrpool.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
     #地址池的IP範圍
      addresses:
      - 192.168.110.188-192.168.110.250

建立地址池

[root@k8scloude1 svc]# kubectl apply -f ipaddrpool.yaml 
configmap/config created

[root@k8scloude1 svc]# kubectl get configmap -o wide
NAME               DATA   AGE
kube-root-ca.crt   1      35h

7.2.3 使用LoadBalancer的方式進行服務釋出

現在podtest沒有svc,給podtest建立svc,型別為LoadBalancer。

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          148m   10.244.112.169   k8scloude2   <none>           <none>

[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=LoadBalancer
service/podtestsvc exposed

檢視svc,EXTERNAL-IP地址是從地址池裡分配的。

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE   SELECTOR
podtestsvc   LoadBalancer   10.97.238.10   192.168.110.188   80:30725/TCP   3s    test=podtest

瀏覽器直接存取外部IP即可存取svc服務:http://192.168.110.188/

再給podtest建立一個svc,型別還是LoadBalancer。

[root@k8scloude1 svc]# kubectl expose --name=podtestsvc2 pod podtest --port=80 --type=LoadBalancer
service/podtestsvc2 exposed

[root@k8scloude1 svc]# kubectl get svc -o wide
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE    SELECTOR
podtestsvc    LoadBalancer   10.97.238.10   192.168.110.188   80:30725/TCP   5m3s   test=podtest
podtestsvc2   LoadBalancer   10.96.128.89   192.168.110.189   80:32644/TCP   5s     test=podtest

瀏覽器直接存取外部IP即可存取svc服務:http://192.168.110.189/。

刪除svc。

[root@k8scloude1 svc]# kubectl delete svc podtestsvc podtestsvc2
service "podtestsvc" deleted
service "podtestsvc2" deleted

[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.

[root@k8scloude1 svc]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          159m   10.244.112.169   k8scloude2   <none>           <none>