为Nginx Ingress配置gRPC服务

对于部署在ACK集群中的gRPC应用,为实现外部客户端的访问,可配置Nginx Ingress并添加 nginx.ingress.kubernetes.io/backend-protocol: "GRPC" 注解来路由gRPC流量。

核心示例

以下为Nginx Ingress安全暴露gRPC服务的核心配置。

  • gRPC 协议代理:通过 backend-protocol: "GRPC" 注解,明确指示 Ingress 将流量作为 gRPC(基于HTTP/2)进行代理,而不是默认的HTTP。

  • TLS 加密:为示例域名 grpc.example.com 启用了 TLS,并使用Secret中存储的证书进行加密。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grpc-ingress
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC" # 关键:指明后端服务为gRPC协议
spec:
  tls:
  - hosts:
    - grpc.example.com                                   # 替换为gRPC服务域名
    secretName: nginx-ingress-tls                        # 配置存储证书的Secret
  rules:
  - host: grpc.example.com                               # 替换为gRPC服务域名
  #...

部署gRPC示例应用

控制台

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

  2. 无状态页面,单击使用YAML创建资源,然后将以下内容复制到模板区域,单击创建

    示例应用YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: grpc-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: grpc-service
      template:
        metadata:
          labels:
            run: grpc-service
        spec:
          containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/grpc-server:latest
            imagePullPolicy: Always
            name: grpc-service
            ports:
            - containerPort: 50051
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: grpc-service
    spec:
      ports:
      - port: 50051
        protocol: TCP
        targetPort: 50051
      selector:
        run: grpc-service
      sessionAffinity: None
      type: NodePort
  3. 在弹窗中找到目标无状态应用,单击查看,确认Pod状态为Running。 

kubectl

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 将以下YAML内容保存为grpc.yaml文件。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: grpc-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: grpc-service
      template:
        metadata:
          labels:
            run: grpc-service
        spec:
          containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/grpc-server:latest
            imagePullPolicy: Always
            name: grpc-service
            ports:
            - containerPort: 50051
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: grpc-service
    spec:
      ports:
      - port: 50051
        protocol: TCP
        targetPort: 50051
      selector:
        run: grpc-service
      sessionAffinity: None
      type: NodePort
  3. 部署gRPC应用并创建服务(Service)。

    kubectl apply -f grpc.yaml
  4. 确认目标应用Pod状态为Running

    kubectl get pod | grep grpc-service

该服务基于以下 .proto 文件定义。服务名为 Greeter,提供了一个 SayHello 方法。

gRPC示例应用接口定义

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

更多gRPC服务示例

SSL证书存储为Secret

要在 Nginx Ingress 中启用 gRPC 所依赖的 HTTP/2 协议,必须先开启 TLS 加密。可以将 SSL证书与私钥存入Secret中进行安全管理,并通过引用该Secret来完成TLS加密配置。

  1. 购买或生成SSL证书。

  2. (可选)若已从阿里云购买证书,需下载SSL证书文件到本地。

  3. 创建Secret,存储证书及私钥。

    控制台

    1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择配置管理 > 保密字典

    3. 保密字典页面,选择default命名空间后,单击左侧创建,在弹出面板中配置新的保密字典。配置完成后,单击确定

      • 名称nginx-ingress-tls

      • 类型TLS证书

      • 证书:证书文件(.crt.pem)中的完整内容

      • 密钥:私钥文件(.key)中的完整内容

    kubectl

    将以下<PUBLIC_CERT> <PRIVATE_KEY>替换成实际的证书文件(.crt.pem)路径和私钥文件(.key)路径,然后执行命令将证书和私钥存储为Secret。

    # --key 参数指定私钥文件,--cert 参数指定证书文件
    kubectl create secret tls nginx-ingress-tls --cert <PUBLIC_CERT> --key <PRIVATE_KEY>

配置Ingress暴露服务

  1. 登录容器服务管理控制台,单击目标集群名称,在集群详情页左侧导航栏选择组件管理

  2. 在搜索框输入Nginx Ingress Controller并定位组件,然后在目标组件卡片上单击安装

    v1.2之前版本的组件已不再维护,请升级Nginx Ingress Controller组件至最新版。
  3. 配置Ingress,通过注解(annotations)指明后端协议为gRPC,并引用上一步创建的Secret。

    控制台

    1. 在左侧导航栏,选择网络 > 路由。选择default命名空间,单击创建 Ingress

    2. 添加以下Ingress配置,单击确定

      • 网关类型:选择Nginx Ingress

      • 名称grpc-ingress

      • 域名grpc.example.com

      • 路径映射路径/匹配规则前缀匹配(Prefix)服务名称grpc-service端口50051

      • TLS配置:开启。域名grpc.example.com保密字典nginx-ingress-tls

      • 注解:名称:nginx.ingress.kubernetes.io/backend-protocol,值GRPC

    3. 路由列表页,查看新建的Ingress,获取访问端点地址。

      Nginx Ingress生效过程耗时约10秒,可稍后单击刷新按钮获取端点信息。若长时间未更新端点信息,可单击路由名称,进入事件页签,进行异常问题排查

    kubectl

    1. 将以下YAML内容保存为grpc-ingress.yaml文件,然后执行kubectl apply -f grpc-ingress.yaml命令。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: grpc-ingress
        annotations:
          # 关键:指明后端服务为gRPC协议
          nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
      spec:
        ingressClassName: nginx
        # 配置TLS,引用存储证书的Secret
        tls:
        - hosts:
          - grpc.example.com             # 替换为gRPC服务域名
          secretName: nginx-ingress-tls  # 上一步创建Secret指定的名称
        rules:
        - host: grpc.example.com         # 替换为gRPC服务域名
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: grpc-service
                  port:
                    number: 50051
    2. 获取访问端点地址。Ingress IP分配会有延迟,若无输出结果,可等待10秒后重试。

      ADDRESS=$(kubectl get ingress grpc-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      echo $ADDRESS

访问gRPC服务

  1. 为便于测试,以下提供本地域名映射方法。

    • macOS / Linuxsudo vi /etc/hosts

    • Windows: 以管理员身份打开记事本,然后打开 C:\Windows\System32\drivers\etc\hosts

    将以下地址替换为实际访问端点地址,在文件末尾添加以下域名映射记录并保存。

    47.102.XX.XX grpc.example.com
  2. 安装grpcurl工具。调用gRPC服务接口。

    grpcurl -d '{"name": "gRPC"}' grpc.example.com:443 helloworld.Greeter/SayHello
    {
      "message": "Hello gRPC"
    }

使用限制

由于gRPC基于长连接的特性,Nginx Ingress暂不支持为其配置服务权重(service-weight)路由。

常见问题

如何生成自签名证书?

执行以下命令可生成一个域名为grpc.example.com、有效期为365天的自签名证书(grpc.crt)和私钥(grpc.key)。

openssl req -x509 -newkey rsa:2048 -keyout grpc.key -out grpc.crt -days 365 -nodes \
  -subj "/CN=grpc.example.com" \
  -addext "subjectAltName=DNS:grpc.example.com"
重要

自签名证书缺乏权威 CA 认证,浏览器及各类客户端默认不予信任,用户访问时将触发安全警告,请勿在生产环境中使用。

SSL证书和TLS证书的区别?

SSL (Secure Sockets Layer) 为早期的加密协议,现已被更安全的TLS (Transport Layer Security) 协议取代。

在行业术语中,“SSL证书”已成为一个习惯性描述,其更准确的名称应为“TLS证书”。

相关文档