Vida Gvidilo por Solvi Kubernetes

Notu. transl.: Ĉi tiu artikolo estas parto de la projektmaterialoj publikigitaj en la publika domeno lernik8s, trejnado de kompanioj kaj individuaj administrantoj por labori kun Kubernetes. En ĝi, Daniele Polencic, projektestro, dividas vidajn instrukciojn pri kiaj paŝoj fari en kazo de ĝeneralaj problemoj kun aplikaĵoj kurantaj sur la K8s-areo.

Vida Gvidilo por Solvi Kubernetes

TL;DR: jen diagramo, kiu helpos vin sencimigi deplojon en Kubernetes:

Vida Gvidilo por Solvi Kubernetes

Fluodiagramo por trovi kaj ripari erarojn en areto. La originalo (en la angla) haveblas ĉe PDF и kiel bildo.

Dum deplojado de aplikaĵo al Kubernetes, estas kutime tri komponantoj, kiujn vi devas difini:

  • deplojo - ĉi tio estas speco de recepto por krei kopiojn de la aplikaĵo, nomataj guŝoj;
  • servo — interna ŝarĝbalancilo, kiu distribuas trafikon inter podoj;
  • Ingreso — priskribo de kiel trafiko venos de la ekstera mondo al la Servo.

Jen rapida grafika resumo:

1) En Kubernetes, aplikoj ricevas trafikon de la ekstera mondo per du tavoloj de ŝarĝbalanciloj: interna kaj ekstera.

Vida Gvidilo por Solvi Kubernetes

2) La interna ekvilibro nomiĝas Servo, la ekstera nomiĝas Eniro.

Vida Gvidilo por Solvi Kubernetes

3) Deplojo kreas podojn kaj kontrolas ilin (ili ne estas kreitaj permane).

Vida Gvidilo por Solvi Kubernetes

Ni diru, ke vi volas disfaldi simplan aplikaĵon Saluton mondo. La YAML-agordo por ĝi aspektos jene:

apiVersion: apps/v1
kind: Deployment # <<<
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
      labels:
        any-name: my-app
    spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service # <<<
metadata:
  name: my-service
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    name: app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress # <<<
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
        serviceName: app
        servicePort: 80
      path: /

La difino estas sufiĉe longa kaj estas facile konfuziĝi pri kiel la komponantoj rilatas unu al la alia.

Ekzemple:

  • Kiam vi uzu la havenon 80 kaj kiam vi uzu 8080?
  • Ĉu mi kreu novan havenon por ĉiu servo por ke ili ne konfliktu?
  • Ĉu etikednomoj gravas? Ĉu ili estu ĉie samaj?

Antaŭ ol koncentriĝi pri senararigado, ni memoru kiel la tri komponantoj rilatas unu al la alia. Ni komencu per Deplojo kaj Servo.

Rilato inter Deplojo kaj Servo

Vi estos surprizita, sed Deplojo kaj Servo neniel estas ligitaj. Anstataŭe, Servo montras rekte al Pods, preterirante Deplojon.

Tiel, ni interesiĝas pri kiel Pods kaj Servoj rilatas unu al la alia. Tri aferoj por memori:

  1. Elektilo (selector) por Servo devas kongrui kun almenaŭ unu Pod-etikedo.
  2. targetPort devas kongrui containerPort ujo ene de la Pod.
  3. port Servo povas esti io ajn. Malsamaj servoj povas uzi la saman havenon ĉar ili havas malsamajn IP-adresojn.

La sekva diagramo reprezentas ĉion ĉi supre en grafika formo:

1) Imagu, ke la servo direktas trafikon al certa pod:

Vida Gvidilo por Solvi Kubernetes

2) Kreante pod, vi devas specifi containerPort por ĉiu ujo en guŝoj:

Vida Gvidilo por Solvi Kubernetes

3) Kreante servon, vi devas specifi port и targetPort. Sed kiu estas uzata por konekti al la ujo?

Vida Gvidilo por Solvi Kubernetes

4) Vojo targetPort. Ĝi devas kongrui containerPort.

Vida Gvidilo por Solvi Kubernetes

5) Ni diru en la ujo estas malfermita pordo 3000. Tiam la valoro targetPort devus esti la sama.

Vida Gvidilo por Solvi Kubernetes

En la YAML-dosiero, etikedoj kaj ports / targetPort devas kongrui:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
     labels:  # <<<
        any-name: my-app  # <<<
   spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
       - containerPort: 8080  # <<<
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
  - port: 80
   targetPort: 8080  # <<<
 selector:  # <<<
    any-name: my-app  # <<<

Kio pri la etikedo track: canary ĉe la supro de la sekcio Deployment? Ĉu ĝi devus kongrui?

Ĉi tiu etikedo estas deploj-specifa kaj ne estas uzata de la servo por direkti trafikon. Alivorte, ĝi povas esti forigita aŭ asignita malsama valoro.

Kio pri la elektilo matchLabels?

Ĝi ĉiam devas kongrui kun la etikedoj de la Pod, ĉar ĝi estas uzata de Deployment por spuri podojn.

Ni supozu, ke vi faris la ĝustajn redaktojn. Kiel kontroli ilin?

Vi povas kontroli la pod-etikedon per la sekva komando:

kubectl get pods --show-labels

Aŭ, se balgoj apartenas al pluraj aplikoj:

kubectl get pods --selector any-name=my-app --show-labels

Kie any-name=my-app estas etikedo any-name: my-app.

Ĉu restas malfacilaĵoj?

Vi povas konektiĝi al la pod! Por fari tion, vi devas uzi la komandon port-forward en kubectl. Ĝi permesas vin konekti al la servo kaj kontroli la konekton.

kubectl port-forward service/<service name> 3000:80

Jen:

  • service/<service name> — servonomo; en nia kazo estas my-service;
  • 3000 estas la haveno, kiu devas esti malfermita en la komputilo;
  • 80 - haveno specifita en la kampo port servo.

Se la konekto estis establita, tiam la agordoj estas ĝustaj.

Se la konekto malsukcesas, estas problemo kun la etikedoj aŭ la havenoj ne kongruas.

Rilato inter Servo kaj Eniro

La sekva paŝo en havigi aliron al la aplikaĵo implikas agordi Ingress. Ingress devas scii kiel trovi servon, poste trovi podojn kaj direkti trafikon al ili. Ingress trovas la postulatan servon laŭ nomo kaj malferma haveno.

En la priskribo de Eniro kaj Servo du parametroj devas kongrui:

  1. servicePort en Eniro devas kongrui kun la parametro port en Servo;
  2. serviceName en Ingress devas kongrui kun la kampo name en Servo.

La sekva diagramo resumas la havenkonektoj:

1) Kiel vi jam scias, Servo aŭskultas certan port:

Vida Gvidilo por Solvi Kubernetes

2) Eniro havas parametron nomitan servicePort:

Vida Gvidilo por Solvi Kubernetes

3) Ĉi tiu parametro (servicePort) ĉiam devas kongrui port en la Difino de Servo:

Vida Gvidilo por Solvi Kubernetes

4) Se haveno 80 estas specifita en Servo, tiam necesas tion servicePort estis ankaŭ egala al 80:

Vida Gvidilo por Solvi Kubernetes

En la praktiko, vi devas atenti la jenajn liniojn:

apiVersion: v1
kind: Service
metadata:
 name: my-service  # <<<
spec:
  ports:
 - port: 80  # <<<
   targetPort: 8080
  selector:
    any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
       serviceName: my-service  # <<<
       servicePort: 80  # <<<
     path: /

Kiel kontroli ĉu Ingress funkcias?

Vi povas uzi la metodon kun kubectl port-forward, sed anstataŭ la servo vi devas konekti al la Ingress-regilo.

Unue vi devas eltrovi la nomon de la pod kun la Ingress-regilo:

kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running

Trovu la Ingress-podon (ĝi povas esti en malsama nomspaco) kaj rulu la komandon describepor ekscii la havennumerojn:

kubectl describe pod nginx-ingress-controller-6fc5bcc 
--namespace kube-system 
 | grep Ports
Ports:         80/TCP, 443/TCP, 18080/TCP

Fine, konektu al la pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Nun ĉiufoje kiam vi sendas peton al la haveno 3000 en via komputilo, ĝi estos plusendita al la haveno 80 de la pod kun la Ingress-regilo. Irante al http://localhost:3000, vi devus vidi la paĝon generitan de la aplikaĵo.

Resumo de havenoj

Ni rememoru denove, kiuj havenoj kaj etikedoj devas kongrui:

  1. La elektilo en la Servodifino devas kongrui kun la etikedo de la pod;
  2. targetPort en la difino Servo devas kongrui containerPort ujo ene de balgo;
  3. port en la difino Servo povas esti io ajn. Malsamaj servoj povas uzi la saman havenon ĉar ili havas malsamajn IP-adresojn;
  4. servicePort Eniro devas kongrui port en la difino de Servo;
  5. La servonomo devas kongrui kun la kampo serviceName en Eniro.

Bedaŭrinde, ne sufiĉas scii kiel ĝuste strukturi YAML-agordon.

Kio okazas kiam aferoj misfunkcias?

La pod eble ne komenciĝas aŭ ĝi povas kraŝi.

3 Paŝoj por Diagnozi Aplikajn Problemojn en Kubernetes

Antaŭ ol vi komencas sencimigi vian deplojon, vi devas bone kompreni kiel funkcias Kubernetes.

Ĉar ĉiu aplikaĵo elŝutita en K8s havas tri komponentojn, ili devus esti elpurigitaj en certa ordo, komencante de la malsupro.

  1. Unue vi devas certigi, ke la guŝoj funkcias, poste...
  2. Kontrolu ĉu la servo provizas trafikon al la podoj, kaj tiam...
  3. Kontrolu ĉu Ingress estas agordita ĝuste.

Vida reprezentado:

1) Vi devus komenci serĉi problemojn de la fundo. Unue kontrolu, ke balgoj havas statusojn Ready и Running:

Vida Gvidilo por Solvi Kubernetes

2) Se la balgoj estas pretaj (Ready), vi devus ekscii ĉu la servo distribuas trafikon inter podoj:

Vida Gvidilo por Solvi Kubernetes

3) Fine, vi devas analizi la rilaton inter la servo kaj la Eniro:

Vida Gvidilo por Solvi Kubernetes

1. Diagnozo de podoj

Plejofte la problemo rilatas al la pod. Certigu, ke balgoj estas listigitaj kiel Ready и Running. Vi povas kontroli ĉi tion per la komando:

kubectl get pods
NAME                    READY STATUS            RESTARTS  AGE
app1                    0/1   ImagePullBackOff  0         47h
app2                    0/1   Error             0         47h
app3-76f9fcd46b-xbv4k   1/1   Running           1         47h

En la komanda eligo supre, la lasta pod estas listigita kiel Running и Ready, tamen, ĉi tio ne estas la kazo por la aliaj du.

Kiel kompreni kio misfunkciis?

Estas kvar utilaj komandoj por diagnozi podojn:

  1. kubectl logs <имя pod'а> permesas al vi ĉerpi ŝtipojn el ujoj en balgo;
  2. kubectl describe pod <имя pod'а> permesas al vi vidi liston de eventoj asociitaj kun la pod;
  3. kubectl get pod <имя pod'а> permesas vin akiri la YAML-agordon de pod stokita en Kubernetes;
  4. kubectl exec -ti <имя pod'а> bash permesas al vi lanĉi interagan komandan ŝelon en unu el la podujoj

Kiun vi elektu?

La fakto estas, ke ne ekzistas universala komando. Kombinaĵo de ĉi tiuj devus esti uzata.

Tipaj podproblemoj

Estas du ĉefaj specoj de pod-eraroj: lanĉaj eraroj kaj rultempaj eraroj.

Komencaj eraroj:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

Rultempaj eraroj:

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

Iuj eraroj estas pli oftaj ol aliaj. Jen kelkaj el la plej oftaj eraroj kaj kiel ripari ilin.

ImagePullBackOff

Ĉi tiu eraro okazas kiam Kubernetes ne povas akiri bildon por unu el la podujoj. Jen la tri plej oftaj kialoj por ĉi tio:

  1. La nomo de la bildo estas malĝusta - ekzemple, vi faris eraron en ĝi, aŭ la bildo ne ekzistas;
  2. Neekzistanta etikedo estis specifita por la bildo;
  3. La bildo estas konservita en privata registro kaj Kubernetes ne havas permeson aliri ĝin.

La unuaj du kialoj estas facile elimineblaj - nur korektu la bildonomon kaj etikedon. En la kazo de ĉi-lasta, vi devas enigi akreditaĵojn por la fermita registro en Sekreta kaj aldoni ligilojn al ĝi en podoj. En la dokumentado de Kubernetes estas ekzemplo kiel tio povas esti farita.

Kraŝa Buklo Malŝaltita

Kubenetes ĵetas eraron CrashLoopBackOff, se la ujo ne povas komenci. Ĉi tio kutime okazas kiam:

  1. Estas cimo en la aplikaĵo, kiu malhelpas ĝin lanĉi;
  2. Ujo agordita malĝuste;
  3. La Liveness-testo malsukcesis tro multajn fojojn.

Vi devas provi atingi la ŝtipojn de la ujo por ekscii la kialon de ĝia malsukceso. Se estas malfacile aliri la protokolojn ĉar la ujo rekomencas tro rapide, vi povas uzi la jenan komandon:

kubectl logs <pod-name> --previous

Ĝi montras erarmesaĝojn de la antaŭa enkarniĝo de la ujo.

RunContainerError

Ĉi tiu eraro okazas kiam la ujo ne komenciĝas. Ĝi respondas al la momento antaŭ ol la aplikaĵo estas lanĉita. Ĝi estas kutime kaŭzita de malĝustaj agordoj, ekzemple:

  • provante munti neekzistantan volumenon kiel ConfigMap aŭ Sekretoj;
  • provo munti nurlegeblan volumon kiel lego-skribi.

La teamo taŭgas por analizi tiajn erarojn kubectl describe pod <pod-name>.

Pods estas en Pritraktata stato

Fojo kreita, la balgo restas en la ŝtato Pending.

Kial ĉi tio okazas?

Jen la eblaj kialoj (mi supozas, ke la planilo funkcias bone):

  1. La areto ne havas sufiĉajn rimedojn, kiel pretigpovon kaj memoron, por funkcii la pod.
  2. La objekto estas instalita en la taŭga nomspaco ResourceQuota kaj kreado de pod kaŭzos la nomspacon preterpasi la kvoton.
  3. Pod estas ligita al Pritraktata PersistentVolumeClaim.

En ĉi tiu kazo, oni rekomendas uzi la komandon kubectl describe kaj kontrolu la sekcion Events:

kubectl describe pod <pod name>

En kazo de eraroj rilataj al ResourceQuotas, oni rekomendas vidi la grapolprotokolojn uzante la komandon

kubectl get events --sort-by=.metadata.creationTimestamp

Pods ne estas Pretaj

Se pod estas listigita kiel Running, sed ne estas en stato Ready, signifas kontroli ĝian pretecon (preteca sondo) malsukcesas.

Kiam tio okazas, la pod ne konektas al la servo kaj neniu trafiko fluas al ĝi. La fiasko de la preteca testo estas kaŭzita de problemoj en la aplikaĵo. En ĉi tiu kazo, por trovi la eraron, vi devas analizi la sekcion Events en la komanda eligo kubectl describe.

2. Servaj diagnozoj

Se balgoj estas listigitaj kiel Running и Ready, sed ankoraŭ ne estas respondo de la aplikaĵo, vi devus kontroli la servo-agordojn.

Servoj respondecas pri direktado de trafiko al podoj depende de siaj etikedoj. Tial, la unua afero, kiun vi devas fari, estas kontroli kiom da podoj funkcias kun la servo. Por fari tion, vi povas kontroli la finpunktojn en la servo:

kubectl describe service <service-name> | grep Endpoints

Finpunkto estas paro de valoroj de la formo <IP-адрес:порт>, kaj almenaŭ unu tia paro devas ĉeesti en la eligo (tio estas, almenaŭ unu pod funkcias kun la servo).

Se sekcio Endpoins malplena, du opcioj estas eblaj:

  1. ne ekzistas podoj kun la ĝusta etikedo (sugesto: kontrolu ĉu la nomspaco estas ĝuste elektita);
  2. Estas eraro en la servaj etikedoj en la elektilo.

Se vi vidas liston de finpunktoj sed ankoraŭ ne povas aliri la aplikaĵon, tiam la verŝajna kulpulo estas cimo en targetPort en la priskribo de la servo.

Kiel kontroli la funkciojn de la servo?

Sendepende de la speco de servo, vi povas uzi la komandon kubectl port-forward por konekti al ĝi:

kubectl port-forward service/<service-name> 3000:80

Jen:

  • <service-name> — servonomo;
  • 3000 estas la haveno, kiun vi malfermas en la komputilo;
  • 80 - haveno ĉe la servoflanko.

3. Diagnozo de eniro

Se vi legis ĉi tien, tiam:

  • balgoj estas listigitaj kiel Running и Ready;
  • la servo sukcese distribuas trafikon inter podoj.

Tamen, vi ankoraŭ ne povas "atingi" la aplikaĵon.

Ĉi tio signifas, ke la Ingress-regilo plej verŝajne ne estas agordita ĝuste. Ĉar la Ingress-regilo estas triaparta komponento en la areto, ekzistas malsamaj sencimigaj metodoj depende de ĝia tipo.

Sed antaŭ ol vi uzas specialajn ilojn por agordi Ingress, vi povas fari ion tre simplan. Enir-uzoj serviceName и servicePort por konekti al la servo. Vi devas kontroli ĉu ili estas ĝuste agorditaj. Vi povas fari tion uzante la komandon:

kubectl describe ingress <ingress-name>

Se kolumno Backend malplena, estas alta probablo de agorda eraro. Se la backends estas en loko, sed la aplikaĵo ankoraŭ ne estas alirebla, tiam la problemo eble rilatas al:

  • Eniri alireblajn agordojn de la publika Interreto;
  • agordoj de alirebleco de cluster de la publika Interreto.

Vi povas identigi problemojn kun la infrastrukturo konektante rekte al la Ingress-podo. Por fari tion, unue trovu la Ingress Controller pod (ĝi povas esti en malsama nomspaco):

kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running

Uzu la komandon describepor agordi la havenon:

kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system 
 | grep Ports

Fine, konektu al la pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Nun ĉiuj petoj al haveno 3000 en la komputilo estos redirektitaj al haveno 80 de la pod.

Ĉu ĝi funkcias nun?

  • Se jes, tiam la problemo estas kun la infrastrukturo. Necesas ekscii ĝuste kiel trafiko estas direktita al la areto.
  • Se ne, tiam la problemo estas kun la Ingress-regilo.

Se vi ne povas funkcii la Ingress-regilon, vi devos sencimigi ĝin.

Estas multaj varioj de Ingress-regiloj. La plej popularaj estas Nginx, HAProxy, Traefik, ktp. (por pliaj informoj pri ekzistantaj solvoj, vidu nia recenzo - ĉ. traduk.) Vi devus raporti al la gvidilo pri solvo de problemoj en la koncerna dokumentaro pri regilo. Ĉar la Eniro Nginx estas la plej populara Ingress-regilo, ni inkluzivis kelkajn konsiletojn en la artikolo por solvi problemojn rilatajn al ĝi.

Sencimigi la Ingress Nginx-regilon

La projekto Ingress-nginx havas oficialulon kromaĵo por kubectl. Teamo kubectl ingress-nginx povas esti uzata por:

  • analizo de protokoloj, backends, atestiloj, ktp.;
  • ligoj al Ingress;
  • studante la nunan agordon.

La sekvaj tri komandoj helpos vin pri tio:

  • kubectl ingress-nginx lint - ĉekoj nginx.conf;
  • kubectl ingress-nginx backend — esploras la malantaŭon (simila al kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs — kontrolas la protokolojn.

Notu, ke en iuj kazoj vi eble bezonos specifi la ĝustan nomspacon por la Ingress-regilo uzante la flagon --namespace <name>.

Resumo

Solvi Kubernetes povas esti malfacila se vi ne scias kie komenci. Vi ĉiam devas alproksimiĝi al la problemo de malsupre supren: komencu per podoj, kaj poste transiru al la servo kaj Eniro. La sencimigaj teknikoj priskribitaj en ĉi tiu artikolo povas esti aplikitaj al aliaj objektoj, kiel ekzemple:

  • idle Jobs kaj CronJobs;
  • StatefulSets kaj DaemonSets.

Mi esprimas mian dankemon Gergely Risko, Daniel Weibel и Charles Christyraj por valoraj komentoj kaj aldonoj.

PS de tradukisto

Legu ankaŭ en nia blogo:

fonto: www.habr.com

Aldoni komenton