Aws-external-dns: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
| (не показано 26 промежуточных версий этого же участника) | |||
| Строка 1: | Строка 1: | ||
[[Категория: AWS]] |
[[Категория: AWS]] |
||
| − | [[Категория: |
+ | [[Категория: k8s]] |
[[Категория: EKS]] |
[[Категория: EKS]] |
||
| + | [[Категория: ExternalDNS]] |
||
| + | |||
=Постановка задачи= |
=Постановка задачи= |
||
Задача: есть некоторый базовый домен <code>mydomain.tld</code>, который лежит на серверах AWS в Route53 |
Задача: есть некоторый базовый домен <code>mydomain.tld</code>, который лежит на серверах AWS в Route53 |
||
<BR> |
<BR> |
||
Требуется при разворачивании приложения в EKS автоматически создавать записи типа CNAME и <BR> |
Требуется при разворачивании приложения в EKS автоматически создавать записи типа CNAME и <BR> |
||
| − | направлять их на балансировщик (Ingress или другой, но пока Ingress), |
+ | направлять их на балансировщик (<code>Ingress</code> или другой, в перспективе ALB но пока <code>Ingress</code>), |
при запуске экземпляра приложения, например для <BR> |
при запуске экземпляра приложения, например для <BR> |
||
экземпляра <B><code>staging</code></B> создать записи |
экземпляра <B><code>staging</code></B> создать записи |
||
| Строка 16: | Строка 18: | ||
Имя экземпляра приложения <B><code>staging</code></B> может быть произвольным |
Имя экземпляра приложения <B><code>staging</code></B> может быть произвольным |
||
| + | =Обзор решения= |
||
| − | =Решение= |
||
| + | Для того что бы работать с доменами как с ресурсами k8s требуется обработчик этих ресурсов, <BR> |
||
| ⚫ | |||
| + | в этом случае это [https://github.com/kubernetes-sigs/external-dns ExternalDns] |
||
| + | <BR> |
||
| + | Далее настройки касаются только AWS, в случае других провайдеров/регистраторо настройки будут отличаться |
||
| + | <BR> |
||
| + | * Создать роль которая разрешает модификацию DNS |
||
| + | * Создать политику Trust Policy — это специальный документ JSON, ВСТРОЕННЫЙ В РОЛЬ, НЕ ОТДЕЛЬНАЯ СУЩНОСТЬ, который определяет, кто имеет право "представлять" IAM роль, то есть использовать её права. |
||
| + | Она не определяет, что роль может делать. Она определяет, кто может её использовать. Например: |
||
| + | ** EC2-инстанс |
||
| + | ** Lambda-функция |
||
| + | ** Конкретный экзкмпляр Kubernetes пода (через запуск пода от имени Service Account) через OIDC |
||
| + | |||
| + | * Policy привязывается к <code>IAM ROLE с trust policy</code> |
||
| + | * Создается сераисный аккаунт с аннотацией |
||
| + | <PRE> |
||
| + | apiVersion: v1 |
||
| + | kind: ServiceAccount |
||
| + | metadata: |
||
| + | name: my-sa |
||
| + | namespace: my-namespace |
||
| + | annotations: |
||
| + | eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/MyEksIamRole |
||
| + | </PRE> |
||
| + | Который будет обладать всеми правами прописанными в полиси |
||
| + | * Под этим аккаунтом запускается POD который следит за ДНС и вносит изменения при необходимости |
||
| + | |||
| ⚫ | |||
Для начала потребуется создать политику следующего вида: |
Для начала потребуется создать политику следующего вида: |
||
| Строка 58: | Строка 86: | ||
<code> aws route53 list-hosted-zones-by-name | jq '.HostedZones[] | select(.Name=="<b>mydomain.tld</b>") | .Id' </code> |
<code> aws route53 list-hosted-zones-by-name | jq '.HostedZones[] | select(.Name=="<b>mydomain.tld</b>") | .Id' </code> |
||
| − | + | =Создание IAM Role (Trust Policy)= |
|
Далее требуется создать роль (которая далее будет привязана к Service Account). |
Далее требуется создать роль (которая далее будет привязана к Service Account). |
||
| + | <BR> |
||
| + | Это отдельный вид роли который позвоялет получить права этой роли для Service Account (отсюда и Trust Policy - часть роли, описываюший разрешение на то кто может представляться этой рольую) |
||
<BR> |
<BR> |
||
Пример роли (в web console я не нашл как вставить сразу json но результат можно посмотреть в таком виде и сравнить с желаемым): |
Пример роли (в web console я не нашл как вставить сразу json но результат можно посмотреть в таком виде и сравнить с желаемым): |
||
| Строка 108: | Строка 138: | ||
но возможно эта информация уже устарела или зависит от того как именно создавался кластер |
но возможно эта информация уже устарела или зависит от того как именно создавался кластер |
||
}} |
}} |
||
| + | |||
| + | =Привязка политики к роли= |
||
| + | Я "накликал" это в Web Console :( |
||
=External DNS= |
=External DNS= |
||
| + | |||
| ⚫ | |||
| + | * https://github.com/kubernetes-sigs/external-dns |
||
| ⚫ | |||
| + | |||
| ⚫ | |||
| ⚫ | |||
| + | ==Подготовительная работа== |
||
<BR> |
<BR> |
||
Добавить репозиторий |
Добавить репозиторий |
||
| Строка 121: | Строка 158: | ||
helm pull bitnami/external-dns |
helm pull bitnami/external-dns |
||
</PRE> |
</PRE> |
||
| − | Создать отдельный namespace (опционально - но лучше конечно создавать): |
+ | Создать отдельный <code>namespace</code> (опционально - но лучше конечно создавать): |
<PRE> |
<PRE> |
||
kubectl create namespace external-dns |
kubectl create namespace external-dns |
||
| Строка 144: | Строка 181: | ||
serviceaccount/external-dns created |
serviceaccount/external-dns created |
||
</PRE> |
</PRE> |
||
| + | <BR> |
||
| + | {{caution|text= |
||
| ⚫ | |||
| + | <code>external-dns.alpha.kubernetes.io/controller</code> <BR> |
||
| + | совпадает с указанной в параметре <code>--controller</code>. <BR> |
||
| ⚫ | |||
| + | }} |
||
| + | ==Установка== |
||
| − | |||
| + | Устанавлить <code>External DNS</code> с нужными параметрами |
||
| − | |||
| + | <PRE> |
||
| − | |||
| − | |||
| ⚫ | |||
| ⚫ | |||
| − | |||
helm upgrade \ |
helm upgrade \ |
||
--install external-dns bitnami/external-dns \ |
--install external-dns bitnami/external-dns \ |
||
| Строка 166: | Строка 206: | ||
--set txtOwnerId=external-dns \ |
--set txtOwnerId=external-dns \ |
||
--set logLevel=debug |
--set logLevel=debug |
||
| + | </PRE> |
||
| + | |||
| + | * <code> serviceAccount.name=external-dns</code> - использовать предсозданный <code>Service Account</code> |
||
| + | * <code> serviceAccount.create=false</code> - не создавать <code>Service Account</code> при установке chart |
||
| + | * <code> provider=aws</code> - очевидно |
||
| + | * <code> sources={ingress}</code> - смотреть на домены только на <code>Ingress</code> (это массив, его элементы можно перечислить, я не уверен что это елинственно-возможный синтаксис) |
||
| + | * <code> domainFilters[0]=mydomain.tld</code> - оционально, разрешить работу только с 2 зонами (это тоже массив) |
||
| + | * <code> domainFilters[1]=myseconddomain.tld</code> |
||
| + | * <code> policy=upsert-only</code> насколько я понимаю, эта опция означает "не удалять", другими словами при удалении <code>Ingress</code> запись останется (вероятно это более безопасный вариант?) |
||
| + | * <code> registry=txt</code> |
||
| + | * <code> txtOwnerId=external-dns</code> |
||
| + | * <code> logLevel=debug</code> (options: panic, debug, info, warning, error, fatal, trace) |
||
| + | |||
| + | {{caution|text= |
||
| + | Нигде в документации толком не сказано, что за опция <code>txt-owner-id</code> — она определяет значения <code>TXT</code>-записи,<BR> |
||
| + | которая создаётся <code>ExternalDNS</code> для записей, которые он создаёт, что бы отменить их как «свои», т.е. те, которые управляются им. |
||
| + | <BR> |
||
| + | Если, к примеру, у вас в домене уже есть запись <code>subdomain.example.com</code>, и к ней нет <code>TXT</code>, <BR> |
||
| + | которую добавляет <code>ExternalDNS</code>, то при создании <code>Ingress</code> с host: <code>subdomain.example.com</code> — <code>ExternalDNS</code> <BR> |
||
| + | ничего с существующей записью не сделает. |
||
| + | <BR> |
||
| + | (https://rtfm.co.ua/ru/kubernetes-obnovlenie-dns-v-route53-pri-sozdanii-ingress/) |
||
| + | }} |
||
| + | |||
| + | ==Настройка <code>Ingress</code>== |
||
| + | Настройка <code>Ingress</code> сводится к указанию правильной аннотации |
||
| + | <PRE> |
||
| + | apiVersion: networking.k8s.io/v1 |
||
| + | kind: Ingress |
||
| + | metadata: |
||
| + | annotations: |
||
| + | ... |
||
| + | external-dns.alpha.kubernetes.io/controller: dns-controller |
||
| + | ... |
||
| + | </PRE> |
||
| + | |||
| + | =Дополнительно проверить= |
||
| + | * Для домашней лабы - интеграцию с Mikrotk (Вроде бы заявлено) |
||
Текущая версия на 11:10, 29 июня 2025
Постановка задачи
Задача: есть некоторый базовый домен mydomain.tld, который лежит на серверах AWS в Route53
Требуется при разворачивании приложения в EKS автоматически создавать записи типа CNAME и
направлять их на балансировщик (Ingress или другой, в перспективе ALB но пока Ingress),
при запуске экземпляра приложения, например для
экземпляра staging создать записи
backend.staging.mydomain.tldfrontend.staging.mydomain.tldчто-то-еще.staging.mydomain.tld
Имя экземпляра приложения staging может быть произвольным
Обзор решения
Для того что бы работать с доменами как с ресурсами k8s требуется обработчик этих ресурсов,
в этом случае это ExternalDns
Далее настройки касаются только AWS, в случае других провайдеров/регистраторо настройки будут отличаться
- Создать роль которая разрешает модификацию DNS
- Создать политику Trust Policy — это специальный документ JSON, ВСТРОЕННЫЙ В РОЛЬ, НЕ ОТДЕЛЬНАЯ СУЩНОСТЬ, который определяет, кто имеет право "представлять" IAM роль, то есть использовать её права.
Она не определяет, что роль может делать. Она определяет, кто может её использовать. Например:
- EC2-инстанс
- Lambda-функция
- Конкретный экзкмпляр Kubernetes пода (через запуск пода от имени Service Account) через OIDC
- Policy привязывается к
IAM ROLE с trust policy - Создается сераисный аккаунт с аннотацией
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa
namespace: my-namespace
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/MyEksIamRole
Который будет обладать всеми правами прописанными в полиси
- Под этим аккаунтом запускается POD который следит за ДНС и вносит изменения при необходимости
IAM Policy
Для начала потребуется создать политику следующего вида:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ExternalDNSAccess",
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/Z1038XXXXXXXXXXXXXXX",
"arn:aws:route53:::hostedzone/Z0235XXXXXXXXXXXXXXX"
]
},
{
"Effect": "Allow",
"Action": "route53:ListHostedZones",
"Resource": "*"
}
]
}
В том пример присутствуют две записи:
"arn:aws:route53:::hostedzone/Z1038XXXXXXXXXXXXXXX", "arn:aws:route53:::hostedzone/Z0235XXXXXXXXXXXXXXX"
так как приложение использует более чем одну зону.
Для получения Id (Z1038XXXXXXXXXXXXXXX в примере) для домена mydomain.tld использовать комманду
aws route53 list-hosted-zones-by-name | jq '.HostedZones[] | select(.Name=="mydomain.tld") | .Id'
Создание IAM Role (Trust Policy)
Далее требуется создать роль (которая далее будет привязана к Service Account).
Это отдельный вид роли который позвоялет получить права этой роли для Service Account (отсюда и Trust Policy - часть роли, описываюший разрешение на то кто может представляться этой рольую)
Пример роли (в web console я не нашл как вставить сразу json но результат можно посмотреть в таком виде и сравнить с желаемым):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal": {
"Federated": "arn:aws:iam::54XXXXXXXXXX:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX"
},
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX:sub": [
"system:serviceaccount:external-dns:external-dns"
],
"oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX:aud": [
"sts.amazonaws.com"
]
}
}
}
]
}
Значения
arn:aws:iam::54XXXXXXXXXXэто ID аккаунтаoidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXXкак правильно называется это значение,
я не знаю, но получить его можно следующей коммандой:
aws eks describe-cluster --name education-eks-1o3RFCvh --query "cluster.identity.oidc.issuer"
education-eks-1o3RFCvhэто имя кластера
Вывод команды будет примерно таким:
"https://oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX"
|
В интиерентаах пишут что нужно отдельно включать OIDC командой eksctl utils associate-iam-oidc-provider --region=us-east-2 --cluster=education-eks-1o3RFCvh --approve но возможно эта информация уже устарела или зависит от того как именно создавался кластер |
Привязка политики к роли
Я "накликал" это в Web Console :(
External DNS
ExternalDNS это код который работает внутри кластера k8s от имени сервисного аккаунта,
связанного с IAM ролью и за счет этого получает все права, которые есть у роли
Подготовительная работа
Добавить репозиторий
helm repo add bitnami https://charts.bitnami.com/bitnami
При желании для изучения можно скачать чарт:
helm pull bitnami/external-dns
Создать отдельный namespace (опционально - но лучше конечно создавать):
kubectl create namespace external-dns
Подготовить конфигурационный файл SERVICE-ACCOUNT-external-dns.yaml для сервисного аккаунта следующего содержания:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
namespace: external-dns
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::54XXXXXXXXXX:role/ExternalDNSServiceAccountRole
В этом файле ключевой является аннотация:
arn:aws:iam::54XXXXXXXXXX:role/ExternalDNSServiceAccountRole- это ссылка на созданную IAM ROLE с правами работы с DNS
Создать Service Account
kubectl apply -f SERVICE-ACCOUNT-external-dns.yaml serviceaccount/external-dns created
|
ExternalDNS будет обрабатывать только те ресурсы, у которых аннотация |
Установка
Устанавлить External DNS с нужными параметрами
helm upgrade \
--install external-dns bitnami/external-dns \
--namespace external-dns \
--set serviceAccount.name=external-dns \
--set serviceAccount.create=false \
--set provider=aws \
--set sources={ingress} \
--set domainFilters[0]=mydomain.tld \
--set domainFilters[1]=myseconddomain.tld \
--set policy=upsert-only \
--set registry=txt \
--set txtOwnerId=external-dns \
--set logLevel=debug
serviceAccount.name=external-dns- использовать предсозданныйService AccountserviceAccount.create=false- не создаватьService Accountпри установке chartprovider=aws- очевидноsources={ingress}- смотреть на домены только наIngress(это массив, его элементы можно перечислить, я не уверен что это елинственно-возможный синтаксис)domainFilters[0]=mydomain.tld- оционально, разрешить работу только с 2 зонами (это тоже массив)domainFilters[1]=myseconddomain.tldpolicy=upsert-onlyнасколько я понимаю, эта опция означает "не удалять", другими словами при удаленииIngressзапись останется (вероятно это более безопасный вариант?)registry=txttxtOwnerId=external-dnslogLevel=debug(options: panic, debug, info, warning, error, fatal, trace)
|
Нигде в документации толком не сказано, что за опция |
Настройка Ingress
Настройка Ingress сводится к указанию правильной аннотации
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
...
external-dns.alpha.kubernetes.io/controller: dns-controller
...
Дополнительно проверить
- Для домашней лабы - интеграцию с Mikrotk (Вроде бы заявлено)