Skip to content

ExternalDNS for Route53

func create hosted zone

install

install-with-eksdemo-

install-

  • https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md
  • 创建所需要的服务账号 (create service account)

    • 确保 EKS 集群名称正确 (ensure eks cluster name is correct)
    • 确保使用正确的 Region (ensure region is correct)
    • 确保域名匹配所需 (ensure domain name is correct)
      CLUSTER_NAME=ekscluster1
      AWS_REGION=us-east-2
      DOMAIN_NAME=api0413.aws.panlm.xyz
      EXTERNALDNS_NS=externaldns
      export AWS_PAGER=""
      
      # create namespace if it does not yet exist
      kubectl get namespaces | grep -q $EXTERNALDNS_NS || \
        kubectl create namespace $EXTERNALDNS_NS
      
      cat >externaldns-policy.json <<-EOF
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
              "arn:aws:route53:::hostedzone/*"
            ]
          },
          {
            "Effect": "Allow",
            "Action": [
              "route53:ListHostedZones",
              "route53:ListResourceRecordSets"
            ],
            "Resource": [
              "*"
            ]
          }
        ]
      }
      EOF
      
      POLICY_NAME=AllowExternalDNSUpdates-${RANDOM}
      aws iam create-policy --policy-name ${POLICY_NAME} --policy-document file://externaldns-policy.json
      
      # example: arn:aws:iam::XXXXXXXXXXXX:policy/AllowExternalDNSUpdates
      export POLICY_ARN=$(aws iam list-policies \
       --query 'Policies[?PolicyName==`'"${POLICY_NAME}"'`].Arn' --output text)
      
      eksctl create iamserviceaccount \
        --cluster ${CLUSTER_NAME} \
        --name "external-dns" \
        --namespace ${EXTERNALDNS_NS:-"default"} \
        --override-existing-serviceaccounts \
        --attach-policy-arn $POLICY_ARN \
        --approve
      
  • 使用上述服务账号安装 ExternalDNS (install ExternalDNS with existed SA)

    echo ${EXTERNALDNS_NS}
    echo ${DOMAIN_NAME}
    echo ${AWS_REGION}
    
    envsubst >externaldns-with-rbac.yaml <<-EOF
    # comment out sa if it was previously created
    # apiVersion: v1
    # kind: ServiceAccount
    # metadata:
    #   name: external-dns
    #   labels:
    #     app.kubernetes.io/name: external-dns
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: external-dns
      labels:
        app.kubernetes.io/name: external-dns
    rules:
    
      - apiGroups: [""]
        resources: ["services","endpoints","pods","nodes"]
        verbs: ["get","watch","list"]
      - apiGroups: ["extensions","networking.k8s.io"]
        resources: ["ingresses"]
        verbs: ["get","watch","list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: external-dns-viewer
      labels:
        app.kubernetes.io/name: external-dns
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: external-dns
    subjects:
      - kind: ServiceAccount
        name: external-dns
        namespace: ${EXTERNALDNS_NS} # change to desired namespace: externaldns, kube-addons
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: external-dns
      labels:
        app.kubernetes.io/name: external-dns
    spec:
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app.kubernetes.io/name: external-dns
      template:
        metadata:
          labels:
            app.kubernetes.io/name: external-dns
        spec:
          serviceAccountName: external-dns
          containers:
            - name: external-dns
              image: registry.k8s.io/external-dns/external-dns:v0.13.2
              args:
                - --source=service
                - --source=ingress
                - --domain-filter=${DOMAIN_NAME} # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
                - --provider=aws
                - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
                - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
                - --registry=txt
                - --txt-owner-id=external-dns
              env:
                - name: AWS_DEFAULT_REGION
                  value: ${AWS_REGION} # change to region where EKS is installed
         # # Uncommend below if using static credentials
         #        - name: AWS_SHARED_CREDENTIALS_FILE
         #          value: /.aws/credentials
         #      volumeMounts:
         #        - name: aws-credentials
         #          mountPath: /.aws
         #          readOnly: true
         #  volumes:
         #    - name: aws-credentials
         #      secret:
         #        secretName: external-dns
    EOF
    
    kubectl create --filename externaldns-with-rbac.yaml \
      --namespace ${EXTERNALDNS_NS:-"default"}
    

sample

verify

  • create namespace
    NS=verify
    kubectl create ns ${NS}
    

service sample

  • create nlb (no more clb, 20230423) with service definition

    envsubst >verify-nginx.yaml <<-EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      annotations:
        external-dns.alpha.kubernetes.io/hostname: nginx.${DOMAIN_NAME}
        service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    spec:
      type: LoadBalancer
      ports:
      - port: 80
        name: http
        targetPort: 80
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            ports:
            - containerPort: 80
              name: http
    EOF
    
    kubectl create --filename verify-nginx.yaml -n ${NS:-default}
    

  • wait nlb available and execute

    aws route53 list-resource-record-sets --output json --hosted-zone-id $ZONE_ID \
      --query "ResourceRecordSets[?Name == 'nginx.${DOMAIN_NAME}.']|[?Type == 'A']"
    
    aws route53 list-resource-record-sets --output json --hosted-zone-id $ZONE_ID \
      --query "ResourceRecordSets[?Name == 'nginx.${DOMAIN_NAME}.']|[?Type == 'TXT']"
    
    dig +short nginx.${DOMAIN_NAME}. A
    
    curl http://nginx.${DOMAIN_NAME}
    

ingress sample

  • ensure certificate is existed and create alb

    echo ${CERTIFICATE_ARN}
    
    envsubst >verify-nginx-ingress.yaml <<-EOF
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/tags: Environment=dev,Team=test,Application=nginx
        alb.ingress.kubernetes.io/target-type: ip
        alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
        alb.ingress.kubernetes.io/ssl-redirect: '443'
        alb.ingress.kubernetes.io/certificate-arn: ${CERTIFICATE_ARN}
    spec:
      ingressClassName: alb
      rules:
    
        - host: server.${DOMAIN_NAME}
          http:
            paths:
              - backend:
                  service:
                    name: nginx
                    port:
                      number: 80
                path: /
                pathType: Prefix
    EOF
    
    kubectl create --filename verify-nginx-ingress.yaml -n ${NS:-default}
    

  • wait alb available and execute

    aws route53 list-resource-record-sets --output json --hosted-zone-id $ZONE_ID \
      --query "ResourceRecordSets[?Name == 'server.${DOMAIN_NAME}.']"
    
    dig +short server.${DOMAIN_NAME}. A
    
    curl https://server.${DOMAIN_NAME}