×

您可以为离开集群的流量分配一致的 IP 地址,例如需要基于 IP 的配置才能满足安全标准的安全组。

默认情况下,Red Hat OpenShift Service on AWS (ROSA) 使用 OVN-Kubernetes 容器网络接口 (CNI) 从池中分配随机 IP 地址。这可能会使配置安全锁定不可预测或开放。

请参阅配置出站 IP 地址了解更多信息。

目标
  • 学习如何为出站集群流量配置一组可预测的 IP 地址。

先决条件
  • 使用 OVN-Kubernetes 部署的 ROSA 集群

  • OpenShift CLI(oc

  • ROSA CLI(rosa

  • jq

设置环境变量

  • 运行以下命令设置环境变量

    替换ROSA_MACHINE_POOL_NAME变量的值以定位不同的机器池。

    $ export ROSA_CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export ROSA_MACHINE_POOL_NAME=worker

确保容量

为每个公共云提供商,分配给每个节点的 IP 地址数量是有限制的。

  • 运行以下命令验证足够的容量

    $ oc get node -o json | \
        jq '.items[] |
            {
                "name": .metadata.name,
                "ips": (.status.addresses | map(select(.type == "InternalIP") | .address)),
                "capacity": (.metadata.annotations."cloud.network.openshift.io/egress-ipconfig" | fromjson[] | .capacity.ipv4)
            }'
    示例输出
    ---
    {
      "name": "ip-10-10-145-88.ec2.internal",
      "ips": [
        "10.10.145.88"
      ],
      "capacity": 14
    }
    {
      "name": "ip-10-10-154-175.ec2.internal",
      "ips": [
        "10.10.154.175"
      ],
      "capacity": 14
    }
    ---

创建出站 IP 规则

  1. 在创建出站 IP 规则之前,请确定您将使用哪些出站 IP。

    您选择的出站 IP 应作为配置工作节点的子网的一部分存在。

  2. 可选:保留您请求的出站 IP 以避免与 AWS 虚拟私有云 (VPC) 动态主机配置协议 (DHCP) 服务冲突。

    AWS CIDR 预留文档页面上请求显式 IP 预留。

将出站 IP 分配给命名空间

  1. 运行以下命令创建一个新项目

    $ oc new-project demo-egress-ns
  2. 运行以下命令为命名空间内的所有 Pod 创建出站规则

    $ cat <<EOF | oc apply -f -
    apiVersion: k8s.ovn.org/v1
    kind: EgressIP
    metadata:
      name: demo-egress-ns
    spec:
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      egressIPs:
        - 10.10.100.253
        - 10.10.150.253
        - 10.10.200.253
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: demo-egress-ns
    EOF

将出站 IP 分配给 Pod

  1. 运行以下命令创建一个新项目

    $ oc new-project demo-egress-pod
  2. 运行以下命令为 Pod 创建出站规则

    spec.namespaceSelector 是必填字段。

    $ cat <<EOF | oc apply -f -
    apiVersion: k8s.ovn.org/v1
    kind: EgressIP
    metadata:
      name: demo-egress-pod
    spec:
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      egressIPs:
        - 10.10.100.254
        - 10.10.150.254
        - 10.10.200.254
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: demo-egress-pod
      podSelector:
        matchLabels:
          run: demo-egress-pod
    EOF

标记节点

  1. 运行以下命令获取您待处理的出站 IP 分配

    $ oc get egressips
    示例输出
    NAME              EGRESSIPS       ASSIGNED NODE   ASSIGNED EGRESSIPS
    demo-egress-ns    10.10.100.253
    demo-egress-pod   10.10.100.254

    您创建的出站 IP 规则仅适用于具有k8s.ovn.org/egress-assignable标签的节点。确保该标签仅位于特定机器池上。

  2. 使用以下命令将标签分配给您的机器池

    如果您依赖节点标签作为机器池,则此命令将替换这些标签。请务必将所需的标签输入到--labels字段中,以确保您的节点标签保持不变。

    $ rosa update machinepool ${ROSA_MACHINE_POOL_NAME} \
      --cluster="${ROSA_CLUSTER_NAME}" \
      --labels "k8s.ovn.org/egress-assignable="

查看出站 IP

  • 运行以下命令查看出站 IP 分配

    $ oc get egressips
    示例输出
    NAME              EGRESSIPS       ASSIGNED NODE                   ASSIGNED EGRESSIPS
    demo-egress-ns    10.10.100.253   ip-10-10-156-122.ec2.internal   10.10.150.253
    demo-egress-pod   10.10.100.254   ip-10-10-156-122.ec2.internal   10.10.150.254

验证

部署示例应用程序

要测试出站 IP 规则,请创建一个限制为我们指定的出站 IP 地址的服务。这模拟了期望少量 IP 地址的外部服务。

  1. 运行echoserver命令来复制请求

    $ oc -n default run demo-service --image=gcr.io/google_containers/echoserver:1.4
  2. 将 Pod 公开为服务,并将入口限制为您指定的出站 IP 地址,方法是运行以下命令

    $ cat <<EOF | oc apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-service
      namespace: default
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
        service.beta.kubernetes.io/aws-load-balancer-internal: "true"
    spec:
      selector:
        run: demo-service
      ports:
        - port: 80
          targetPort: 8080
      type: LoadBalancer
      externalTrafficPolicy: Local
      # NOTE: this limits the source IPs that are allowed to connect to our service.  It
      #       is being used as part of this demo, restricting connectivity to our egress
      #       IP addresses only.
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      loadBalancerSourceRanges:
        - 10.10.100.254/32
        - 10.10.150.254/32
        - 10.10.200.254/32
        - 10.10.100.253/32
        - 10.10.150.253/32
        - 10.10.200.253/32
    EOF
  3. 检索负载均衡器主机名并将其保存为环境变量,方法是运行以下命令

    $ export LOAD_BALANCER_HOSTNAME=$(oc get svc -n default demo-service -o json | jq -r '.status.loadBalancer.ingress[].hostname')

测试命名空间出站

  1. 启动交互式 shell 以测试命名空间出站规则

    $ oc run \
      demo-egress-ns \
      -it \
      --namespace=demo-egress-ns \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. 向负载均衡器发送请求,并确保您可以成功连接

    $ curl -s http://$LOAD_BALANCER_HOSTNAME
  3. 检查输出以查看是否成功连接

    client_address是负载均衡器的内部 IP 地址,而不是您的出站 IP。您可以通过连接到限制为.spec.loadBalancerSourceRanges的服务来验证您是否已正确配置客户端地址。

    示例输出
    CLIENT VALUES:
    client_address=10.10.207.247
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com
    user-agent=curl/7.76.1
    BODY:
    -no body in request-
  4. 运行以下命令退出 Pod

    $ exit

测试 Pod 出站

  1. 启动交互式 shell 以测试 Pod 出站规则

    $ oc run \
      demo-egress-pod \
      -it \
      --namespace=demo-egress-pod \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. 运行以下命令向负载均衡器发送请求

    $ curl -s http://$LOAD_BALANCER_HOSTNAME
  3. 检查输出以查看是否成功连接

    client_address是负载均衡器的内部 IP 地址,而不是您的出站 IP。您可以通过连接到限制为.spec.loadBalancerSourceRanges的服务来验证您是否已正确配置客户端地址。

    示例输出
    CLIENT VALUES:
    client_address=10.10.207.247
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com
    user-agent=curl/7.76.1
    BODY:
    -no body in request-
  4. 运行以下命令退出 Pod

    $ exit

可选:测试被阻止的出站

  1. 可选:运行以下命令测试当出站规则不适用时流量是否被成功阻止

    $ oc run \
      demo-egress-pod-fail \
      -it \
      --namespace=demo-egress-pod \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. 运行以下命令向负载均衡器发送请求

    $ curl -s http://$LOAD_BALANCER_HOSTNAME
  3. 如果命令不成功,则表示出站已成功阻止。

  4. 运行以下命令退出 Pod

    $ exit

清理集群

  1. 运行以下命令清理集群

    $ oc delete svc demo-service -n default; \
    $ oc delete pod demo-service -n default; \
    $ oc delete project demo-egress-ns; \
    $ oc delete project demo-egress-pod; \
    $ oc delete egressip demo-egress-ns; \
    $ oc delete egressip demo-egress-pod
  2. 运行以下命令清理已分配的节点标签

    如果您依赖节点标签来管理您的机器池,此命令将替换这些标签。请将您所需的标签输入到--labels字段中,以确保您的节点标签保持不变。

    $ rosa update machinepool ${ROSA_MACHINE_POOL_NAME} \
      --cluster="${ROSA_CLUSTER_NAME}" \
      --labels ""