![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/bed059552ed86580939aa18fbdf1553e.jpg)
Kubernetes'i tootmises kasutamise aastate jooksul on meil kogunenud palju huvitavaid lugusid, kuidas erinevate sĂŒsteemi komponentide vead on pĂ”hjustanud ebameeldivaid ja/vĂ”i arusaamatuid tagajĂ€rgi, mis mĂ”jutavad konteinerite ja pod'ide tööd. Selles artiklis oleme koostanud valiku mĂ”nedest kĂ”ige sagedamatest vĂ”i huvitavamatest neist. Isegi kui te ei pruugi kunagi sattuda sellistesse olukordadesse, on alati huvitav lugeda sellistest lĂŒhikesest detektiivides â eriti âesimesest kĂ€estâ, eks?..
Lugu 1. Supercronic ja kĂŒlmunud Docker
Ăhes meie klastris saime perioodiliselt âkĂŒlmunudâ Docker, mis hĂ€iris klastrite normaalset toimimist. Samas olid Docker'i logides jĂ€rgmised kirjed
level=error msg="containerd: start init process" error="exit status 2: "runtime/cgo: pthread_create failed: No space left on device
SIGABRT: abort
PC=0x7f31b811a428 m=0
goroutine 0 [idle]:
goroutine 1 [running]:
runtime.systemstack_switch() /usr/local/go/src/runtime/asm_amd64.s:252 fp=0xc420026768 sp=0xc420026760
runtime.main() /usr/local/go/src/runtime/proc.go:127 +0x6c fp=0xc4200267c0 sp=0xc420026768
runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc4200267c8 sp=0xc4200267c0
goroutine 17 [syscall, locked to thread]:
runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:2086 +0x1
⊠Selles veas huvitab meid kĂ”ige rohkem sĂ”num: pthread_create failed: No space left on device. Kiire ĂŒlevaade nĂ€itas, et Docker ei saa protsessi forkida, mistĂ”ttu see aeg-ajalt âkĂŒlmusâ.
JĂ€lgimisel, mis toimus, vastas selline pilt:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/bd778052c87b338493bae54b26830ef3.jpg)
Sarnast olukorda tÀheldati ka teistes sÔlmedes:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/ef512532a95ca982e4342071115dbe9f.jpg)
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/43c32ebca78755dde348ed5e7ac75c79.jpg)
Nendel samadel sÔlmedel nÀeme:
root@kube-node-1 ~ # ps auxfww | grep curl -c
19782
root@kube-node-1 ~ # ps auxfww | grep curl | head
root 16688 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 17398 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 16852 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 9473 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 4664 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 30571 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 24113 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 16475 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 7176 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]
root 1090 0.0 0.0 0 0 ? Z Feb06 0:00 | _ [curl]Selgus, selline kĂ€itumine on pod'i töö tagajĂ€rg (Go utiliit, mida kasutame cron-ĂŒlesannete kĂ€ivitamiseks pod'ides):
_ docker-containerd-shim 833b60bb9ff4c669bb413b898a5fd142a57a21695e5dc42684235df907825567 /var/run/docker/libcontainerd/833b60bb9ff4c669bb413b898a5fd142a57a21695e5dc42684235df907825567 docker-runc
| _ /usr/local/bin/supercronic -json /crontabs/cron
| _ /usr/bin/newrelic-daemon --agent --pidfile /var/run/newrelic-daemon.pid --logfile /dev/stderr --port /run/newrelic.sock --tls --define utilization.detect_aws=true --define utilization.detect_azure=true --define utilization.detect_gcp=true --define utilization.detect_pcf=true --define utilization.detect_docker=true
| | _ /usr/bin/newrelic-daemon --agent --pidfile /var/run/newrelic-daemon.pid --logfile /dev/stderr --port /run/newrelic.sock --tls --define utilization.detect_aws=true --define utilization.detect_azure=true --define utilization.detect_gcp=true --define utilization.detect_pcf=true --define utilization.detect_docker=true -no-pidfile
| _ [newrelic-daemon]
| _ [curl]
| _ [curl]
| _ [curl]
âŠProbleem on jĂ€rgmine: kui ĂŒlesanne kĂ€ivitub supercronicis, siis protsess, mille see edasi annab, ei suuda Ă”igesti lĂ”petada, muutudes .
MĂ€rkus: TĂ€psemalt öeldes, protsessid genereeritakse cron-ĂŒlesannetest, kuid supercronic ei ole init-sĂŒsteem ja ei suuda "seda lapsendavaid" protsesse, mille tema lastega toimub. Signaalide SIGHUP vĂ”i SIGTERM korral ei edastata neid edasi genereeritud protsessidele, mille tĂ”ttu tĂŒtarprotsessid ei lĂ”petata, jÀÀdes zombistaatusele. TĂ€iendavateks lugemiseks vĂ”ib nĂ€iteks lugeda .
Sorriteen on mÔningaid probleemide lahendamise viise:
- Ajutise lahendusena - suurendage sĂŒsteemis samal ajal PIDde arvu:
/proc/sys/kernel/pid_max (since Linux 2.5.34) This file specifies the value at which PIDs wrap around (i.e., the value in this file is one greater than the maximum PID). PIDs greater than this value are not alloâ cated; thus, the value in this file also acts as a system-wide limit on the total number of processes and threads. The default value for this file, 32768, results in the same range of PIDs as on earlier kernels - VĂ”i kĂ€ivitada ĂŒlesandeid supercronicis mitte otse, vaid sama abil, , mis suudab Ă”igesti lĂ”petada protsesse ja ei genereeri zombisid.
Lugu 2. "Zombid" cgroupi eemaldamisel
Kubelet hakkas tarbima suures koguses CPU-d:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/6140058330faaa3785b089dcba857056.jpg)
See ei meeldi kellelegi, seega relvasime end ja hakkasime probleemiga tegelema. Uurimise tulemused olid jÀrgmised:
- Kubelet kulutab rohkem kui kolmandiku CPU ajast mÀluandmete kogumisele kÔikidest cgroupidest:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%20241%22%3E%3C%2Fsvg%3E)
- Tuletisede arendajate postil vĂ”ib leida . LĂŒhidalt, sisu seisneb selles, et erinevad tmpfs-failid ja muud sarnased asjad ei eemaldu tĂ€ielikult sĂŒsteemist cgroupi eemaldamisel - jÀÀvad nn zombiks. Aega vĂ”i hiljem nad siiski kustutatakse page cache'ist, kuid serveris on palju mĂ€lu ja tuum ei nĂ€e mĂ”tet nende kustutamiseks aega raisata. SeetĂ”ttu nad jĂ€tkuvalt kuhjuvad. Miks see ĂŒldse juhtub? See on server cron-töödega, mis pidevalt loob uusi tĂ¶Ă¶ĂŒlesandeid ja nendega uusi pod'e. Seega luuakse nende konteinerite jaoks uued cgroup'id, mis varsti kustutatakse.
- Miks cAdvisor kubeleti juures kulutab nii palju aega? Seda on lihtne nÀha kÔige lihtsama teostuse abil
time cat /sys/fs/cgroup/memory/memory.stat. Kui tervel masinal see operatsioon kestab 0,01 sekundit, siis probleemse cron02 peal 1,2 sekundit. Asi on selles, et cAdvisor, kes loeb sysfs'ist andmeid vĂ€ga aeglaselt, proovib arvestada kasutatud mĂ€lu ja zombide cgroup'e. - Kuna me pĂŒĂŒdsime zombisid sunniviisiliselt kustutada, siis proovisime puhastada cache'e, nagu soovitati LKML'is:
sync; echo 3 > /proc/sys/vm/drop_caches, â aga tuum osutus keerulisemaks ning masin hangus.
Mida siis teha? Probleem lahendatakse (, ja kirjelduse leiate ) Linuxi tuuma versiooni 4.16 uuendamisega.
Lugu 3. Systemd ja selle mount
Taaskord tarbib kubelet liiga palju ressursse mÔnedes sÔlmedes, aga seekord juba mÀlu:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/044c4e23a772c61a6206b9b20aa67c1d.jpg)
Selgus, et probleem on systemd's, mis on kasutusel Ubuntu 16.04-s, ja see tekib mount'ide haldamisel, mis luuakse ConfigMap'ide vĂ”i salajaste jaoks. PĂ€rast pod'i lĂ”petamist , said edasiarendust â uue vĂ€lja jÀÀb systemd teenus ja selle teenusmount sĂŒsteemi. Aja jooksul neid koguneb tohutult. Selle teema kohta on isegi probleeme: kops #5916
- ;
- .
(issue systemd's â Probleem ei esine enam Ubuntu 18.04-s, aga kui soovite endiselt kasutada Ubuntu 16.04, siis vĂ”ib meie lahendus selle teema jaoks teile Ă€ra kuluda. ).
Nii et me tegime jÀrgmise DaemonSet'i:
Nii, me oleme loonud jÀrgmise DaemonSet'i:
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
labels:
app: systemd-slices-cleaner
name: systemd-slices-cleaner
namespace: kube-system
spec:
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: systemd-slices-cleaner
template:
metadata:
labels:
app: systemd-slices-cleaner
spec:
containers:
- command:
- /usr/local/bin/supercronic
- -json
- /app/crontab
Image: private-registry.org/systemd-slices-cleaner/systemd-slices-cleaner:v0.1.0
imagePullPolicy: Always
name: systemd-slices-cleaner
resources: {}
securityContext:
privileged: true
volumeMounts:
- name: systemd
mountPath: /run/systemd/private
- name: docker
mountPath: /run/docker.sock
- name: systemd-etc
mountPath: /etc/systemd
- name: systemd-run
mountPath: /run/systemd/system/
- name: lsb-release
mountPath: /etc/lsb-release-host
imagePullSecrets:
- name: antiopa-registry
priorityClassName: cluster-low
tolerations:
- operator: Exists
volumes:
- name: systemd
hostPath:
path: /run/systemd/private
- name: docker
hostPath:
path: /run/docker.sock
- name: systemd-etc
hostPath:
path: /etc/systemd
- name: systemd-run
hostPath:
path: /run/systemd/system/
- name: lsb-release
hostPath:
path: /etc/lsb-release⊠ja kasutatakse sellist skripti:
#!/bin/bash
# we will work only on xenial
hostrelease="/etc/lsb-release-host"
test -f ${hostrelease} && grep xenial ${hostrelease} > /dev/null || exit 0
# sleeping max 30 minutes to dispense load on kube-nodes
sleep $((RANDOM % 1800))
stoppedCount=0
# counting actual subpath units in systemd
countBefore=$(systemctl list-units | grep subpath | grep "run-" | wc -l)
# let's go check each unit
for unit in $(systemctl list-units | grep subpath | grep "run-" | awk '{print $1}'); do
# finding description file for unit (to find out docker container, who born this unit)
DropFile=$(systemctl status ${unit} | grep Drop | awk -F': ' '{print $2}')
# reading uuid for docker container from description file
DockerContainerId=$(cat ${DropFile}/50-Description.conf | awk '{print $5}' | cut -d/ -f6)
# checking container status (running or not)
checkFlag=$(docker ps | grep -c ${DockerContainerId})
# if container not running, we will stop unit
if [[ ${checkFlag} -eq 0 ]]; then
echo "Stopping unit ${unit}"
# stoping unit in action
systemctl stop $unit
# just counter for logs
((stoppedCount++))
# logging current progress
echo "Stopped ${stoppedCount} systemd units out of ${countBefore}"
fi
done⊠ja see kÀivitatakse iga 5 minuti jÀrel juba mainitud supercronic'i abil. Selle Dockerfile nÀeb vÀlja jÀrgmine:
FROM ubuntu:16.04
COPY rootfs /
WORKDIR /app
RUN apt-get update &&
apt-get upgrade -y &&
apt-get install -y gnupg curl apt-transport-https software-properties-common wget
RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable" &&
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - &&
apt-get update &&
apt-get install -y docker-ce=17.03.0*
RUN wget https://github.com/aptible/supercronic/releases/download/v0.1.6/supercronic-linux-amd64 -O
/usr/local/bin/supercronic && chmod +x /usr/local/bin/supercronic
ENTRYPOINT ["/bin/bash", "-c", "/usr/local/bin/supercronic -json /app/crontab"]Lugu 4. Ăheaegsus pod'ide planeerimisel
On mÀrgatud, et: kui meil on nodis paigutatud pod ja selle pildi alla laadimine vÔtab kaua aega, siis teine pod, mis "satub" samale node'ile, lihtsalt ei alusta uue pod'i kuvatamise tÔmbamisega.Selle asemel ootab ta, kuni eelmine pod'i pilt on tÔmmatud. Tulemuseks on pod, mis on juba planeeritud ja mille pilt oleks vÔinud alla laadida vaid minutiga, jÀÀb pikaks ajaks staatusele containerCreating.
SĂŒndmustes on umbes jĂ€rgmine:
Normal Pulling 8m kubelet, ip-10-241-44-128.ap-northeast-1.compute.internal pulling image "registry.example.com/infra/openvpn/openvpn:master"Selgub, et ainult ĂŒks pilt aeglasest registrist vĂ”ib blokeerida juurutamise node'ile.
Kahjuks ei ole olukorrast vÀljapÀÀse palju:
- PĂŒĂŒdke kasutada oma Docker registrit otse klastris vĂ”i otse klassi (nĂ€iteks GitLab Registry, Nexus jne);
- Kasutage selliseid tööriistu nagu .
Lugu 5. SÔlmede hangumine mÀlu puuduse tÔttu
Erinevate rakenduste kasutamise ajal oleme samuti kogenud olukordi, kus sÔlm lakkab tÀielikult olemast kÀttesaadav: ei vasta SSH, kÔik jÀlgimisdemonid pingutavad ja logides ei ole midagi (vÔi peaaegu midagi) ebatavalist.
NĂ€itan piltidel ĂŒhe sĂ”lme nĂ€iteks, kus töötas MongoDB.
Nii nÀeb atop vÀlja kuni katastroofid:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/5de916d270a862cbcbb5ed23c31f698e.jpg)
Ja nii â pĂ€rast katastroofid:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/0f32bf1113204cf19f4639a297e40348.jpg)
JÀlgimises on samuti nÀhtav terav tÔus, mille kÀigus sÔlm lakab olemast kÀttesaadav:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/31e770cac5be32bb7f95cfbbc6b9f1ae.jpg)
Seega, ekraanipiltidest on nÀha, et:
- MĂ€lu masinas on peaaegu otsas;
- TÀheldatakse jÀrsku mÀlutarbimise kasvu, mille jÀrel juurdepÀÀs kogu masinale katkeb;
- Mongo'le tuleb suur ĂŒlesanne, mis paneb andmebaasi protsessi kasutama rohkem mĂ€lu ja aktiivselt lugema kettalt.
Selgub, et kui Linuxis lÔpeb vaba mÀlu (tekib mÀlurÔhk) ja s-wappi pole, siis kuni OOM killer'i saabumise hetk vÔib tÀhendada tasakaalu lehitsemise vahel lehtede paigutamise page cache'i ja nende kirjutamise tagasi kettale. Sellega tegeleb kswapd, kes julgeb vabastada vÔimalikult palju mÀlu lehti edasiseks jaotamiseks.
Kahjuks, kui sisend/vĂ€ljund koormus on suur koos vĂ€ikese vaba mĂ€luhulgaga, kasvab kswapd kogu sĂŒsteemi pudelikaelaks, kuna sellele sĂ”ltuvad kĂ”ik mĂ€lu lehtede jaotused (page faults) sĂŒsteemis. See vĂ”ib kesta vĂ€ga kaua, kui protsessid ei soovi enam mĂ€lu kasutada ning jÀÀvad OOM killer'i ÀÀrele.
KĂŒsimus on loomulik: miks OOM killer tuleb nii hilja? Praeguses iteratsioonis on OOM killer ÀÀrmiselt rumal: ta lĂ”petab protsessi ainult siis, kui ebaĂ”nnestub mĂ€lulehe jaotamise katse, st kui page fault lĂ€heb lĂ€bi veaga. Seda ei juhtu piisavalt kaua, kuna kswapd julgeb vabastada mĂ€lulehti, kustutades page cache'i (kogu ketta I/O sĂŒsteemis, pĂ”himĂ”tteliselt) tagasi kettale. TĂ€iendavalt, koos sammudega, mis on vajalikud sarnaste probleemide lahendamiseks tuumas, saate lugeda .
See kÀitumine Linuxi 4.6+ tuumaga.
Ajalugu 6. Podâid jÀÀvad seisundisse Pending
MĂ”nedes klastrites, kus töötab tĂ”eliselt palju podâe, oleme hakanud mĂ€rkama, et suur osa neist jÀÀb vĂ€ga kauaks "ripakile" seisu Pending, kuigi samal ajal on Docker-konteinerid juba sĂ”lmedes kĂ€ivitatud ja nendega saab kĂ€sitsi töötada.
Samas on describe pole midagi halba:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Edukalt mÀÀratud sphinx-0 ss-dev-kub07-le
Normal SuccessfulAttachVolume 1m attachdetach-controller AttachVolume.Attach Ônnestus mahuti "pvc-6aaad34f-ad10-11e8-a44c-52540035a73b" jaoks
Normal SuccessfulMountVolume 1m kubelet, ss-dev-kub07 MountVolume.SetUp Ônnestus mahuti "sphinx-config" jaoks
Normal SuccessfulMountVolume 1m kubelet, ss-dev-kub07 MountVolume.SetUp Ônnestus mahuti "default-token-fzcsf" jaoks
Normal SuccessfulMountVolume 49s (x2 over 51s) kubelet, ss-dev-kub07 MountVolume.SetUp Ônnestus mahuti "pvc-6aaad34f-ad10-11e8-a44c-52540035a73b" jaoks
Normal Pulled 43s kubelet, ss-dev-kub07 Konteineri pilt "registry.example.com/infra/sphinx-exporter/sphinx-indexer:v1" on juba masinas olemas
Normal Created 43s kubelet, ss-dev-kub07 Kontainer loodud
Normal Started 43s kubelet, ss-dev-kub07 Kontainer kÀivitatud
Normal Pulled 43s kubelet, ss-dev-kub07 Konteineri pilt "registry.example.com/infra/sphinx/sphinx:v1" on juba masinas olemas
Normal Created 42s kubelet, ss-dev-kub07 Kontainer loodud
Normal Started 42s kubelet, ss-dev-kub07 Kontainer kĂ€ivitatudUurides asja, tegime jĂ€relduse, et kubelet ei suuda lihtsalt API-serverile kĂ”iki podâide olekuandmeid piisavalt kiiresti edastada, liveness/readiness-testide kohta.
Ja uurides abi, leidsime jÀrgmised parameetrid:
--kube-api-qps - QPS, mida kasutada kubernetes apiserveriga suhtlemisel (vaikimisi 5)
--kube-api-burst - Burst, mida kasutada kubernetes apiserveriga suhtlemisel (vaikimisi 10)
--event-qps - Kui > 0, piirata ĂŒrituste loomise sagedust sekundis sellele vÀÀrtusele. Kui 0, piiramatu. (vaikimisi 5)
--event-burst - Maksimaalne suurus purunevate ĂŒrituste jaoks, lubab ajutiselt ĂŒrituste rekordite puruneda sellele numbrile, ĂŒletamata siiski event-qps-i. Kasutatakse ainult juhul, kui --event-qps > 0 (vaikimisi 10)
--registry-qps - Kui > 0, piirata registri pull-i QPS-iga sellele vÀÀrtusele.
--registry-burst - Maksimaalne suurus purunevate tĂ”mbamiste jaoks, lubab ajutiselt tĂ”mbamisi puruneda sellele numbrile, ĂŒletamata siiski registry-qps-i. Kasutatakse ainult juhul, kui --registry-qps > 0 (vaikimisi 10)Nagu nĂ€ha, vaikimisi vÀÀrtused on ĂŒsna vĂ€ikesed, ja 90% juhtudest katab see kĂ”ik vajadused... Kuid meie puhul osutus sellest vĂ€heks. SeetĂ”ttu seadsime sellised vÀÀrtused:
--event-qps=30 --event-burst=40 --kube-api-burst=40 --kube-api-qps=30 --registry-qps=30 --registry-burst=40⊠ja kĂ€ivitasime kubeletâid uuesti, pĂ€rast mida nĂ€gime API-serveri mahtuvuse graafikutel jĂ€rgmist pilti:
![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/b2ae099729e55a686f6bec3012b96195.jpg)
⊠ja jah, kÔik hakkas lendama!
P.S.
Suur tÀnu meie ettevÔtte paljudele inseneridele, eriti minu kolleegile R&D meeskonnast Andreile Klimentjevile, abi eest vigade kogumisel ja artikli ettevalmistamisel.).
P.P.S.
Lugege ka meie blogist:
- «».
- Kubernetesi nÀpunÀited ja nipid:
- «»;
- «»;
- «»;
- «».
Allikas: habr.com

![6 huvitavat sĂŒsteemiviga Kubernetes'i kasutamise ajal [ja nende lahendamine]](/wp-content/uploads/2019/03/0d15d1de17cd6838fc1cad19615af218.jpg)