將應用程式與服務連接

用於連接容器的 Kubernetes 模型

現在您已擁有持續執行、複寫的應用程式,您可以將其公開在網路上。

Kubernetes 假設 Pod 可以與其他 Pod 通訊,無論它們落在哪個主機上。Kubernetes 為每個 Pod 提供自己的叢集私有 IP 位址,因此您不需要明確地在 Pod 之間建立連結或將容器連接埠對應至主機連接埠。這表示 Pod 內的容器都可以在 localhost 上互相存取連接埠,並且叢集中的所有 Pod 都可以互相看到,而無需 NAT。本文檔的其餘部分詳細說明如何在這樣的網路模型上執行可靠的服務。

本教學課程使用簡單的 nginx Web 伺服器來示範此概念。

將 Pod 公開至叢集

我們在先前的範例中已執行此操作,但讓我們再次執行它,並專注於網路角度。建立 nginx Pod,並注意它具有容器連接埠規格

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

這使其可從叢集中的任何節點存取。檢查 Pod 正在執行的節點

kubectl apply -f ./run-my-nginx.yaml
kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP            NODE
my-nginx-3800858182-jr4a2   1/1       Running   0          13s       10.244.3.4    kubernetes-minion-905m
my-nginx-3800858182-kna2y   1/1       Running   0          13s       10.244.2.5    kubernetes-minion-ljyd

檢查您的 Pod IP

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.4]]
    [map[ip:10.244.2.5]]

您應該能夠 ssh 連線到叢集中的任何節點,並使用像是 curl 這類的工具,對兩個 IP 進行查詢。請注意,這些容器並未使用節點上的 80 埠,也沒有任何特殊的 NAT 規則將流量路由到 Pod。這表示您可以在同一個節點上執行多個 nginx Pod,全部都使用相同的 containerPort,並從叢集中的任何其他 Pod 或節點,使用指派給 Pod 的 IP 位址來存取它們。如果您想要安排將主機節點上的特定埠轉發到後端的 Pod,您可以做到 - 但網路模型應該表示您不需要這樣做。

如果您感到好奇,可以閱讀更多關於 Kubernetes 網路模型 的資訊。

建立服務(Service)

因此,我們在一個扁平的、叢集範圍的位址空間中執行 nginx Pod。理論上,您可以直接與這些 Pod 通訊,但是當節點故障時會發生什麼事?Pod 會隨著節點一起停止運作,而 Deployment 內的 ReplicaSet 將會建立新的 Pod,並具有不同的 IP。這就是 Service 要解決的問題。

Kubernetes Service 是一種抽象概念,它定義了在叢集中某處運行的、提供相同功能的一組邏輯 Pod。當建立時,每個 Service 都會被指派一個唯一的 IP 位址(也稱為 clusterIP)。此位址與 Service 的生命週期相關聯,並且在 Service 存活期間不會變更。Pod 可以設定為與 Service 通訊,並且知道與 Service 的通訊將會自動負載平衡到作為 Service 成員的某個 Pod。

您可以使用 kubectl expose 為您的 2 個 nginx 副本建立一個 Service

kubectl expose deployment/my-nginx
service/my-nginx exposed

這等同於在以下 yaml 中使用 kubectl apply -f

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

此規範將建立一個 Service,目標是標籤為 run: my-nginx 的任何 Pod 上的 TCP 80 埠,並在抽象化的 Service 埠上公開它 (targetPort:是容器接受流量的埠,port:是抽象化的 Service 埠,可以是任何其他 Pod 用於存取 Service 的埠)。檢視 Service API 物件,以查看 Service 定義中支援的欄位列表。檢查您的 Service

kubectl get svc my-nginx
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.0.162.149   <none>        80/TCP    21s

如先前所述,Service 由一組 Pod 支援。這些 Pod 通過 EndpointSlices 公開。Service 的選擇器將會持續評估,並且結果將會 POST 到使用 標籤 連接到 Service 的 EndpointSlice。當 Pod 停止運作時,它會自動從包含它作為端點的 EndpointSlices 中移除。符合 Service 選擇器的新 Pod 將會自動新增到該 Service 的 EndpointSlice。檢查端點,並注意這些 IP 與第一步中建立的 Pod 的 IP 相同

kubectl describe svc my-nginx
Name:                my-nginx
Namespace:           default
Labels:              run=my-nginx
Annotations:         <none>
Selector:            run=my-nginx
Type:                ClusterIP
IP Family Policy:    SingleStack
IP Families:         IPv4
IP:                  10.0.162.149
IPs:                 10.0.162.149
Port:                <unset> 80/TCP
TargetPort:          80/TCP
Endpoints:           10.244.2.5:80,10.244.3.4:80
Session Affinity:    None
Events:              <none>
kubectl get endpointslices -l kubernetes.io/service-name=my-nginx
NAME             ADDRESSTYPE   PORTS   ENDPOINTS               AGE
my-nginx-7vzhx   IPv4          80      10.244.2.5,10.244.3.4   21s

現在您應該能夠從叢集中的任何節點,使用 curl 對 <叢集-IP>:<埠號> 上的 nginx Service 進行操作。請注意,Service IP 完全是虛擬的,它永遠不會實際傳輸。如果您對這如何運作感到好奇,可以閱讀更多關於 service proxy 的資訊。

存取 Service

Kubernetes 支援兩種主要的 Service 尋找模式 - 環境變數和 DNS。前者開箱即用,而後者則需要 CoreDNS 叢集附加元件

環境變數

當 Pod 在節點上執行時,kubelet 會為每個作用中的 Service 新增一組環境變數。這會引入排序問題。為了了解原因,請檢查您正在執行的 nginx Pod 的環境(您的 Pod 名稱會有所不同)

kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443

請注意,沒有提到您的 Service。這是因為您在 Service 之前建立了副本。這樣做的另一個缺點是,排程器可能會將兩個 Pod 放在同一部機器上,如果該機器故障,將會使您的整個 Service 停止運作。我們可以透過終止 2 個 Pod 並等待 Deployment 重新建立它們來以正確的方式執行此操作。這次 Service 在副本之前就已存在。這將為您提供 Pod 的排程器層級 Service 分散(假設您的所有節點都具有相等的容量),以及正確的環境變數

kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;

kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE     IP            NODE
my-nginx-3800858182-e9ihh   1/1       Running   0          5s      10.244.2.7    kubernetes-minion-ljyd
my-nginx-3800858182-j4rm4   1/1       Running   0          5s      10.244.3.8    kubernetes-minion-905m

您可能會注意到 Pod 有不同的名稱,因為它們被終止並重新建立。

kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
MY_NGINX_SERVICE_HOST=10.0.162.149
KUBERNETES_SERVICE_HOST=10.0.0.1
MY_NGINX_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443

DNS

Kubernetes 提供了一個 DNS 叢集附加元件 Service,可以自動為其他 Service 指派 DNS 名稱。您可以檢查它是否在您的叢集上執行

kubectl get services kube-dns --namespace=kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   8m

本節的其餘部分將假設您有一個具有長期 IP (my-nginx) 的 Service,以及一個已為該 IP 指派名稱的 DNS 伺服器。在這裡,我們使用 CoreDNS 叢集附加元件(應用程式名稱 kube-dns),因此您可以使用標準方法(例如 gethostbyname())從叢集中的任何 Pod 與 Service 通訊。如果 CoreDNS 沒有執行,您可以參考 CoreDNS README安裝 CoreDNS 來啟用它。讓我們執行另一個 curl 應用程式來測試這個

kubectl run curl --image=radial/busyboxplus:curl -i --tty --rm
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
Hit enter for command prompt

然後,按下 Enter 鍵並執行 nslookup my-nginx

[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      my-nginx
Address 1: 10.0.162.149

保護 Service 的安全

到目前為止,我們僅從叢集內部存取了 nginx 伺服器。在將 Service 公開到網際網路之前,您需要確保通訊通道是安全的。為此,您將需要

  • 用於 https 的自我簽署憑證(除非您已經有身分憑證)
  • 設定為使用憑證的 nginx 伺服器
  • 一個 secret,使憑證可以被 Pod 存取

您可以從 nginx https 範例 中取得所有這些。這需要安裝 go 和 make 工具。如果您不想安裝這些工具,請按照稍後的步驟手動操作。簡而言之

make keys KEY=/tmp/nginx.key CERT=/tmp/nginx.crt
kubectl create secret tls nginxsecret --key /tmp/nginx.key --cert /tmp/nginx.crt
secret/nginxsecret created
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

以及 configmap

kubectl create configmap nginxconfigmap --from-file=default.conf

您可以在 Kubernetes examples 專案儲存庫 中找到 default.conf 的範例。

configmap/nginxconfigmap created
kubectl get configmaps
NAME             DATA   AGE
nginxconfigmap   1      114s

您可以使用以下命令檢視 nginxconfigmap ConfigMap 的詳細資訊

kubectl describe configmap  nginxconfigmap

輸出類似於

Name:         nginxconfigmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
default.conf:
----
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        listen 443 ssl;

        root /usr/share/nginx/html;
        index index.html;

        server_name localhost;
        ssl_certificate /etc/nginx/ssl/tls.crt;
        ssl_certificate_key /etc/nginx/ssl/tls.key;

        location / {
                try_files $uri $uri/ =404;
        }
}

BinaryData
====

Events:  <none>

以下是在您執行 make 時遇到問題(例如在 Windows 上)時要遵循的手動步驟

# Create a public private key pair
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /d/tmp/nginx.key -out /d/tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
# Convert the keys to base64 encoding
cat /d/tmp/nginx.crt | base64
cat /d/tmp/nginx.key | base64

使用先前命令的輸出,建立一個 yaml 檔案,如下所示。base64 編碼值應全部在一行上。

apiVersion: "v1"
kind: "Secret"
metadata:
  name: "nginxsecret"
  namespace: "default"
type: kubernetes.io/tls
data:
  tls.crt: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQUp5M3lQK0pzMlpJTUEwR0NTcUdTSWIzRFFFQkJRVUFNQ1l4RVRBUEJnTlYKQkFNVENHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0V3aHVaMmx1ZUhOMll6QWVGdzB4TnpFd01qWXdOekEzTVRKYQpGdzB4T0RFd01qWXdOekEzTVRKYU1DWXhFVEFQQmdOVkJBTVRDRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtFd2h1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSjFxSU1SOVdWM0IKMlZIQlRMRmtobDRONXljMEJxYUhIQktMSnJMcy8vdzZhU3hRS29GbHlJSU94NGUrMlN5ajBFcndCLzlYTnBwbQppeW1CL3JkRldkOXg5UWhBQUxCZkVaTmNiV3NsTVFVcnhBZW50VWt1dk1vLzgvMHRpbGhjc3paenJEYVJ4NEo5Ci82UVRtVVI3a0ZTWUpOWTVQZkR3cGc3dlVvaDZmZ1Voam92VG42eHNVR0M2QURVODBpNXFlZWhNeVI1N2lmU2YKNHZpaXdIY3hnL3lZR1JBRS9mRTRqakxCdmdONjc2SU90S01rZXV3R0ljNDFhd05tNnNTSzRqYUNGeGpYSnZaZQp2by9kTlEybHhHWCtKT2l3SEhXbXNhdGp4WTRaNVk3R1ZoK0QrWnYvcW1mMFgvbVY0Rmo1NzV3ajFMWVBocWtsCmdhSXZYRyt4U1FVQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjcKTUI4R0ExVWRJd1FZTUJhQUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjdNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVGQlFBRGdnRUJBRVhTMW9FU0lFaXdyMDhWcVA0K2NwTHI3TW5FMTducDBvMm14alFvCjRGb0RvRjdRZnZqeE04Tzd2TjB0clcxb2pGSW0vWDE4ZnZaL3k4ZzVaWG40Vm8zc3hKVmRBcStNZC9jTStzUGEKNmJjTkNUekZqeFpUV0UrKzE5NS9zb2dmOUZ3VDVDK3U2Q3B5N0M3MTZvUXRUakViV05VdEt4cXI0Nk1OZWNCMApwRFhWZmdWQTRadkR4NFo3S2RiZDY5eXM3OVFHYmg5ZW1PZ05NZFlsSUswSGt0ejF5WU4vbVpmK3FqTkJqbWZjCkNnMnlwbGQ0Wi8rUUNQZjl3SkoybFIrY2FnT0R4elBWcGxNSEcybzgvTHFDdnh6elZPUDUxeXdLZEtxaUMwSVEKQ0I5T2wwWW5scE9UNEh1b2hSUzBPOStlMm9KdFZsNUIyczRpbDlhZ3RTVXFxUlU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
  tls.key: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2RhaURFZlZsZHdkbFIKd1V5eFpJWmVEZWNuTkFhbWh4d1NpeWF5N1AvOE9ta3NVQ3FCWmNpQ0RzZUh2dGtzbzlCSzhBZi9WemFhWm9zcApnZjYzUlZuZmNmVUlRQUN3WHhHVFhHMXJKVEVGSzhRSHA3VkpMcnpLUC9QOUxZcFlYTE0yYzZ3MmtjZUNmZitrCkU1bEVlNUJVbUNUV09UM3c4S1lPNzFLSWVuNEZJWTZMMDUrc2JGQmd1Z0ExUE5JdWFubm9UTWtlZTRuMG4rTDQKb3NCM01ZUDhtQmtRQlAzeE9JNHl3YjREZXUraURyU2pKSHJzQmlIT05Xc0RadXJFaXVJMmdoY1kxeWIyWHI2UAozVFVOcGNSbC9pVG9zQngxcHJHclk4V09HZVdPeGxZZmcvbWIvNnBuOUYvNWxlQlkrZStjSTlTMkQ0YXBKWUdpCkwxeHZzVWtGQWdNQkFBRUNnZ0VBZFhCK0xkbk8ySElOTGo5bWRsb25IUGlHWWVzZ294RGQwci9hQ1Zkank4dlEKTjIwL3FQWkUxek1yall6Ry9kVGhTMmMwc0QxaTBXSjdwR1lGb0xtdXlWTjltY0FXUTM5SjM0VHZaU2FFSWZWNgo5TE1jUHhNTmFsNjRLMFRVbUFQZytGam9QSFlhUUxLOERLOUtnNXNrSE5pOWNzMlY5ckd6VWlVZWtBL0RBUlBTClI3L2ZjUFBacDRuRWVBZmI3WTk1R1llb1p5V21SU3VKdlNyblBESGtUdW1vVlVWdkxMRHRzaG9reUxiTWVtN3oKMmJzVmpwSW1GTHJqbGtmQXlpNHg0WjJrV3YyMFRrdWtsZU1jaVlMbjk4QWxiRi9DSmRLM3QraTRoMTVlR2ZQegpoTnh3bk9QdlVTaDR2Q0o3c2Q5TmtEUGJvS2JneVVHOXBYamZhRGR2UVFLQmdRRFFLM01nUkhkQ1pKNVFqZWFKClFGdXF4cHdnNzhZTjQyL1NwenlUYmtGcVFoQWtyczJxWGx1MDZBRzhrZzIzQkswaHkzaE9zSGgxcXRVK3NHZVAKOWRERHBsUWV0ODZsY2FlR3hoc0V0L1R6cEdtNGFKSm5oNzVVaTVGZk9QTDhPTm1FZ3MxMVRhUldhNzZxelRyMgphRlpjQ2pWV1g0YnRSTHVwSkgrMjZnY0FhUUtCZ1FEQmxVSUUzTnNVOFBBZEYvL25sQVB5VWs1T3lDdWc3dmVyClUycXlrdXFzYnBkSi9hODViT1JhM05IVmpVM25uRGpHVHBWaE9JeXg5TEFrc2RwZEFjVmxvcG9HODhXYk9lMTAKMUdqbnkySmdDK3JVWUZiRGtpUGx1K09IYnRnOXFYcGJMSHBzUVpsMGhucDBYSFNYVm9CMUliQndnMGEyOFVadApCbFBtWmc2d1BRS0JnRHVIUVV2SDZHYTNDVUsxNFdmOFhIcFFnMU16M2VvWTBPQm5iSDRvZUZKZmcraEppSXlnCm9RN3hqWldVR3BIc3AyblRtcHErQWlSNzdyRVhsdlhtOElVU2FsbkNiRGlKY01Pc29RdFBZNS9NczJMRm5LQTQKaENmL0pWb2FtZm1nZEN0ZGtFMXNINE9MR2lJVHdEbTRpb0dWZGIwMllnbzFyb2htNUpLMUI3MkpBb0dBUW01UQpHNDhXOTVhL0w1eSt5dCsyZ3YvUHM2VnBvMjZlTzRNQ3lJazJVem9ZWE9IYnNkODJkaC8xT2sybGdHZlI2K3VuCnc1YytZUXRSTHlhQmd3MUtpbGhFZDBKTWU3cGpUSVpnQWJ0LzVPbnlDak9OVXN2aDJjS2lrQ1Z2dTZsZlBjNkQKckliT2ZIaHhxV0RZK2Q1TGN1YSt2NzJ0RkxhenJsSlBsRzlOZHhrQ2dZRUF5elIzT3UyMDNRVVV6bUlCRkwzZAp4Wm5XZ0JLSEo3TnNxcGFWb2RjL0d5aGVycjFDZzE2MmJaSjJDV2RsZkI0VEdtUjZZdmxTZEFOOFRwUWhFbUtKCnFBLzVzdHdxNWd0WGVLOVJmMWxXK29xNThRNTBxMmk1NVdUTThoSDZhTjlaMTltZ0FGdE5VdGNqQUx2dFYxdEYKWSs4WFJkSHJaRnBIWll2NWkwVW1VbGc9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"

現在使用該檔案建立 secret

kubectl apply -f nginxsecrets.yaml
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

現在修改您的 nginx 副本,以使用 secret 中的憑證啟動 https 伺服器,並修改 Service 以公開兩個埠(80 和 443)

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      - name: configmap-volume
        configMap:
          name: nginxconfigmap
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
        - mountPath: /etc/nginx/conf.d
          name: configmap-volume

關於 nginx-secure-app 宣告檔案的重點

  • 它在同一個檔案中包含 Deployment 和 Service 規範。
  • nginx 伺服器 在 80 埠上提供 HTTP 流量,在 443 埠上提供 HTTPS 流量,而 nginx Service 公開這兩個埠。
  • 每個容器都可以透過掛載在 /etc/nginx/ssl 的卷存取金鑰。這是 nginx 伺服器啟動之前設定的。
kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml

此時,您可以從任何節點連線到 nginx 伺服器。

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.5]]
node $ curl -k https://10.244.3.5
...
<h1>Welcome to nginx!</h1>

請注意,我們在最後一步中如何提供 -k 參數給 curl,這是因為我們在憑證產生時對執行 nginx 的 Pod 一無所知,因此我們必須告訴 curl 忽略 CName 不符的情況。透過建立 Service,我們將憑證中使用的 CName 與 Pod 在 Service 查找期間使用的實際 DNS 名稱連結起來。讓我們從 Pod 測試這個(為了簡單起見,重複使用相同的 secret,Pod 只需要 nginx.crt 即可存取 Service)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl-deployment
spec:
  selector:
    matchLabels:
      app: curlpod
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
kubectl apply -f ./curlpod.yaml
kubectl get pods -l app=curlpod
NAME                               READY     STATUS    RESTARTS   AGE
curl-deployment-1515033274-1410r   1/1       Running   0          1m
kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/tls.crt
...
<title>Welcome to nginx!</title>
...

公開 Service

對於應用程式的某些部分,您可能想要將 Service 公開到外部 IP 位址。Kubernetes 支援兩種方式來做到這一點:NodePorts 和 LoadBalancers。在上一個章節中建立的 Service 已經使用了 NodePort,因此如果您的節點具有公用 IP,您的 nginx HTTPS 副本已準備好在網際網路上提供流量。

kubectl get svc my-nginx -o yaml | grep nodePort -C 5
  uid: 07191fb3-f61a-11e5-8ae5-42010af00002
spec:
  clusterIP: 10.0.162.149
  ports:
  - name: http
    nodePort: 31704
    port: 8080
    protocol: TCP
    targetPort: 80
  - name: https
    nodePort: 32453
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    run: my-nginx
kubectl get nodes -o yaml | grep ExternalIP -C 1
    - address: 104.197.41.11
      type: ExternalIP
    allocatable:
--
    - address: 23.251.152.56
      type: ExternalIP
    allocatable:
...

$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
...
<h1>Welcome to nginx!</h1>

現在讓我們重新建立 Service 以使用雲端負載平衡器。將 my-nginx Service 的 TypeNodePort 變更為 LoadBalancer

kubectl edit svc my-nginx
kubectl get svc my-nginx
NAME       TYPE           CLUSTER-IP     EXTERNAL-IP        PORT(S)               AGE
my-nginx   LoadBalancer   10.0.162.149     xx.xxx.xxx.xxx     8080:30163/TCP        21s
curl https://<EXTERNAL-IP> -k
...
<title>Welcome to nginx!</title>

EXTERNAL-IP 欄位中的 IP 位址是在公用網際網路上可用的位址。CLUSTER-IP 僅在您的叢集/私有雲網路內部可用。

請注意,在 AWS 上,類型為 LoadBalancer 會建立 ELB,它使用(較長的)主機名稱,而不是 IP。它太長而無法放入標準的 kubectl get svc 輸出中,事實上,因此您需要執行 kubectl describe service my-nginx 才能看到它。您會看到類似這樣的內容

kubectl describe service my-nginx
...
LoadBalancer Ingress:   a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
...

下一步

上次修改時間:2024 年 11 月 18 日下午 6:41 PST:docs: factor out typos into new pr (6a73d0e087)