- Kubernetes – orchestrátor kontejnerů (1) – schedulery vs. PaaS
- Kubernetes – orchestrátor kontejnerů (2) – instalace a první běžící kontejner
- Kubernetes – orchestrátor kontejnerů (3) – deployment aplikací, škálování a rollback
- Kubernetes – orchestrátor kontejnerů (4) – interní balancing a discovery služeb
- Kubernetes – orchestrátor kontejnerů (5) – přístup zvenku
Prozatím jsme si vyzkoušeli provoz kontejnerů v Kubernetes. Scheduler pro nás zajistí jejich běh, aniž bychom museli říkat co se na kterém hostiteli má dělat. Dokážeme provozovat kontejner třeba v pěti kopiích s tím, že Kubernetes je rozloží v infrastruktuře a v případě nějakých výpadků naklonuje další. Dokonce to můžeme použít k migraci z jedné verze image na jinou s tím, že Kubernetes kontejnery (přesněji pody, tedy shluky kontejnerů, ale i jeden samotný) mění postupně.
Services – služby, které váš deployment nabízí
V předchozích příkladem nám jedna věc zásadně chyběla. Je fajn, že nám od jedné služby běží pět kopií kontejnerů rozprostřených v infrastruktuře, ale co networking? Jak se k nim dostanou třeba ostatní služby a jak se na ně dá balancovat provoz? O tom je koncept service v Kubernetes, který si teď vyzkoušíme.
Podobně jako v minulých dílech zařiďte deployment pěti podů s labelem mujweb. Takhle vypadá obsah souboru mujweb.yaml:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: mujweb-deployment spec: replicas: 5 template: metadata: labels: app: mujweb spec: containers: - name: mujweb image: cloudsvet/k8s-web:v1 ports: - containerPort: 3000
A takto spustíme deployment, pokud už to nemáme hotové z minula.
kubectl create -f mujweb.yaml
Vytvořte teď nový soubor mujweb-service.yaml. Ten bude představovat naší službu a obsah bude vypadat takhle:
apiVersion: "v1" kind: "Service" metadata: name: "mujweb-sluzba" spec: selector: app: "mujweb" ports: - name: "http" protocol: "TCP" port: 80 targetPort: 3000
Co se tam odehrává? Říkáme, že chceme novou službu, která bude navenek nabízet něco běžícího na portu 80. Služba bude implementována pody, které ve svém názvu (část selector) mají mujweb. Tato část může být podstatně bohatší a dají se tak dělat docela chytré filtrace co všechno patří pod jednu službu. Dovnitř ke kontejnerům se využívá portu 3000 (to je co jsme uvedli v rámci definice deploymentu, tedy uvnitř podu je nějaký web server poslouchající na portu 3000). Tato služba tedy bude něco jako virtuální IP load-balanceru s tím, že členy jeho poolu si Kubernetes doplňuje sám na základě selectoru (tedy pokud vypadne jeden z hostitelů a s ním odumře jeden pod, Kubernetes ho vyřadí z balancingu, rozjede pod jinde a ten pak přiřadí do poolu).
Spusťte službu.
$ kubectl create -f mujweb-sluzba.yaml service "mujweb-sluzba" created
Podívejme se na ni.
$ kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.3.0.1 <none> 443/TCP 1h mujweb-sluzba 10.3.0.155 <none> 80/TCP 16s
Na adrese 10.3.0.155:80 běží naše balancovaná služba. Podívejme se na detailnější popis.
$ kubectl describe services/mujweb-sluzba Name: mujweb-sluzba Namespace: default Labels: <none> Selector: app=mujweb Type: ClusterIP IP: 10.3.0.155 Port: http 80/TCP Endpoints: 10.2.14.3:3000,10.2.14.4:3000,10.2.23.2:3000 + 2 more... Session Affinity: None No events.
Všimněte si Endpoints, to je něco jako pool u klasického balanceru.
Protože se jedná o adresu interní pro Kubernetes (tedy vhodnou pro balancing třeba datových služeb a všeho dalšího, na co se nechodí externě, ale jen interně – jak s balancingem frontendu se dozvíte příště), musíme si to vyzkoušet zevnitř. Stačí nám kontejner s cURL (řekněme něco jako textový webový prohlížeč). Nastartujte jeden v interaktivním režimu (tedy že rovnou skočíte dovnitř) a spusťte curl na mujweb-sluzba. Měli byste být svědky balancingu, protože aplikace v podu vrací svou MAC adresu.
$ kubectl run -i --tty mujlinux --image=tutum/curl Waiting for pod default/mujlinux-1229873022-g9icp to be running, status is Pending, pod ready: false Waiting for pod default/mujlinux-1229873022-g9icp to be running, status is Pending, pod ready: false ... root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:17:03 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:04 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:04 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:04 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:03 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:04 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:17:02 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:03 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:17:02 root@mujlinux-1229873022-g9icp:/# curl mujweb-sluzba v1: 02:42:0a:02:0e:03
Výborně. Něco takového by v klasickém světě hypervisoru a fyzického balanceru znamenalo podstatně víc práce a hlavně by to nebylo takhle krásně dynamické (to by vyžadovalo práce ještě víc).
Vyzkoušejme si teď chování rolling upgradu. Ještě v tomto okně spusťte nekonečnou smyčku curl volání.
root@mujlinux-1229873022-g9icp:/# while true; do curl mujweb-sluzba; sleep 0.4; done v1: 02:42:0a:02:0e:04 v1: 02:42:0a:02:0e:04 v1: 02:42:0a:02:0e:04 v1: 02:42:0a:02:0e:03 v1: 02:42:0a:02:0e:03 v1: 02:42:0a:02:0e:03 v1: 02:42:0a:02:17:03
Otevřete si jiné okno a v něm aktualizujte soubor mujweb.yaml tak, aby mířil na jiný image kontejneru s tagem v2 (to jsme dělali minule, podrobnosti najdete tam).
$ kubectl apply -f mujweb.yaml deployment "mujweb-deployment" configured
Rychle koukněte co se děje v původním okně. Vidíte balancing a rolling upgrade v praxi. Nejdřív hodně v1, pak mix v1 a v2 a nakonec už jen v2.
v1: 02:42:0a:02:17:02 v1: 02:42:0a:02:17:02 v1: 02:42:0a:02:0e:04 v2: 02:42:0a:02:0e:05 v1: 02:42:0a:02:17:02 v1: 02:42:0a:02:0e:03 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:06 v1: 02:42:0a:02:23:03 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:23:04 v1: 02:42:0a:02:23:03 v1: 02:42:0a:02:23:03 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:05 v1: 02:42:0a:02:23:03 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:0e:05 v2: 02:42:0a:02:23:04 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:0e:06 v2: 02:42:0a:02:23:04
Service discovery
Jak ale služby poznájí, kde která je? Pokud máte větší prostředí a chcete k tomu přistupovat systémově a zcela nezávisle na platformě, doporučuji deployment vašeho vlastního Etcd nebo Consul. Každá služba se tam po startu zaregistruje a vše si řídíte sami. Nicméně Kubernetes vám základní service discovery poskytne zadarmo a je mnoho situací, kdy to bohatě stačí. Podívejme se na to.
Zůstaňte v kontejneru, kde jsme testovali curl a nainstalujte si sem dnsutils. Následně se zeptejte kde je mujweb-sluzba.
root@mujlinux-1229873022-g9icp:/# apt-get update root@mujlinux-1229873022-g9icp:/# apt-get install dnsutils -y root@mujlinux-1229873022-g9icp:/# nslookup mujweb-sluzba Server: 10.3.0.10 Address: 10.3.0.10#53 Name: mujweb-sluzba.default.svc.cluster.local Address: 10.3.0.155
Jak vidíte Kubernetes pro vás provozuje DNS server kam automaticky zakládá záznamy pro služby, které vytvoříte. Klasický DNS dotaz má výhodu v tom, že je to velmi stará věc a kompatibilní prakticky se vším. Nicméně základní dotaz nám neprozradil, na kterém portu služba běží. Jasně – teď předpokládáme port 80, ale v případě API to může být 8080, 8443, 8081 nebo cokoli dalšího.
Z toho důvodu Kubernetes vytvořil i bohatší SRV záznam. To už ale musí aplikace umět využít. root@mujlinux-1229873022-g9icp:/# nslookup -querytype=srv _http._tcp.mujweb-sluzba Server: 10.3.0.10 Address: 10.3.0.10#53 _http._tcp.mujweb-sluzba.default.svc.cluster.local service = 10 100 80 mujweb-sluzba.default.svc.cluster.local.
V části service je to třetí číslo číslo portu (první číslo je priorita a druhé váha).
DNS je klasika, ale moderní aplikace si umí vzít většinu konfiguračních informací z proměnných prostředí. Kubernetes nastartovanému kontejneru poskytl informací docela dost, podívejte se.
root@mujlinux-1229873022-g9icp:/# env | grep MUJWEB MUJWEB_SLUZBA_PORT=tcp://10.3.0.155:80 MUJWEB_SLUZBA_SERVICE_HOST=10.3.0.155 MUJWEB_SLUZBA_SERVICE_PORT=80 MUJWEB_SLUZBA_PORT_80_TCP_PORT=80 MUJWEB_SLUZBA_PORT_80_TCP_PROTO=tcp MUJWEB_SLUZBA_PORT_80_TCP_ADDR=10.3.0.155 MUJWEB_SLUZBA_SERVICE_PORT_HTTP=80 MUJWEB_SLUZBA_PORT_80_TCP=tcp://10.3.0.155:80
Je to dost na to, abyste použili curl pro přístup ke službě i bez DNS.
root@mujlinux-1229873022-g9icp:/# curl $MUJWEB_SLUZBA_SERVICE_HOST:$MUJWEB_SLUZBA_SERVICE_PORT v2: 02:42:0a:02:23:04