- 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
Už umíme vytvářet pody v desired state a HA a balancovat provoz na služby. To všechno se ale děje ve vnitřní síti Kubernetes. Jak umožnit přístup zvenku? Jak se uživatelé dostanou na váš web server? To si dnes vyzkoušíme.
NodePort
Pro malé clustery a speciální situace možná vystačíte s konceptem NodePort. Stačí do definice služby uvést, že je právě tohoto typu a Kubernetes si vybere nějaký vysoký port a způsobí, že službu na tomto portu najdete na všech hostitelech clusteru (tedy pokut oslovíte node, kde žádný z podů služby neběží, přesměruje vás). Má to samozřejmě limity ve škálovatelnosti a výkonu a někdy vám může docela vadit, že jsou web aplikace na exotických portech. Přesto tím začněme. Je to jednoduché a někdy se může hodit.
Vytvořme novou službu, která bude velmi podobná té z minulého dílu – jen bude typu NodePort. Takhle bude vypadat náš soubor mujweb-np-sluzba.yaml:
apiVersion: "v1" kind: "Service" metadata: name: "mujweb-np-sluzba" spec: selector: app: "mujweb" ports: - name: "http" protocol: "TCP" port: 80 targetPort: 3000 type: NodePort
Vytvořte službu
kubectl create -f mujweb-np-sluzba.yaml You have exposed your service on an external port on all nodes in your cluster. If you want to expose this service to the external internet, you may need to set up firewall rules for the service port(s) (tcp:30892) to serve traffic. See http://releases.k8s.io/release-1.3/docs/user-guide/services-firewalls.md for more details. service "mujweb-np-sluzba" created
Ze světa zcela mimo Kubernetes cluster (což je přesně to co chceme dosáhnout) se zkuste připojit na port, který jste v předchozím příkazu dostali.
curl 172.17.8.103:30892 v1: 02:42:0a:f4:08:04 curl 172.17.8.103:30892 v1: 02:42:0a:f4:42:04 curl 172.17.8.102:30892 v1: 02:42:0a:f4:42:03 curl 172.17.8.102:30892 v1: 02:42:0a:f4:42:04
Funguje nám to zvenku a ještě to balancuje pody. Všimněte si, že odpověd jsme dostali z hostitele 172.17.8.103 stejně tak, jako z hostitele 172.17.8.102
Load balancer vně Kubernetes (Google GCE, AWS, OpenStack Magnum?)
Druhým typem při definici služby je LoadBalancer. To zní velmi lákavě, ale možnosti omezené na vybraná cloudová prostředí, konkrétně Google GCE, Amazon AWS a OpenStack (tam to ale není “na kliknutí”, musíte se o integraci s Kubernetes postarat třeba použitím Magnum apod.). Pokud uvedete tuto možnost zajistí Kubernetes balancing o úroveň níže, tedy v samotné infrastruktuře (tedy v IaaS). Moje instalace je ve Vagrantu a VirtualBoxu, takže LoadBalancer použít nemohu.
Service-loadbalancer je na konci života
Univerzálnějším řešení měl být service-loadbalancer, který je ovšem dnes nahrazován novou implementací s větší budoucností (Ingress viz dále). Existují do něj pluginy a hlavně na rozdíl od klasického typu představeného v předchozím odstavci podporuje i L7 přístup, ne jen L4 (tzn. dokážete balancovat třeba podle URL). Pokud s Kubernetes začínáte dnes, nemá už moc cenu to zkoumat – pojďme rovnou do Ingress.
Ingress je budoucnost
Přestože koncept Ingress zatím nedosahuje funkčních vlastností service-loadbalancer, je jeho nástupcem. Bez dalšího přemýšlení funguje s Google GCE, tedy v cloudu, ale můžete použít i vlastní Ingress controller. To je způsob jak získat univerzální řešení. Berte to třeba jako plugin – dnes to bude open source NGINX software, ale v budoucnu to může být třeba něco pro F5, A10, OpenStack LBaaS a tak podobně.
Nejprve tedy potřebujeme kontroler. Ať nemusím opisovat, naklonujte si tento repozitář:
git clone https://github.com/kubernetes/contrib.git
Než spustíme samotný Ingress kontroler potřebujeme ještě vytvořit “výchozí stránku”. Půjde o službu (implementovanou samozřejmě kontejnery v podu), na kterou se Ingress kontroler obrátí, pokud neví kudy dál (někdo přistupuje na URL, která není definovaná). Využijeme výchozího příkladu, kdy nám to vrátí jednoduchou chybu 404, ale v praxi tady můžete mít něco graficky vyvedenějšího. Pak spustíme kontroler.
Nastartujte následující služby:
kubectl create -f contrib/ingress/controllers/nginx/examples/default-backend.yaml kubectl expose rc default-http-backend --port=80 --target-port=8080 --name=default-http-backend kubectl create -f contrib/ingress/controllers/nginx/examples/default/rc-default.yaml
Pojďme na nějaké webové aplikace (tu z minula použít nemůžeme – není to opravdové HTML, nemá hlavičky apod.). Abych šetřil místo nepoužiji YAML soubory s definicí (byť to preferuji – lepší přehled a pořádek) a vyzkoušíme si alespoň nastartování deploymentu (příkaz run) a vytvoření služby (příkaz expose). Spustíme si deployment trojice NGINX serverů a trojice Apache server a jim příslušné služby. Proč takhle? Jde mi o to je následně odlišit a abychom nemuseli vytvářet obsah, vystačíme se základní hláškou každého z web serverů.
kubectl run web1 --image=nginx --replicas=3 --port=80 kubectl run web2 --image=eboraas/apache --replicas=3 --port=80 kubectl expose deployment web1 --port=80 --target-port=80 --name=web1 kubectl expose deployment web2 --port=80 --target-port=80 --name=web2
Definujme si Ingress a využijeme jeho L7 vlastností. Budeme chtít, aby běžel na externí IP adrese a aby reagoval podle URL. Pokud budeme chtít ip/mujweb1 tak nás nasměruje do web1 (nginx), pokud půjdeme na ip/mujweb2, dostaneme se na web2 (apache). Takhle vypadá můj weby.yaml:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: weby spec: rules: - http: paths: - path: /mujweb1 backend: serviceName: web1 servicePort: 80 - path: /mujweb2 backend: serviceName: web2 servicePort: 80
A nahoďme to
kubectl create -f weby.yaml
Čas zkoušení. Nejprve nesmyslná URL (měli bychom dostat výchozí službu) a pak ty dvě naše.
curl 172.17.8.103/nesmysl default backend - 404 curl 172.17.8.103/mujweb1 <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.11.1</center> </body> </html> curl 172.17.8.103/mujweb2 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /mujweb2 was not found on this server.</p> <hr> <address>Apache/2.4.10 (Debian) Server at 172.17.8.103 Port 80</address> </body></html>
Ukažme si ještě jinou variantu. Možná nechcete aplikace odlišovat až uvnitř v URL, ale chcete to vyřešit v rámci doménového jména. V takovém případě vytvořte DNS záznamy pro tato jména vedoucí na naší externí IP adresu – já jsem pro zkoušku modifikovat hosts file takhle:
172.17.8.103 web1.cloudsvet.cz 172.17.8.103 web2.cloudsvet.cz
Vytvořme jiný Ingress – takhle vypadá můj weby-host.yaml:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: weby-host spec: rules: - host: web1.cloudsvet.cz http: paths: - path: / backend: serviceName: web1 servicePort: 80 - host: web2.cloudsvet.cz http: paths: - path: / backend: serviceName: web2 servicePort: 80
Původní tam klidně nechte (mohou fungovat oba) a pošlete tam tento nový. Vyzkoušejte, že skutečně na těchto adresách odpovídá jiná služba:
curl web1.cloudsvet.cz curl web2.cloudsvet.cz
Kromě těchto vlastností už dnes NGINX varianta Ingress umí TLS terminaci.