În calitate de creator al Foo, o platformă pentru monitorizarea calității site-ului web, M-am străduit recent într-o migrare către Kubernetes și EKS (un serviciu AWS).

Kubernetes oferă un nivel robust de suport DNS. Din fericire pentru noi, în cadrul unui cluster, putem face referință la pod-uri după numele gazdei, așa cum este definit într-o specificație.

Dar dacă vrem să expunem o aplicație către lumea exterioară ca site web sub un domeniu static? Am crezut că acesta ar fi un caz obișnuit, bine documentat, dar băiatul m-am înșelat.

Să presupunem un serviciu numit foo în spațiul de nume Kubernetes bar. Un pod care rulează în spațiul de nume bar poate căuta acest serviciu făcând pur și simplu o interogare DNS pentru foo. Un pod care rulează în spațiul de nume quux poate căuta acest serviciu făcând o interogare DNS pentru foo.bar ~ DNS pentru servicii și poduri – Kubernetes

Da, este grozav ❤️ Dar acest lucru duce încă la multe mistere nerezolvate. Să facem acest pas la rând, nu ?! Această postare va aborda următoarele elemente.

  1. Cum se definesc serviciile
  2. Cum să expuneți mai multe servicii sub un singur server NGINX. Fără schmancy fantezie “Ingress” Necesar ?
  3. Cum să creați un DNS extern și să vă conectați la un domeniu ați achiziționat prin orice registru calificat, cum ar fi GoDaddy sau Google Domains, de exemplu. Vom folosi Traseul 53 și ExternalDNS să facă ridicarea grea.

Această postare presupune o configurare cu EKS și eksctl așa cum este documentat în „Începând cu eksctl“, dar multe dintre conceptele și exemplele din această postare ar putea fi aplicabile într-o varietate de configurații.

Pasul 1: definiți serviciile

Conectarea aplicațiilor cu serviciile explică modul de expunere a unei aplicații NGINX prin definirea unui Deployment și Service. Să mergem mai departe și să creăm 3 aplicații în același mod: o aplicație web orientată către utilizator, un API și un server proxy invers NGINX pentru a expune cele două aplicații sub o singură gazdă.

web-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        # etc, etc

web-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: web
  labels:
    app: web
spec:
  ports:
  - name: "3000"
    port: 3000
    targetPort: 3000
  selector:
    app: web

api-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        # etc, etc

api-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: api
  labels:
    app: api
spec:
  ports:
  - name: "3000"
    port: 3000
    targetPort: 3000
  selector:
    app: api

Destul de corect, să mergem mai departe!

Pasul 2: expuneți mai multe servicii sub un singur server NGINX

NGINX este un proxy invers prin faptul că transmite o solicitare prin trimiterea acesteia către o origine specificată, preia răspunsul și îl trimite înapoi către client.

Revenind la informațiile despre faptul că numele serviciilor sunt accesibile altor pod-uri dintr-un cluster, putem configura o configurație NGINX pentru a arăta așa ceva.

sites-enabled / www.example.com.conf

upstream api {
  server api:3000;
}

upstream web {
  server web:3000;
}

server {
  listen 80;

  server_name www.example.com;

  location / {
    proxy_pass http://web;
  }

  location /api {
    proxy_pass http://api;
  }
}

Rețineți cum putem face referință la gazde de origine cum ar fi web:3000 și api:300. Niiiice!

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    # this part will make more sense later
    external-dns.alpha.kubernetes.io/hostname: www.example.com
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  - name: "80"
    port: 80
    targetPort: 80
  selector:
    app: nginx

… și, am terminat! Dreapta? Din experiența mea, inițial așa am crezut. LoadBalancer oferă un IP accesibil extern. Puteți confirma rularea kubectl get svc și sigur că veți găsi un nume de gazdă listat în EXTERNAL-IP coloană.

Presupunând că ați achiziționat un domeniu de la un furnizor care oferă o interfață pentru gestionarea setărilor DNS, puteți adăuga pur și simplu această adresă URL ca CNAME si esti bun, nu? Ei bine, cam … dar nu atât.

Podurile Kubernetes sunt considerate a fi entități relativ efemere (mai degrabă decât durabile). Găsiți mai multe despre acest lucru în „Ciclul de viață al podului – Kubernetes“.

Cu toate acestea, oricând s-a făcut o schimbare semnificativă în ciclul de viață al unui serviciu, în cazul nostru aplicația NGINX, vom avea o adresă IP diferită, care la rândul său va provoca perioade de nefuncționare semnificative în aplicația noastră, care învinge un scop principal al Kubernetes – pentru a ajuta la stabilirea unei aplicații „extrem de disponibile”.

Bine, nu intra în panică – vom trece prin asta?

Pasul 3: Creați un serviciu DNS extern pentru a puncta dinamic NGINX

În pasul anterior, cu LoadBalancer spec. împreună cu EKS am creat de fapt un Balansator de sarcină elastic (pentru mai bine sau mai rău).

În această secțiune vom crea un serviciu DNS care ne indică echilibrarea sarcinii prin „înregistrarea ALIAS”. Această înregistrare ALIAS este în esență dinamică prin aceea că se creează una nouă de fiecare dată când serviciul nostru se schimbă. Stabilitatea este stabilită în înregistrările serverului de nume.

Tl; dr pentru porțiunea rămasă este pur și simplu urmați documentație pentru utilizarea ExternalDNS cu Route 53. Traseul 53 este „serviciu web Cloud Domain Name System (DNS)“.

Mai jos erau lucruri pe care trebuia să le fac, care nu erau evidente din documentație. Ține-te de caii tăi, acest lucru devine puțin scrappy.

  • eksctl utils associate-iam-oidc-provider --cluster=your-cluster-name pe eksctl documentația conturilor de servicii.
  • La crearea documentului de politică IAM în conformitate cu Documentație ExternalDNS, De fapt, a trebuit să o fac prin CLI vs online în contul meu. Am continuat să primesc această eroare: WebIdentityErr: failed to retrieve credentialsncaused by: AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentityntstatus code: 403. Când am creat politica prin CLI, problema a dispărut. Mai jos este comanda completă pe care ar trebui să o puteți copia literalmente și să o executați dacă aveți AWS CLI instalat.
aws iam create-policy 
  --policy-name AllowExternalDNSUpdates 
  --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["route53:ChangeResourceRecordSets"],"Resource":["arn:aws:route53:::hostedzone/*"]},{"Effect":"Allow","Action":["route53:ListHostedZones","route53:ListResourceRecordSets"],"Resource":["*"]}]}'
  • Utilizați politica de ieșire ARN de mai sus pentru a crea un rol IAM legat de contul de serviciu ExternalDNS cu o comandă care va arăta ceva de genul eksctl create iamserviceaccount --cluster=your-cluster-name --name=external-dns --namespace=default --attach-policy-arn=arn:aws:iam::123456789:policy/AllowExternalDNSUpdates.
  • Acum ar trebui să avem un nou rol din cele de mai sus, pe care îl putem vedea în Consola IAM care va avea un nume de ceva de genul eksctl-foo-addon-iamserviceaccount-Role1-abcdefg. Faceți clic pe rolul din listă și în partea de sus a ecranului următor notați „ROL ARN” ca ceva de genul arn:aws:iam::123456789:role/eksctl-foo-addon-iamserviceaccount-Role1-abcdefg.
  • Urma acești pași pentru a crea o „zonă găzduită” în Traseul 53.
  • Puteți confirma lucrurile în Consola Route 53.
  • Dacă furnizorul dvs. de domeniu vă permite să gestionați setările DNS, adăugați cele 4 înregistrări ale serverului de nume din ieșirea comenzii pe care ați executat-o ​​pentru a crea o „zonă găzduită”.
  • Implementați ExternalDNS urmând instructiunile. Apoi, puteți coada buștenii cu kubectl logs -f name-of-external-dns-pod. Ar trebui să vedeți o linie de genul acesta la sfârșit: time="2020-05-05T02:57:31Z" level=info msg="All records are already up to date"

Ușor, nu ?! Bine, poate nu … dar cel puțin nu a trebuit să-ți dai seama de toate singur? Ar putea exista unele lacune mai sus, dar sperăm că vă ajută să vă ghidați în procesul dvs.

Concluzie

Deși această postare poate avea unele zone gri, dacă vă ajută să stabiliți rezoluția DNS dinamică ca parte a unei aplicații extrem de disponibile, aveți ceva cu adevărat special?

Vă rugăm să adăugați comentarii dacă vă pot ajuta să clarific ceva sau să corectez terminologia mea!