×

External DNS Operator 部署和管理 ExternalDNS,为来自外部 DNS 提供商(如 Amazon Route 53)的服务和路由提供 Red Hat OpenShift Service on AWS (ROSA) 集群的名称解析。在本教程中,我们将使用辅助 Ingress 控制器部署和配置 External DNS Operator 以管理 Amazon Route 53 中的 DNS 记录。

External DNS Operator 不支持使用 IAM 角色进行服务账户 (IRSA) 的 STS,而是使用长期有效的身份访问管理 (IAM) 凭据。当 Operator 支持 STS 时,本教程将进行更新。

先决条件

  • 一个 ROSA Classic 集群

    目前不支持带有 HCP 的 ROSA。

  • 具有 cluster-admin 权限的用户帐户

  • OpenShift CLI (oc)

  • Amazon Web Services (AWS) CLI (aws)

  • 一个唯一的域名,例如 apps.example.com

  • 上述域名的 Amazon Route 53 公共托管区域

设置您的环境

  1. 配置以下环境变量

    $ export DOMAIN=<apps.example.com> (1)
    $ export AWS_PAGER=""
    $ export CLUSTER=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${CLUSTER}/external-dns"
    $ mkdir -p ${SCRATCH}
    1 替换为您要用于 IngressController 的自定义域名。
  2. 在继续下一部分之前,请确保所有字段都正确输出。

    $ echo "Cluster: ${CLUSTER}, Region: ${REGION}, AWS Account ID: ${AWS_ACCOUNT_ID}"

    前面命令的“集群”输出可能是您的集群名称、集群的内部 ID 或集群的域名前缀。如果您更倾向于使用其他标识符,您可以通过运行以下命令手动设置此值。

    $ export CLUSTER=my-custom-value

辅助 Ingress 控制器设置

使用以下步骤使用自定义域名部署辅助 Ingress 控制器。

先决条件
  • 一个唯一的域名,例如 apps.example.com

  • 使用上面选择的自定义域名配置的通配符或 SAN TLS 证书 (CN=*.apps.example.com)

步骤
  1. 从私钥和公钥证书创建一个新的 TLS 密钥,其中 fullchain.pem 是您的完整通配符证书链(包括任何中间证书),privkey.pem 是您的通配符证书的私钥。

    $ oc -n openshift-ingress create secret tls external-dns-tls --cert=fullchain.pem --key=privkey.pem
  2. 创建一个新的 IngressController 资源。

    $ cat << EOF | oc apply -f -
    apiVersion: operator.openshift.io/v1
    kind: IngressController
    metadata:
      name: external-dns-ingress
      namespace: openshift-ingress-operator
    spec:
      domain: ${DOMAIN}
      defaultCertificate:
        name: external-dns-tls
      endpointPublishingStrategy:
        loadBalancer:
          dnsManagementPolicy: Unmanaged
          providerParameters:
            aws:
              type: NLB
            type: AWS
          scope: External
        type: LoadBalancerService
    EOF

    IngressController 示例将在您的 AWS 账户中创建一个可访问互联网的网络负载均衡器 (NLB)。要改为配置内部 NLB,请在创建 IngressController 资源之前将 .spec.endpointPublishingStrategy.loadBalancer.scope 参数设置为 Internal

  3. 验证您的自定义域名 IngressController 是否已成功创建外部负载均衡器。

    $ oc -n openshift-ingress get service/router-external-dns-ingress
    示例输出
    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE
    router-external-dns-ingress   LoadBalancer   172.30.71.250   a4838bb991c6748439134ab89f132a43-aeae124077b50c01.elb.us-east-1.amazonaws.com   80:32227/TCP,443:30310/TCP   43s

准备您的 AWS 账户

  1. 检索 Amazon Route 53 公共托管区域 ID。

    $ export ZONE_ID=$(aws route53 list-hosted-zones-by-name --output json \
      --dns-name "${DOMAIN}." --query 'HostedZones[0]'.Id --out text | sed 's/\/hostedzone\///')
  2. 准备一份文档,其中包含必要的 DNS 更改,以启用 Ingress 控制器的规范域的 DNS 解析。

    $ NLB_HOST=$(oc -n openshift-ingress get service/router-external-dns-ingress -ojsonpath="{.status.loadBalancer.ingress[0].hostname}")
    $ cat << EOF > "${SCRATCH}/create-cname.json"
    {
      "Comment":"Add CNAME to ingress controller canonical domain",
      "Changes":[{
          "Action":"CREATE",
          "ResourceRecordSet":{
            "Name": "router-external-dns-ingress.${DOMAIN}",
          "Type":"CNAME",
          "TTL":30,
          "ResourceRecords":[{
            "Value": "${NLB_HOST}"
          }]
        }
      }]
    }
    EOF

    External DNS Operator 使用此规范域名作为 CNAME 记录的目标。

  3. 提交您对 Amazon Route 53 的更改以进行传播。

    aws route53 change-resource-record-sets \
      --hosted-zone-id ${ZONE_ID} \
      --change-batch file://${SCRATCH}/create-cname.json
  4. 创建一个 AWS IAM 策略文档,允许 External DNS Operator 仅更新自定义域名公共托管区域。

    $ cat << EOF > "${SCRATCH}/external-dns-policy.json"
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "route53:ChangeResourceRecordSets"
          ],
          "Resource": [
            "arn:aws:route53:::hostedzone/${ZONE_ID}"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
            "route53:ListHostedZones",
            "route53:ListResourceRecordSets"
          ],
          "Resource": [
            "*"
          ]
        }
      ]
    }
    EOF
  5. 创建一个 AWS IAM 用户。

    $ aws iam create-user --user-name "${CLUSTER}-external-dns-operator"
  6. 附加策略。

    $ aws iam attach-user-policy --user-name "${CLUSTER}-external-dns-operator" --policy-arn $POLICY_ARN

    将来这将更改为使用 IRSA 的 STS。

  7. 为 IAM 用户创建 AWS 密钥。

    $ SECRET_ACCESS_KEY=$(aws iam create-access-key --user-name "${CLUSTER}-external-dns-operator")
  8. 创建静态凭据。

    $ cat << EOF > "${SCRATCH}/credentials"
    [default]
    aws_access_key_id = $(echo $SECRET_ACCESS_KEY | jq -r '.AccessKey.AccessKeyId')
    aws_secret_access_key = $(echo $SECRET_ACCESS_KEY | jq -r '.AccessKey.SecretAccessKey')
    EOF

安装 External DNS Operator

  1. 创建一个新项目。

    $ oc new-project external-dns-operator
  2. 从 OperatorHub 安装 External DNS Operator。

    $ cat << EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: external-dns-group
      namespace: external-dns-operator
    spec:
      targetNamespaces:
      - external-dns-operator
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: external-dns-operator
      namespace: external-dns-operator
    spec:
      channel: stable-v1.1
      installPlanApproval: Automatic
      name: external-dns-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
    EOF
  3. 等待 External DNS Operator 运行。

    $ oc rollout status deploy external-dns-operator --timeout=300s
  4. 从 AWS IAM 用户凭据创建密钥。

    $ oc -n external-dns-operator create secret generic external-dns \
      --from-file "${SCRATCH}/credentials"
  5. 部署 ExternalDNS 控制器。

    $ cat << EOF | oc apply -f -
    apiVersion: externaldns.olm.openshift.io/v1beta1
    kind: ExternalDNS
    metadata:
      name: ${DOMAIN}
    spec:
      domains:
        - filterType: Include
          matchType: Exact
          name: ${DOMAIN}
      provider:
        aws:
          credentials:
            name: external-dns
        type: AWS
      source:
        openshiftRouteOptions:
          routerName: external-dns-ingress
        type: OpenShiftRoute
      zones:
        - ${ZONE_ID}
    EOF
  6. 等待控制器运行。

    $ oc rollout status deploy external-dns-${DOMAIN} --timeout=300s

部署示例应用程序

现在 ExternalDNS 控制器正在运行,您可以部署一个示例应用程序来确认在公开新路由时自定义域名已配置并受信任。

  1. 为您的示例应用程序创建一个新项目。

    $ oc new-project hello-world
  2. 部署一个 hello world 应用程序。

    $ oc new-app -n hello-world --image=docker.io/openshift/hello-openshift
  3. 为应用程序创建一个路由,并指定您的自定义域名。

    $ oc -n hello-world create route edge --service=hello-openshift hello-openshift-tls \
    --hostname hello-openshift.${DOMAIN}
  4. 检查 ExternalDNS 是否自动创建了 DNS 记录。

    记录可能需要几分钟才能出现在 Amazon Route 53 中。

    $ aws route53 list-resource-record-sets --hosted-zone-id ${ZONE_ID} \
       --query "ResourceRecordSets[?Type == 'CNAME']" | grep hello-openshift
  5. 可选:您还可以查看指示它们由 ExternalDNS 创建的 TXT 记录。

    $ aws route53 list-resource-record-sets --hosted-zone-id ${ZONE_ID} \
       --query "ResourceRecordSets[?Type == 'TXT']" | grep ${DOMAIN}
  6. 将新创建的DNS记录 curl 到您的示例应用程序,以验证“hello world”应用程序是否可访问。

    $ curl https://hello-openshift.${DOMAIN}
    示例输出
    Hello OpenShift!