使用服务连接应用程序

Kubernetes 连接容器的模型

现在您已经拥有了一个持续运行的复制应用程序,您可以将其暴露在网络上。

Kubernetes 假设 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

这等效于 kubectl apply -f 以下 yaml

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,该 EndpointSlice 使用标签连接到服务。当 Pod 死机时,它会自动从包含它作为端点的 EndpointSlices 中删除。匹配服务 selector 的新 Pod 将自动添加到该服务的 EndpointSlice 中。检查端点,并注意 IP 与第一步中创建的 Pod 相同

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

您现在应该能够从集群中的任何节点使用 <CLUSTER-IP>:<PORT> 对 nginx 服务进行 curl。请注意,服务 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 放在同一台机器上,如果它死机,这将使您的整个服务停止运行。我们可以通过杀死这两个 Pod 并等待 Deployment 重新创建它们来正确地执行此操作。这次,服务在副本之前存在。这将为您提供调度程序级别的服务传播(前提是所有节点的容量都相同),以及正确的环境变量

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

然后,按回车键并运行 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 访问

您可以从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"

现在使用该文件创建秘密

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

现在修改您的 nginx 副本以使用秘密中的证书启动 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 清单的值得注意的要点

  • 该文件包含部署和服务规范。
  • 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 地址是公共互联网上可用的地址。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 年 5 月 17 日下午 9:43 PST:修复 connect-applications-service.md 中的错别字 (e4abc3028e)