Imperatiivne vs deklaratiivne - Kubernetese õpetus

Kubernetesesse saab kasutada kahte peamist viisi: tingimata paljude kubectli käskude abil või deklaratiivselt manifestide kirjutamise ja rakenduse kubectl kasutamisega. Esimene on hea õppimiseks ja interaktiivseks katsetamiseks (analoogne programmeerimiskeele REPL-iga); viimane on hea reprodutseeritavate juurutuste jaoks, st tootmiseks - ehkki võite tootmisel silumiseks siiski kasutada mõnda kubectli käsku.

PayScale'i andmeteaduse meeskond oli Kubernetese varajane kasutuselevõtja. Kirjutasin selle õpetuse esmalt meeskonna kaasliikmetele ja aitasin Kubernetes'i rakendust ülejäänud ettevõttes levitada. Loodame, et see aitab ka teisi.

Foto autor Matthew T Rader saidil Unsplash

Eeltingimused

See õpetus eeldab, et teil on juurdepääs klastrile. Tänapäeval saate hõlpsalt oma arvutis käivitada ühe sõlmega klastri või luua oma lemmikpilves mitme sõlmega klastri. Veenduge, et kubectl on teie masinasse installitud ja korralikult seadistatud. Järgmine käsk peaks õnnestuma:

kubectl klastri-teave

Teil peaks ka vaike nimeruumis olema piisavalt õigusi (mis võivad erineda vaike nimeruumist). Redigeerimisrollist peaks piisama. Kui lõite selle õpetuse jaoks klastri, olete tõenäoliselt administraator, nii et teil on hea minna. Vastasel juhul võib keegi olla teile pinnase ette valmistanud. Kui te ei saa sellest lõigust aru, siis jätkake :)

Valikuline: kui otsustate luua ja edasi lükata kohandatud konteineri pildi (vt allpool), mitte avalikku tõmmata, eeldame, et teil ja klastril on juurdepääs konteineri piltide registrile. Jällegi võib keegi olla teile pinnase ette valmistanud. GKE töötab hästi GCR-iga, AKS töötab hästi ka ACR-iga jne. Muidu on populaarsed valikud DockerHub ja Quay, kuid kui te oma pilti ei avalikusta, peate võib-olla konfigureerima vaiketeenuse konto oma nimeruumis pildi tõmbamisega salajane.

Valikuline: ehitage ja lükake

Olenemata sellest, kas rakendame tingimata või deklaratiivselt, vajame konteineri pilti. Võite selle osa vahele jätta ja kasutada olemasolevat pilti, kui teil on kiire, nt nginx, kuid mõned selle õpetuse toimingud on kohandatud selle rakenduse jaoks, mille me selles jaotises ehitame. Kui soovite teada saada, kuidas rakendust konteineritesse paigutada, lugege edasi.

Selle õpetuse jaoks alustame lihtsa veebirakenduse lähtekoodiga. Siin on näidisrakendus Node.js, mis põhineb dokumendil Node.js toodud näidisel (kirjutage vastus oma lemmik programmeerimiskeeles). Tühjas kaustas kopeerige allolev kood faili nimega app.js:

// app.js
const http = nõuda ('http');
const os = vaja ('os');
const ip = '0.0.0.0';
const port = 3000;
const hostname = os.hostname ();
const whoami = protsess.env ['WHOAMI'] || 'Anonüümne';
const server = http.createServer ((req, res) => {
  res.statusCode = 200;
  res.setHeader ('Sisu tüüp', 'tekst / tavaline');
  res.end (`Tere, ma olen $ {whoami}, alates $ {hostname}. \ n`);
});
server.listen (port, ip, () => {
  console.log (`Server töötab aadressil http: // $ {ip}: $ {port} /`);
});

Tegime põhinäites mõned muudatused:

  • Tähtis! Teenige 0.0.0.0, mitte 127.0.0.1. Viimane on mõeldud ainult tagasihelistamiseks ja see rakendus kuulab klastri IP-l (hõivatud 0.0.0.0) sissetulevaid taotlusi.
  • Samuti muutisime sõnumit „Tere maailm” kahe muutujaga: hostinimi, mis näitab, millele replika reageerib, ja keskkonnamuutuja WHOAMI, mis tuleb seadistada juurutamisajal vaikesättel „Anonüümne”.

Kui olete installinud Node.js, saate rakendust kohapeal testida:

node app.js # seejärel avage http: // localhost: 3000

Märkus. Kui loote iseenda oma, siis ärge häirige TLS-i lõpetamise või autentimisega, sest neid saab klastri servas hallata näiteks suursaadik ja isegi klastri rakenduste vahel teenusevõrgus nagu Istio, kui otsustate minna ilma usalduseta.

Pakime selle rakenduse Dockeri pildina. Kopeerige allolev kood faili nimega Dockerfile:

# Dockerfail
Sõlmest: 8
Koopia app.js.
ENTRYPOINT [“node”, “app.js”]

Käivitage samas kaustas:

doki ehitamine-myrepo: mytag.

Sõltuvalt teie konteineri piltide registrist asendage myrepo näiteks GCR-il gcr.io/project-name/image-name või DockerHubis kasutajanimega / image-name (vaikimisi registriga). Asendage mytag kõige uuemaga. Kui kasutate seda õpetust koos inimrühmaga, kasutage kindlasti erinevaid silte. Ärge unustage viimast punkti, muutes praeguse kausta ehitamise konteksti.

Lõpuks lükake pilt oma hoidlasse (kust Kubernetes tõmbub):

dokker push myrepo: mytag

Kohustuslik seadistamine

Jookse

Lühim viis Kubernetesisse juurutamiseks on käsu kubectl käivitamine. Asendage myapp millegi ainulaadsega, kui kasutate seda õpetust koos teiste inimestega ja jagate nimeruumi; asenda myrepo: mytag eelmises etapis valituga (või kasuta lihtsalt nginx):

kubectl run myapp - pilt myrepo: mytag --replicas 2

Käsk võib tunduda tuttav, kui olete kunagi konteineri käivitamiseks kohapeal doki käivitanud, kuid sarnasus siin peatub. Kapoti all juhtub järgmist (illustreeritud ka alloleval joonisel):

  1. kubectl tõlgib su hädavajaliku käsu deklaratiivseks Kubernetes'i juurutusobjektiks. Juurutamine on kõrgema taseme API, mis võimaldab värskendusi jooksvalt kasutada (vt allpool).
  2. kubectl saadab juurutuse Kubernetes API serverisse kube-apiserver, mis töötab klastris.
  3. kube-apiserver salvestab juurutuse kausta etcd (hajutatud võtmeväärtusega pood), mis töötab ka klastris ja vastab kubectlile.
  4. Asünkroonselt loob Kubernetesi juhihaldur, kube-controller-manager, kes jälgib juurutamise sündmusi (muu hulgas), loob juurutamisest replicaSetti ja saadab selle kube-apiserverile. ReplicaSet on juurutamise versioon. Jooksva värskenduse ajal luuakse uus replicaSet, mida järk-järgult vähendatakse soovitud arv koopiaid, samal ajal kui vana nullitakse.
  5. kube-apiserver salvestab ReplicaSet kausta etcd.
  6. Asünkroonselt, kube-controller-manager, loob ReplicaSetist kaks kausta (või rohkem, kui me laiendame), ja saadab need kube-apiserverisse. Kaunad on Kubernetese põhiüksus. Need tähistavad ühte või mitut konteinerit, mis jagavad Linuxi rühma ja nimeruume.
  7. kube-apiserver salvestab kaustad jne.
  8. Asünkroonselt uuendab Kubernetes'i ajakava kube-planeerija, mis jälgib Pod-sündmusi, uuendab iga Pod-i, et määrata see sõlmele, ja saadab need tagasi kube-apiserverisse.
  9. kube-apiserver salvestab kaustad jne.
  10. Lõpuks käivitab konteineri tegelikult määratud jälgimisnupul töötav kubelet, mis alati vaatab.

Märkus: kontroller, planeerija ja kubelet saadavad olekuteavet ka API serverisse.

Kokkuvõtlikult võib öelda, et Kubernetes on juhtsilmustega CRUD API.

Kubebuilderi dokumentatsioonist, mis on litsentsitud Apache litsentsi versiooni 2.0 alusel

Hankige, kirjeldage

kubectl run lõi juurutuse, mis rullus lahti Pods ReplicaSet. Kus nad on? Kasutage kubectl get, et loetleda kõik vaikimisi kasutatavas nimeruumis olevad juurutamised, replikatsioonid ja komplektid:

kubectl saab juurutusi # mitmuses või ainsuses või juurutab lühidalt
kubectl saab replikaate # või rs
kubectl saada kaunade # või po

Üksiku objekti saamiseks lisage argumendina selle nimi, nt:

kubectl saada kasutuselevõtu myapp

Objekti oleku vaatamiseks etcd-s salvestatud kujul kasutage suvandit - väljund (või -o):

kubectl võtab kasutusele rakenduse myapp -o yaml

Lisateabe saamiseks, sealhulgas objektiga seotud hiljutiste sündmuste (nt vigade), kasutage käsku kubectl kirjeldada:

kubectl kirjeldab juurutusrakenduse myapp kasutamist

Minge edasi ja käivitage samad käsud ka ReplicaSet ja Pods.

Silt

Sildid on väga kasulikud. Silt on võtmeväärtusega stringipaar. Kõiki Kubernetes'i objekte saab märgistada ja neid silte saab kasutada valijana. Käsklus kubectl käivitas käsu = myapp meie juurutamisse (ja kontrollitud ReplicaSet ja Pods) automaatselt. Nägite seda YAML-i väljundites ja kirjeldustes. Nende siltide nägemiseks tavalises tabeli väljundis kasutage suvandit - show-labels:

kubectl saab juurutamist - show-sildid
kubectl saab replikaate - show-sildid
kubectl hangib kaustad - show-sildid

Kui teate, millised võtmed teid huvitavad, kasutage väärtuste veergude kuvamiseks suvandit - sildi-veerud (või -L), nt:

kubectl saavad replikaadid -L käivitada

Kõige tähtsam on see, et objektide sildi järgi filtreerimiseks kasutage suvandit - selector (või -l), nt:

kubectl hangi kaustad -l run = myapp

Saate silte lisada ka käsitsi, nt:

kubectl sildi juurutamine myapp foo = riba

Kustuta

Kubernetes API on põhimõtteliselt deklaratiivne, mis tähendab, et kontrollerid töötavad alati vaadeldava oleku ja soovitud oleku ühitamiseks. Seega, kui kustutame Pod, loob ReplicaSet kontroller uue, et see asendada, et säilitada soovitud replikate arv. Vaata ise:

kubectl kustuta kaustad -l run = myapp
# oota natuke
kubectl hangi kaustad -l run = myapp

Pange tähele, et uutel kaustadel on erinevad genereeritud nimed kui vanadel (juhusliku järelliidete osa).

Sama on ka ReplicaSetiga. Kui me selle kustutame, loob juurutuskontroller selle asendamiseks uue. Kuid kui kustutame juurutamise ise, on meie eesmärk tegelikult rakendus kustutada; miski ei juhi juurutamist, vaid meid.

Port-edasi

Siiani oleme näinud objekte, mille Kubernetes lõi vastusena kubectli jooksule. Kubernetes näitab, et kaunad on valmis lihtsalt seetõttu, et konteinerites olevad protsessid töötavad. Võiksime määratleda olulisema elujõulisuse sondi, kuid nüüd kontrolligem seda käsitsi testides, kas meie rakendus töötab ootuspäraselt.

kubectl port-forward puhverdab kohaliku porti (teie arvutis) Pod-pordi kaudu API-serveri kaudu (turvatud TLS-iga Interneti kaudu, teie masina puhverserveri ja API-serveri vahel). See on üsna paindlik käsk. Kui esitate argumentidena Pod-nime ja pordi, edastab kubectl selle Pod-pordi lihtsalt. Kuna Pod-nimesid genereeritakse tavaliselt koos juhuslike märkidega, on sageli mugavam esitada kontrollitava objekti, näiteks juurutuse, tüüpi / nimepaari. kubectl valib sulle sobiva kausta:

kubectl port-forward kasutuselevõtt / myapp 3000

Seejärel avage lihtsalt "brauseris" (või keerake mõnes muus terminalis) leht http: // localhost: 3000 /, et näha sõnumit “Tere maailm”. Masina nimi ei tohiks uuesti laadimisel muutuda, kuna edastame ainult ühte kausta. Samuti pange tähele, et kubectl runi käivitamisel ei määranud me WHOAMI keskkonnamuutujat; meil võiks see olla valikuga --env abil, kuid kasutame seda väljajätmist võimalusena, kuidas hilisemas etapis redigeerida kubectli komplekti ja kubectli plaastri abil juurutamist.

Pordi edastamise peatamiseks vajutage Ctrl + C. Kui ühendus on mõnda aega passiivne, suletakse see automaatselt.

Märkus. Võite kasutada teistsugust porti, nt kui Pod-pord on teie arvutis, nt:

kubectl port-forward juurutamine / myapp 5000: 3000

Paljasta

Meie rakendus töötab, kuid muud juurutatud rakendused (nende kaustad) ei peaks pordi edastamist kasutama. Podidel on Pod IP-d ja DNS-kirjed. Me võiksime neid kasutada, kuid kaustad on lühiajalised, nende IP-d ja nimed muutuvad. Samuti vajame moodust, kuidas rääkida mitte ju üksikute Pod-dega, vaid ka juurutamisega (või muude Pod-gruppidega). Vajame teenuse avastamist.

Kubernetesi teenus suunab liikluse teenuse sildi valijale vastavate kaustade komplekti. Kui valijale sobib mitu tasku, kuulavad ja võtavad nad kõik vastu liiklust. Kasutuselevõtu paljastamiseks võime teenuse valijana lihtsalt kasutada juurutamise valijat (meie puhul run = app).

Kubectl paljastamiskäsk automatiseerib teenuse loomise juurutamisest, replicaSetist või isegi teisest teenusest või ühest kaustast. Otsija valitakse antud objektilt automaatselt, kui suvanditega pole teisiti määratud:

kubectl paljastab juurutamise myapp --port 80 - target-port 3000 # kuvame tavalises HTTP-pordis 80, mida me ei saanud oma dev-seadmes kasutada

Kontrollige, kas teenus on loodud:

kubectl saada teenuse nr või svc

Kuulatavate kaablite kausta IP-sid näete teenuse kirjelduses või kaasotsija lõpp-punktides (teenuse juhtimisel). See võib olla kasulik võrgundusprobleemide silumiseks:

kubectl kirjeldab teenuse myapp
kubectl saada lõpp-punkte myapp

Keerame üles interaktiivse terminali abil ajutise puldi, et tegelikult teenusele helistada:

kubectl run mytest -it --rm --imape alpine # Alpine on pisike
# sees Mytest:
apk lisada lokk
curl http: // myapp # “Tere maailm ...”
väljumine

See väärib mõnda selgitust: kubectli käitus lõi juurutuse nagu varem, eraldas TTY (-t või - päris), hoidis stdin lahti (-i või --stdin), oli selle küljes ja kustutas juurutuse, kui me väljusime ( --rm). Need valikud võivad tunduda tuttavad, kuna need on olemas ka doki käitamise jaoks.

Palgid

Kui meie rakendusel oli probleeme, võiksime kontrollida selle logisid. Konteinerilogid salvestatakse konteineri käitusaja (tavaliselt Dockeri deemon) sõlmedes ja neid vaikimisi pööratakse automaatselt, kui logifail ületab 10 MB. Võiksime logiagenti üles seada, et logid püsivasse taustaprogrammi suunata; lihtsalt pidage meeles, kubectli logid näevad ainult sõlmedele jäänud logisid.

Nii nagu port-forward puhul, võime ka taotleda konkreetse Pod-i logisid, sisestades selle nime, või taotleda Pod-gruppide logisid, sisestades kontrollitava objekti (nt juurutamine) tüüpi / nimepaari:

kubectl logib juurutamist / myapp

Meie puhul pole palju sisse logitud. Tootmisrakendus võib siiski olla sõnavaesem, eriti kui peate logisid tegelikult kontrollima (nii palju vigu!). Väljundit saate piirata - säriaja (nt 1 m), - hilise aja (nt 2018–11–01T16: 30: 00) ja - jao (nt 20 rida) valikuga. Muud kasulikud valikud hõlmavad --järgmist (või -f), - eelnevat (kui konteinerid jätkuvad krahhidena) ja - ajatempleid (kui teie rakendus ei logi ajatempleid juba sisse). Pärast seda võib olla mugav väljund faili kirjutada ja sellega ümber käia, näiteks:

kubectl logib juurutamist / myapp --ce 5m> log.txt
grepi viga log.txt
# veel grep

Exec, kopeeri

kubectl pakub veel mõnda tööriista jooksvate konteinerite silumiseks. kubectl exec käivitab konteineris käsu ja kubectl cp kopeerib failid ja kataloogid konteineritesse ja konteineritest. Need kaks käsku võtavad kasutusele otsesed nimed, mitte juurutusnimed. Siin on kasulik trikk, kasutades ära suvand --output jsonpath Pod-nime salvestamiseks koorega muutujasse:

POD_NAME = $ (kubectl hangib kaustad -l käivitub = myapp -o jsonpath = {. Üksused [0] .metadata.name})

Seejärel saame seda muutujat kasutada teistes käskudes:

kubectl exec $ POD_NAME -it sh # avab konteineris interaktiivse kesta
# konteineri sees, ainult mõned näited:
sõlme - teisendus
kaja $ WHOAMI
väljumine
# tagasi oma masinasse
kubectl cp $ POD_NAME: app.js remote-app.js # jällegi, lihtsalt näide (on paremaid võimalusi teada saada, milline kood praegu tootmises töötab)

Komplekt, skaala, plaaster

Peame ikkagi seadistama WHOAMI keskkonnamuutuja. Seda saame teha kubectli komplekti või kubectli plaastri abil. Kui me siin oleme, õpime ka seda, kuidas ressursside muutusi kubectli abil saada - vaadata (või -w) ja jälgida jooksvaid värskendusi reaalajas:

kubectl võtab kasutusele rakenduse myapp -w
# teises terminalis:
kubectl saavad replikaadid -w -l run = myapp
# kolmandas terminalis:
kubectl saada kaunad -w -l run = myapp
# neljandas terminalis:
kubectl set env juurutamine / myapp WHOAMI = "HAL 9000"

Kolmes esimeses terminalis jälgige uue ReplicaSet loomist ja uute / vanade kaustade korraldatud loomist / kustutamist. Näete ka olekumuutustele vastavaid ridu (vaadake kaustade numbreid veerus SOOVITATUD, HETKESEISEKS, AJAKOHASEKS, KÄTTESAADAVAKS / VALMIS). Olete just olnud jooksva värskenduse tunnistajaks. Mõelgem välja meie juurutamine enne uue muudatuse käivitamist:

kubectl scale --replicas 3 juurutamise myapp

Kubectli komplekti käsk on piiratud keskkonnamuutujate, piltide, ressursitaotluste / limiitide, selektorite, teenuseAccounts ja RoleBindings subjektide seadmisega (vrd Role-Based Access Control ehk RBAC, mis jääb välja selle juhendi rakendusalast). Kubectli plaastri käsk on üldisem. See aktsepteerib konkreetsete väljade asendamiseks või ühendamiseks JSON-i või YAML-i. Lihtsustatud näitena kavatseme mööda minna ajastajast ja sundida kõiki poodiume töötama ühel sõlmel:

Esiteks vaadake, kas meie rakenduse koopiad töötavad praegu erinevatel sõlmedel:

kubectl get pods -l run = myapp -o wide # kontrolli NODE veergu

Valime lihtsalt ühe ja parandame sellega meie juurutamise:

NODE_NAME = $ (kubectl hangib kaustad -l töötab = myapp -o jsonpath = {. Üksused [0] .spec.nodeName})
kubectl plaastri juurutamine myapp -p '{"spec": {"mall": {"spec": {"nodeName": "' $ NODE_NAME '"}}}}' '

Nüüd tuleks kõik kaunad samasse sõlme määrata:

kubectl saada kaunad -l run = myapp -o wide

Märkus. Ajasti mõjutamiseks on nutikamaid viise, näiteks teatud sõlmede märgistamine ja sõlmevalija, afiinsuste ja anti-afiinsuste, rikete ja tolerantside kasutamine jne.

Deklaratiivne konfiguratsioon

Palju õnne! Kui olete sellega kaugele jõudnud, olete õppinud, kuidas Kubernetesile öelda, mida teha. Kuid Kubernetese jõud on selle deklaratiivses API-s ja kontrollerites. Võite lihtsalt öelda Kubernetesile, mida soovite, ja ta teab, mida teha. Seega, välja arvatud kirjutuskaitstud hankimine, kirjeldamine ja logid, silumisporti edasisuunamine, täitmine ja cp ning kustutamine (kaustade asendamine on lihtsam kui nende parandamine), kasutate harva, kui üldse, teisi käske, mida me nägin eelmises jaotises (vabandust, kuid need olid kasulikud mõne olulise kontseptsiooni tutvustamiseks). Enamasti kasutate lihtsalt kubectli rakendusi ja YAML (või JSON) manifeste olekust, mille Kubernetes salvestab rakenduses etcd.

Jooksvate objektide manifestide tellingute jaoks saate lihtsalt salvestada kubectl get -o yaml --export väljundi:

kubectl saada juurutamine myapp -o yaml --export> myapp-deployment.yaml
kubectl teenuse teenus myapp -o yaml --export> myapp-service.yaml
# kopeerimiskomplekte ja taskuid kontrollitakse ja need ei vaja manifeste (juurutusdokument sisaldab kausta malli)

Manifest ei vaja tegelikult kogu salvestatud olekut. Osa sellest lisab Kubernetes. Ekspordi suvandiga eemaldatakse olekusektsioon ja mõned metaandmed (UID, loomise ajatempel jne), kuid võiksite eemaldada veelgi rohkem, nt vaikeväärtusi. Me vajame lihtsalt piisavalt, et täpsustada, mida me tahame.

Dokumentatsioonis on toodud põhinäited juurutamiste ja teenuste kohta. Meie puhul langeb manifest järgmiselt:

# myapp-deployment.yaml
apiVersion: rakendused / v1
liik: juurutamine
metaandmed:
  nimi: myapp
spec:
  koopiad: 3
  valija:
    matchLabels:
      käivita: myapp
  mall:
    metaandmed:
      sildid:
        käivita: myapp
    spec:
      konteinerid:
      - nimi: myapp
        pilt: psdocker / myapp: mytag
        env:
        - nimi: WHOAMI
          väärtus: "HAL 9000"
# myapp-service.yaml
apiVersioon: v1
lahke: teenindus
metaandmed:
  nimi: myapp
spec:
  valija:
    käivita: myapp
  sadamad:
  - port: 80
    targetPort: 3000

Toimimise tõestamiseks kustutage kõigepealt kõik ja rakendage siis meie manifestid:

kubectl kustutab juurutusrakenduse myapp
kubectl teenuse myapp kustutamine
kubectl rakenda -f myapp-deployment.yaml -f myapp-service.yaml

Kui me poleks juurutamist ja teenust kustutanud, oleks neid värskendatud, et need vastaksid manifestidele. Käsk kubectl apply on idempotentne. Pärast manifestide muutmist saame seda uuesti kasutada. Proovige näiteks repliikide arvu redigeerida ja käivitage viimane käsk uuesti.

Kui te pole skeemis kindel või soovite oma võimalusi uurida, on Kubernetes API viide kasulik kaaslane.

Mitme keskkonnaga keerukate rakenduste puhul võib töötlemata manifestide haldamine keeruliseks osutuda. Abiks võivad olla sellised tööriistad nagu kustomize (nüüd kubectli osa alates v1.14), Helm või Jsonnet. Jesse Suen kirjutas suurepärase võrdluse. Terve ehituse ja juurutamise protsessi jälgimiseks ning siltidega pildinimede manifestidesse süstimiseks on veel üks kasulik tööriist skaffold.

Läheme kaugemale

Selles õpetuses oleme töötanud Kuberneteses kodakondsuseta rakenduste põhiosadega: Deployments, ReplicaSets, Pods, Services. Juurutamisel on ka alternatiive (mitte kõik rakendused ei toeta värskenduste värskendamist): StatefulSets, DaemonSets, Jobs, CronJobs jne. ConfigMaps ja Secrets on kasulikud rakenduse konfiguratsiooni talletamiseks. Samuti oleme juurutanud seadmeid ainult kõige elementaarsemal viisil. Tootmisel peaksite seadistama protsessori- ja mälupäringud ning limiidid ja teid võib muu hulgas huvitada automaatne skaleerimine.

Kubernetesi õppimiseks on paar head raamatut. Ainus, mida ma lugesin ja soovitan kõhklemata, on Kubernetes tegevuses (Manning). Muidugi on ametlik dokumentatsioon suurepärane viide ja ilmub õigustatult enamiku Google'i otsingute ülaosas.