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:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

Rewşek wusa li ser girêkên din jî tê dîtin:

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]

Di heman girêkan de em dibînin:

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] <defunct>
root     17398  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root     16852  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root      9473  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root      4664  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root     30571  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root     24113  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root     16475  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root      7176  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>
root      1090  0.0  0.0      0     0 ?        Z    Feb06   0:00      |       _ [curl] <defunct>

Derket holê ku ev tevger encama xebata podê ye superkronîk (karsazek ​​Go-ya ku em bikar tînin da ku karên kronan di pods de bimeşînin):

 _ 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] <defunct>
|       _ [curl] <defunct>
|       _ [curl] <defunct>
|       _ [curl] <defunct>
…

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:

  1. 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
  2. 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:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

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 xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

  • 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:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

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:

  1. #5916;
  2. kubernetes #57345.

... ya paşîn ya ku di pergalê de PR-yê vedibêje: #7811 (mijar di sîstemê de - #7798).

Pirsgirêk êdî di Ubuntu 18.04-ê de nemaye, lê heke hûn dixwazin Ubuntu 16.04-ê bikar bînin, dibe ku hûn li ser vê mijarê rêça me kêrhatî bibînin.

Ji ber vê yekê me DaemonSet-a jêrîn çêkir:

---
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

... û ew skrîpta jêrîn bikar tîne:

#!/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:

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"]

Çîrok 4. Pêşbaziya dema plansazkirina pods

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:

  1. 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.);
  2. Karûbarên wekî wekî kraken.

Çîrok 5. Ji ber kêmbûna bîrê girêk daliqandî ne

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:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

Û bi vî awayî - после qeza:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

Di çavdêriyê de, di heman demê de bazdanek tûj jî heye, ku tê de girêk namîne:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

Bi vî rengî, ji dîmenan diyar dibe ku:

  1. RAM li ser makîneyê nêzîkî dawiyê ye;
  2. Di xerckirina RAM-ê de bazdanek tûj heye, piştî ku gihîştina tevahiya makîneyê ji nişkê ve tê asteng kirin;
  3. 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.

Ev tevger divê baştir bibe bi kernel Linux 4.6+.

Çîrok 6. Pod di dewleta Li bendê de asê dibin

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:

--event-qps=30 --event-burst=40 --kube-api-burst=40 --kube-api-qps=30 --registry-qps=30 --registry-burst=40

... û 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:

Di xebata Kubernetes de 6 xeletiyên pergalê yên balkêş [û çareseriya wan]

... û 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).

PPS

Li ser bloga me jî bixwînin:

Source: www.habr.com

Add a comment