使用服务连接应用程序

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 的分配 IP 地址从集群中的任何其他 Pod 或节点访问它们。如果你希望将主机节点上的特定端口转发到后端 Pod,你可以这样做 - 但网络模型应该意味着你不需要这样做。

如果你感兴趣,可以阅读更多关于 Kubernetes 网络模型 的信息。

创建服务

因此,我们在一个扁平的、集群范围的地址空间中运行 nginx Pod。理论上,你可以直接与这些 Pod 通信,但是当一个节点宕机时会发生什么?Pod 会随之消亡,Deployment 中的 ReplicaSet 将创建新的 Pod,并具有不同的 IP。这就是服务所解决的问题。

Kubernetes 服务是一个抽象概念,它定义了集群中某个位置运行的一组逻辑 Pod,它们都提供相同的功能。创建后,每个服务都会分配一个唯一的 IP 地址(也称为 clusterIP)。此地址与服务的生命周期相关联,并且在服务运行时不会更改。可以将 Pod 配置为与服务通信,并且知道与服务的通信将自动负载均衡到服务的某个成员 Pod。

你可以使用 kubectl expose 为你的 2 个 nginx 副本创建一个服务

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

此规范将创建一个服务,该服务的目标是具有 run: my-nginx 标签的任何 Pod 上的 TCP 端口 80,并将其暴露在抽象的服务端口上(targetPort:是容器接受流量的端口,port:是抽象的服务端口,可以是其他 Pod 用于访问服务的任何端口)。查看 服务 API 对象以查看服务定义中支持的字段列表。检查你的服务

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

如前所述,服务由一组 Pod 支持。这些 Pod 通过 EndpointSlices 暴露。服务的 selector 将被持续评估,结果将被 POST 到使用 标签 连接到服务的 EndpointSlice。当一个 Pod 死亡时,它会自动从包含它作为端点的 EndpointSlices 中移除。与服务的选择器匹配的新 Pod 将自动添加到该服务的 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 <CLUSTER-IP>:<PORT> 上的 nginx 服务。请注意,服务 IP 是完全虚拟的,它永远不会到达网络。如果你对它的工作原理感到好奇,可以阅读更多关于 服务代理 的信息。

访问服务

Kubernetes 支持两种主要的查找服务的方式 - 环境变量和 DNS。前者开箱即用,而后者需要 CoreDNS 集群插件

环境变量

当 Pod 在节点上运行时,kubelet 会为每个活动服务添加一组环境变量。这引入了排序问题。要了解原因,请检查正在运行的 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

注意,其中没有提到你的服务。这是因为你在服务之前创建了副本。这样做的另一个缺点是调度程序可能会将两个 Pod 放在同一台机器上,如果该机器宕机,将导致整个服务宕机。我们可以通过杀死 2 个 Pod 并等待 Deployment 重新创建它们来以正确的方式进行操作。这次服务在副本*之前*存在。这将为你提供 Pod 的调度程序级别的服务分散(前提是所有节点都具有相同的容量),以及正确的环境变量

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 集群插件服务,可以自动为其他服务分配 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),以及一个已为该 IP 分配名称的 DNS 服务器。这里我们使用 CoreDNS 集群插件(应用程序名称 kube-dns),因此你可以使用标准方法(例如 gethostbyname())从集群中的任何 Pod 与服务通信。如果 CoreDNS 未运行,你可以参考 CoreDNS 自述文件安装 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

保护服务安全

到目前为止,我们只从集群内部访问了 nginx 服务器。在将服务暴露给互联网之前,你需要确保通信信道是安全的。为此,你将需要

  • 用于 https 的自签名证书(除非你已经拥有身份证书)
  • 配置为使用证书的 nginx 服务器
  • 使 Pod 可以访问证书的 Secret

你可以从 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 示例项目仓库 中找到 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 服务器,并修改服务以暴露两个端口(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 服务暴露这两个端口。
  • 每个容器都可以通过挂载在 /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>

注意我们在最后一步中为 curl 提供了 -k 参数,这是因为我们在证书生成时不知道运行 nginx 的 pod 的任何信息,所以我们必须告诉 curl 忽略 CName 不匹配。通过创建服务,我们将证书中使用的 CName 与 pod 在服务查找期间使用的实际 DNS 名称链接起来。让我们从一个 pod 中测试一下(为了简单起见,重用了相同的密钥,pod 只需要 nginx.crt 即可访问服务)

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>
...

暴露服务

对于应用程序的某些部分,您可能希望将服务暴露到外部 IP 地址。Kubernetes 支持两种方法:NodePorts 和 LoadBalancers。上一节中创建的服务已经使用了 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>

现在让我们重新创建服务以使用云负载均衡器。将 my-nginx 服务的 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 地址是公共互联网上可用的 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:文档:将拼写错误分解到新的 PR 中 (6a73d0e087)