ProHoster > Blog > Rêveberî > Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]
Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]
Bi salên bikaranîna Kubernetes di hilberînê de, me gelek çîrokên balkêş berhev kirine ka çawa xeletiyên di hêmanên pergalê yên cihêreng de bûne sedema encamên ne xweş û/an nefêmkirî ku bandorê li xebata konteyneran û potan dikin. Di vê gotarê de me hilbijarkek ji yên herî gelemperî an balkêş çêkiriye. Her çend hûn qet ne bextewar bin ku hûn bi rewşên weha re rû bi rû nebin jî, xwendina li ser çîrokên detektîf ên weha - nemaze "destê yekem" - her gav balkêş e, ne wusa?..
Çîrok 1. Supercronic û Docker daleqandî
Li ser yek ji koman, me bi awayekî periyodîk Dockerek cemidî wergirt, ku destwerdana xebata normal a komê dike. Di heman demê de, jêrîn di têketinên Docker de hate dîtin:
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
…
Ya ku herî zêde me di derbarê vê xeletiyê de eleqedar dike ev peyam e: pthread_create failed: No space left on device. Lêkolîna Zû belgekirin diyar kir ku Docker nekare pêvajoyek bişopîne, ji ber vê yekê ew dem bi dem cemidand.
Di çavdêriyê de, wêneya jêrîn bi tiştê ku diqewime re têkildar e:
Pirsgirêk ev e: dema ku peywirek di superkronîk de tê meşandin, pêvajo ji hêla wê ve hatî çêkirin nikare rast biqede, zivirî nav zombie.
bingotin: Ji bo ku rasttir be, pêvajo ji hêla peywirên cron ve têne çêkirin, lê supercronic ne pergalek destpêkê ye û nikare pêvajoyên ku zarokên wê çêdibin "qebûl bike". Dema ku sînyalên SIGHUP an SIGTERM têne bilind kirin, ew ji pêvajoyên zarokan re nayên derbas kirin, di encamê de pêvajoyên zarokan bi dawî nabin û di rewşa zombî de dimînin. Hûn dikarin li ser van hemîyan bêtir bixwînin, mînakî, li gotarek weha.
Ji bo çareserkirina pirsgirêkan du rê hene:
Wekî çareseriyek demkî - di yek xala demê de hejmara PID-an di pergalê de zêde bikin:
/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
An jî peywiran di supercronic de ne rasterast, lê heman bikar tînin dest pê bikin tini, ku karibe pêvajoyan rast biqedîne û zozanan neke.
Çîrok 2. "Zombî" dema ku cgroup jêbirin
Kubelet dest bi vexwarina gelek CPU kir:
Kes ji vê hez nake, lewma me xwe çekdar kir lhevderketî û dest bi çareserkirina pirsgirêkê kir. Encamên lêkolînê wiha bûn:
Kubelet ji sêyeka dema xwe ya CPU-yê bêtir ji hemî cgroupan daneyên bîranînê dikişîne:
Di navnîşa nameya pêşdebirên kernel de hûn dikarin bibînin gotûbêjkirina pirsgirêkê. Bi kurtî, xal bi vê yekê tê: pelên cûrbecûr tmpfs û tiştên din ên mîna wan bi tevahî ji pergalê nayê derxistin dema ku cgroup jêbirin, tê gotin memcg zombie. Zû yan dereng ew ê ji cacheya rûpelê werin jêbirin, lê li ser serverê pir bîranîn heye û kernel fêdeya windakirina demê li ser jêbirina wan nabîne. Ji ber vê yekê ew berdewam dikin. Çima ev yek jî dibe? Ev serverek bi karên kron e ku bi domdarî karên nû diafirîne, û bi wan re jî podên nû. Bi vî rengî, cgroupên nû ji bo konteynerên di wan de têne afirandin, ku di demek nêzîk de têne jêbirin.
Çima cAdvisor di kubelet de ew qas wext winda dike? Ev bi darvekirina herî hêsan tê dîtin time cat /sys/fs/cgroup/memory/memory.stat. Ger li ser makîneyek saxlem operasyon 0,01 çirkeyan digire, wê hingê li ser cron02 pirsgirêk 1,2 çirkeyan digire. Tişt ev e ku cAdvisor, ku daneyên ji sysfs pir hêdî dixwîne, hewl dide ku bîranîna ku di cgroupên zombî de tê bikar anîn hesab bike.
Ji bo ku bi zorê zozanan rakin, me hewl da ku wekî ku di LKML-ê de tê pêşniyar kirin paqij bikin: sync; echo 3 > /proc/sys/vm/drop_caches, - lê kernel tevlihevtir derket û erebe qelibî.
Çi bikim? Pirsgirêk tê çareser kirin (bikaranîn, û ji bo ravekirinê binêre peyama berdanê) nûvekirina kernel Linux bo guhertoya 4.16.
Dîrok 3. Sîstem û çiyayê wê
Dîsa, kubelet li ser hin girêkan gelek çavkaniyan dixwe, lê vê carê ew pir bîranîn dixwe:
Derket holê ku di pergala ku di Ubuntu 16.04-ê de tê bikar anîn de pirsgirêkek heye, û ew dema ku çîçikên ku ji bo girêdanê hatine afirandin têne rêvebirin çêdibe. subPath ji ConfigMap an veşartî. Piştî ku pod karê xwe qedand karûbarê systemd û çiyayê karûbarê wê dimîne di sîstemê de. Bi demê re, hejmareke mezin ji wan kom dibin. Di vê mijarê de jî pirsgirêk hene:
#!/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
... û ew her 5 hûrdeman bi karanîna superkronîk a ku berê hatî destnîşan kirin dimeşîne. Dockerfile wê bi vî rengî xuya dike:
Hate dîtin ku: heke me podek li ser girêkekê were danîn û wêneya wê ji bo demek pir dirêj were kişandin, wê gavê potek din ku heman girêkê "lêdixe" dê bi hêsanî. dest bi kişandina wêneya podê nû nake. Di şûna wê de, ew li bendê dimîne heya ku wêneya podê berê were kişandin. Wekî encamek, podek ku jixwe hatî plansaz kirin û wêneya wê dikaribû tenê di deqeyekê de were dakêşandin dê di rewşa containerCreating.
Bûyer dê bi vî rengî xuya bikin:
Normal Pulling 8m kubelet, ip-10-241-44-128.ap-northeast-1.compute.internal pulling image "registry.example.com/infra/openvpn/openvpn:master"
Ew dizane ku wêneyek yek ji qeydek hêdî dikare sazkirinê asteng bike per node.
Mixabin, gelek rêyên ji rewşê tune ne:
Biceribînin ku hûn Registry Docker-a xwe rasterast di nav komê de an rasterast bi komê re bikar bînin (mînak, GitLab Registry, Nexus, hwd.);
Di dema xebitandina sepanên cihêreng de, me di heman demê de rastî rewşek jî hat ku girêkek bi tevahî dev ji gihîştina xwe berdide: SSH bersivê nade, hemî şeytanên çavdêriyê dikevin, û dûv re di têketin de tiştek (an hema hema tiştek) anormal tune.
Ez ê di wêneyan de ji we re bi mînaka yek girêkek ku MongoDB lê dixebitî vebêjim.
Tiştê ku li jor xuya dike ev e ber qeza:
Û bi vî awayî - после qeza:
Di çavdêriyê de, di heman demê de bazdanek tûj jî heye, ku tê de girêk namîne:
Bi vî rengî, ji dîmenan diyar dibe ku:
RAM li ser makîneyê nêzîkî dawiyê ye;
Di xerckirina RAM-ê de bazdanek tûj heye, piştî ku gihîştina tevahiya makîneyê ji nişkê ve tê asteng kirin;
Erkek mezin digihîje Mongo, ku pêvajoya DBMS neçar dike ku bêtir bîranîn bikar bîne û bi çalak ji dîskê bixwîne.
Derket holê ku heke bîranîna belaş li Linux biqede (zexta bîrê dikeve) û guheztin çênebe, wê hingê ber Dema ku kujerê OOM digihîje, dibe ku di navbera avêtina rûpelan li cacheya rûpelê û nivîsandina wan li dîskê de çalakiyek hevseng çêbibe. Ev ji hêla kswapd-ê ve tête kirin, ku bi cesaret ji bo belavkirina paşîn bi qasî ku pêkan dibe gelek rûpelên bîranînê azad dike.
Mixabin, bi bargiraniyek I/O ya mezin re digel hejmarek piçûk bîranîna belaş, kswapd dibe stûna tevahiya pergalê, ji ber ku ew pê ve girêdayî ne hemî veqetandinên (xeletiyên rûpelê) rûpelên bîranînê yên di pergalê de. Ev dikare ji bo demek pir dirêj bidome heke pêvajo êdî nexwazin bîranînê bikar bînin, lê li qeraxa çoltera OOM-kujer sabît bibin.
Pirsa xwezayî ev e: çima kujer OOM ew qas dereng tê? Di dubarekirina xwe ya heyî de, kujerê OOM zehf bêaqil e: ew ê pêvajoyê bikuje tenê gava ku hewildana veqetandina rûpelek bîranînê têk biçe, ango. heke xeletiya rûpelê têk bibe. Ev ji bo demek dirêj çênabe, ji ber ku kswapd bi cesaret rûpelên bîranînê azad dike, cache rûpelê (tevahiya dîska I/O di pergalê de, bi rastî) vedigere dîskê. Bi hûrgulî, bi ravekirina gavên ku ji bo rakirina pirsgirêkên weha di kernelê de hewce ne, hûn dikarin bixwînin vir.
Di hin koman de, ku tê de bi rastî gelek zozan dixebitin, me dest pê kir ku piraniya wan ji bo demek pir dirêj li dewletê "daleqandî" ne. Pending, her çend konteynerên Docker bixwe berê li ser girêkan dimeşin û dikarin bi destan bi wan re bixebitin.
Wekî din, di describe tiştek xelet tune:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Successfully assigned sphinx-0 to ss-dev-kub07
Normal SuccessfulAttachVolume 1m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-6aaad34f-ad10-11e8-a44c-52540035a73b"
Normal SuccessfulMountVolume 1m kubelet, ss-dev-kub07 MountVolume.SetUp succeeded for volume "sphinx-config"
Normal SuccessfulMountVolume 1m kubelet, ss-dev-kub07 MountVolume.SetUp succeeded for volume "default-token-fzcsf"
Normal SuccessfulMountVolume 49s (x2 over 51s) kubelet, ss-dev-kub07 MountVolume.SetUp succeeded for volume "pvc-6aaad34f-ad10-11e8-a44c-52540035a73b"
Normal Pulled 43s kubelet, ss-dev-kub07 Container image "registry.example.com/infra/sphinx-exporter/sphinx-indexer:v1" already present on machine
Normal Created 43s kubelet, ss-dev-kub07 Created container
Normal Started 43s kubelet, ss-dev-kub07 Started container
Normal Pulled 43s kubelet, ss-dev-kub07 Container image "registry.example.com/infra/sphinx/sphinx:v1" already present on machine
Normal Created 42s kubelet, ss-dev-kub07 Created container
Normal Started 42s kubelet, ss-dev-kub07 Started container
Piştî hin kolandinê, me texmîn kir ku kubelet bi hêsanî wext tune ku hemî agahdariya li ser rewşa pod û ceribandinên zindîtî / amadebûnê ji servera API re bişîne.
Û piştî xwendina alîkariyê, me pîvanên jêrîn dîtin:
--kube-api-qps - QPS to use while talking with kubernetes apiserver (default 5)
--kube-api-burst - Burst to use while talking with kubernetes apiserver (default 10)
--event-qps - If > 0, limit event creations per second to this value. If 0, unlimited. (default 5)
--event-burst - Maximum size of a bursty event records, temporarily allows event records to burst to this number, while still not exceeding event-qps. Only used if --event-qps > 0 (default 10)
--registry-qps - If > 0, limit registry pull QPS to this value.
--registry-burst - Maximum size of bursty pulls, temporarily allows pulls to burst to this number, while still not exceeding registry-qps. Only used if --registry-qps > 0 (default 10)
Wek tê dîtin, nirxên xwerû pir piçûk in, û di %90 de ew hemû hewcedariyên xwe pêk tînin... Lê li cem me ev têr nekir. Ji ber vê yekê, em nirxên jêrîn destnîşan dikin:
... û kubelets ji nû ve dest pê kir, piştî ku me di grafikên bangên servera API-ê de wêneya jêrîn dît:
... û erê, her tiştî dest pê kir!
PS
Ji bo alîkariya wan di berhevkirina xeletiyan û amadekirina vê gotarê de, ez spasiya xwe ya kûr ji gelek endezyarên pargîdaniya me re, û nemaze ji hevkarê xwe yê tîmê me yê R&D Andrey Klimentyev re radigihînim (zuzzas).