Begin juni 2019 werd er een WSO2 webinar gehouden over hoe je de WSO2 API Manager in een Kubernetes omgeving kunt runnen. In een notendop is Kubernetes (k8s) een gecontaineriseerde workload- en servicemanagementtool die automatisch kan schalen, herstellen en daarnaast workloadmanagement, health monitoring en network routing uit kan voeren op een gecontaineriseerde omgeving. Deze functies maken K8s een erg sterke tool om je softwarecomponenten op te hosten. Tot voor kort was er geen ondersteuning voor K8s in WSO2. Eén missende schakel was de ondersteuning voor het clustering mechanisme om de functies van Kubernetes voor de membership change-notifications te kunnen gebruiken.
Nu K8s support ook op het WSO2 platform beschikbaar komt, kunnen de carbon nodes door K8s gebruikt worden om andere leden in de WSO2 cluster te detecteren en de verschillende WSO2 clusteringfuncties te gebruiken. De ondersteuning voor K8s wordt progressief toegevoegd aan de WSO2 Integration stack en dus besloot ik om de WSO2 Enterprise Integrator op Kubernetes eens uit te proberen. In deze blog beschrijf ik de eerste stappen die ik genomen heb om een WSO2 Enterprise Integrator cluster op te zetten en vertel tegen welke problemen ik aangelopen ben en hoe ik ze op heb kunnen lossen.
K8s voor beginners
Ik heb deze blog geschreven voor beginners en geef dus uitleg over iedere stap die ik neem om een K8s cluster te installeren met een WSO2 Enterprise Integrator deployment. De hordes die ik onderweg moest nemen beschrijf ik ook. Ik heb mijn lokale K8s installatie vooraf leeg gegooid, zodat het process begint met een lege K8s cluster.
Houd in de gaten dat je een WSO2 abonnement nodig hebt om de onderstaande stappen te kunnen volgen, omdat de images (aangeboden door WSO2) uit de WSO2 Docker hub komen waar je zonder abonnement niet bij kunt.
WSO2 postte op Github informatie over hoe je met WSO2 EI met kubernetes kunt laten werken. Ik zocht naar eenvoudige set-up om mee te beginnen en besloot dus de ‘scalable-integrator’ Helm chart versie [4] uit te proberen. Het doel is om een cluster van twee EI-instanties op te zetten en te bekijken hoe dat werkt op K8s.
Benodigdheden
Ik voer deze stappen uit op een Docker Desktop met een lokale Kubernetes cluster. Mijn Docker desktop is geconfigureerd met maximaal 6GB geheugen en 2 CPU-kernen. In de meeste gevallen is een two-node cluster voor ieder WSO2 product toereikend en andere containers kunnen eventueel ernaast runnen, mocht dat nodig zijn.
Als eerste heb ik het materiaal dat in de Github repo aangeboden wordt bekeken. In de Helm chart sources viel het me op dat ik een NFS server nodig zou hebben voor het opslaan van de CAR-bestanden en dat daar ook de ‘tenant specific configuration files’ opgeslagen zouden worden.
Ik wilde voor deze test geen NFS opzetten, dus besloot ik om de aangeboden Helm chart te wijzigen door in plaats van de huidige NFS een hostpath persistent volume claim te gebruiken.
Ik veranderde het persistent-volumes.yaml bestand en verving de NFS-configuratie met een hostPath alternatief:
# nfs: # server: {{ .Values.serverIp }} # path: {{ .Values.locationPath }} hostPath: path: “/Users/thijs/workarea/blogs/k8s-ei” |
Daarna ben ik begonnen aan de stappen die nodig zijn om een K8s cluster te maken.
Stap 1: Installatie
Als eerste heb ik Helm geïnstalleerd en Tiller.WSO2 heeft Helm charts die alle configuratie bevat die we nodig hebben voor dit K8s-cluster.
Voor de Helm installatie gebruikte ik de binary resources van [3]. Direct na het installeren van Helm heb ik de installatie van MySQL via Helm geïnitieerd.
# helm install –name wso2ei-scalable-integrator-rdbms-service -f ../mysql/values.yaml stable/ mysql –namespace wso2 |
Hierdoor kreeg ik de foutmelding: ‘Could not find a ready tiller pod’.
De melding lijkt duidelijk aan te geven wat er fout zit, dus bekijken we de pod status:
# kubectl get pods –namespace kube-system |
De uitkomst van de bovenstaande regel was (ingekort):
# >tiller-deploy-74497878f7-ccjll 1/1 Running 0 5m |
Het lijkt erop dat Tiller draait, dus misschien was ik te ongeduldig? Laten we de installatie van MySQL nog een keer proberen.
Geweldig, nu werkt het, wat helm zelf ook aangeeft met ‘STATUS: DEPLOYED’.
Een snelle check met kubectl laat zien dat MySQL daadwerkelijk draait.
# kubectl get pods –namespace wso2 |
# NAME READY STATUS RESTARTS AGE wso2ei-scalable-integrator-rdbms-service-mysql-89b8b4fb4-dnc4d 1/1 Running 0 58s |
Stap 2: Deployment
De volgende stap is de deployment van de enterprise integrator.
helm install –name wso2ei-scalable-integrator ./ –namespace wso2 |
De reactie dat het geslaagd is kwam bijna direct: STATUS: DEPLOYED.
Laten we nu gaan kijken of alles goed staat door de pod status te controleren.
kubectl get pods -n wso2 NAME READY STATUS RESTARTS AGE wso2ei-scalable-integrator-deployment-7dbc5df68b-tfqzm 0/1 ErrImagePull 0 12s wso2ei-scalable-integrator-deployment-7dbc5df68b-vphh4 0/1 ErrImagePull 0 12s wso2ei-scalable-integrator-rdbms-service-mysql-89b8b4fb4-dnc4d 1/1 Running 0 3m |
Hmm, dat ziet er niet goed uit. Kubernetes is niet in staat om de wso2 images correct te importeren… Om te ontdekken wat er fout zit in mijn pod wil ik de pod status zien.
kubectl describe pod wso2ei-scalable-integrator-deployment -n wso2 |
In de laatste paar regels worden de Events getoond en daar zie ik een fout staan met betrekking tot de toegang tot de docker hub instantie van WSO2, ‘Get https://docker.wso2.com/v2/wso2ei-integrator/manifests/6.2.0: unauthorized: authentication required’
Eens kijken of we dat kunnen oplossen…
Stap 3. WSO2-abonnement
Ik sla de documentatie van WSO2 erop na en besef me dat ik de inloggegevens van mijn WSO2-abonnement niet opgegeven heb, dus pas ik ze aan in het daarvoor bestemde config-bestand (values.yaml) en verwijder de integrator instantie en maak deze (opnieuw) aan.
Omdat we Helm gebruiken om dat allemaal te doen, heb ik besloten de Helm release te verwijderen en die opnieuw te maken.
helm ls –all –short |grep wso2 |
Dit leverde me twee dingen op:
wso2ei-scalable-integrator wso2ei-scalable-integrator-rdbms-service |
Ik verwijderde de integrator release en maakte die opnieuw.
helm delete –purge wso2ei-scalable-integrator helm install –name wso2ei-scalable-integrator ./ –namespace wso2 |
Opnieuw controleer ik de pod status met:
kubectl describe pod wso2ei-scalable-integrator-deployment -n wso2 |
en zie nu dat het laatste event is dat de image uit de Docker-repo is geïmporteerd. Dit ziet er veelbelovend uit!
Het controleren van de pod status laat zien dat de container op dat moment gecreëerd is:
kubectl describe pod wso2ei-scalable-integrator-deployment -n wso2 kubectl get pods -n wso2 |
NAME READY STATUS RESTARTS AGE wso2ei-scalable-integrator-deployment-7dbc5df68b-bfc77 0/1 ContainerCreating 0 2m wso2ei-scalable-integrator-deployment-7dbc5df68b-g9cnq 0/1 ContainerCreating 0 2m wso2ei-scalable-integrator-rdbms-service-mysql-89b8b4fb4-dnc4d 1/1 Running 0 24m |
Laten we een poosje wachten om te zien wat er gebeurt.
Het importeren van de image kan namelijk even duren, omdat het met bijna 1.5GB nogal groot is.
Stap 4. Docker check
Omdat ik al een poosje geen veranderingen zie in mijn K8s pod statussen, besluit ik om te Docker te checken of de image er al is.
De controle van de docker image list laat me zien dat er een (nieuwe) image was.
docker image ls |grep wso2 docker.wso2.com/wso2ei-integrator 6.2.0 14cb7eacbb76 18 hours ago |
Na ongeveer 6 minuten start de container eindelijk op.
kubectl get pods -n wso2 |
NAME READY STATUS RESTARTS AGE wso2ei-scalable-integrator-deployment-7dbc5df68b-bfc77 1/1 Running 0 7m wso2ei-scalable-integrator-deployment-7dbc5df68b-g9cnq 1/1 Running 0 7m wso2ei-scalable-integrator-rdbms-service-mysql-89b8b4fb4-dnc4d 1/1 Running 0 28m |
Er zijn nu drie pods die runnen, één MySQL en twee WSO2EI instanties.
Stap 5. Admin-console
Laten we eens kijken of we toegang tot de admin-console van één van deze WSO2 EI instanties kunnen krijgen.
Om te weten te komen hoe we toegang kunnen krijgen tot de instanties, zullen we de ingress netwerkadressen moeten bepalen.
Die kun je laten zien door:
kubectl get ing -n wso2 |
NAME HOSTS ADDRESS PORTS AGE wso2ei-scalable-integrator-gateway-tls-ingress wso2ei-scalable-integrator-gateway 80, 443 8m wso2ei-scalable-integrator-ingress wso2ei-scalable-integrator 80, 443 8m |
Hmm, geen adres? Dus wat kunnen we dan doen? We kunnen geen toegang krijgen tot onze instanties omdat de hosts van de pods niet verbonden zijn aan lokale adressen.
Stap 6. Nginx
Toen realiseerde ik me dat ik de Nginx ingress-controller niet geïnstalleerd had, wat wel aangeraden werd aan in begin van de WSO2-pagina.
Dus zullen we dat nu moeten doen:
helm install stable/nginx-ingress –name nginx-wso2ei –set rbac.create=true |
Stap 7. Ingress adressen
Na het installeren van de Nginx waren er nog steeds geen ingress adressen zichtbaar.
Ik ga eerst het aantal deployments terugschroeven om te zien of een deployment-restart zou kunnen werken.
Ik krijg de naam van de deployment:
kubectl get deployments -n wso2 |
Dit laat wso2ei-scalable-integrator-deployment als naam zien en ik zet het aantal replica’s terug naar 0 om bewust alle replica’s te stoppen.
kubectl scale deployment –replicas=0 wso2ei-scalable-integrator-deployment -n wso2 |
Na het gebruik van het scaling commando zien we dat er echt 0 instanties zijn.
kubectl get deployments -n wso2 |
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE wso2ei-scalable-integrator-deployment 0 0 0 0 22m |
Laten we dit terug opschalen om de containers weer op te starten en dan te kijken of dat effect heeft op de ingress adressen.
kubectl scale deployment –replicas=2 wso2ei-scalable-integrator-deployment -n wso2 kubectl get deployments -n wso2 |
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE wso2ei-scalable-integrator-deployment 2 2 2 0 25m |
Zie je de kolom AVAILABLE? Daar staat nu een 0 en ik had daar een 2 verwacht…
Als ik de statussen van de pods bekijk, zie ik dat er al twee pods waren.
kubectl get pods -n wso2 |
NAME READY STATUS RESTARTS AGE wso2ei-scalable-integrator-deployment-7dbc5df68b-lqklh 0/1 Running 0 47s wso2ei-scalable-integrator-deployment-7dbc5df68b-m69gb 0/1 Running 0 47s |
Ze zijn dus gewoon nog niet klaar, dus laten we controleren of er iets fout is of dat ik gewoon weer te ongeduldig was.
kubectl describe pod wso2ei-scalable-integrator-deployment-7dbc5df68b-lqklh -n wso2 |
De laatste event line geeft aan:
Normal Started 55s kubelet, docker-for-desktop Started container |
Blijkt dat de container gestart is en dat ik dus echt te ongeduldig was.
Na ongeveer 3 minuten laat de deploymentinformatie zien dat alle deployments nu beschikbaar zijn.
wso2ei-scalable-integrator-deployment 2 2 2 2 27m |
Bij het opvragen van de ingress adressen krijg ik nog steeds geen resultaat.
Helaas ben ik hier niks mee opgeschoten. Op één of andere manier krijg ik het niet voor elkaar dat K8s mijn service aan een extern IP-adres blootstelt.
In de K8s documentatie [1] over Ingress types zien we dat er verschillende soorten ingress types bestaan.
Als we naar de Helm charts kijken die WSO2 gecreëerd heeft, dan kunnen we vaststellen dat er hier een name-based virtual hosting type gebruikt is, omdat de integrator-ingress.yml een host value (wso2ei-scalable-integrator) onder ‘rules’ heeft staan.
spec: tls: – hosts: – wso2ei-scalable-integrator rules: – host: wso2ei-scalable-integrator http: paths: – path: / backend: serviceName: wso2ei-scalable-integrator-service servicePort: 9443 |
Dit houdt in dat we deze hostname mee moeten geven bij alle aanvragen die we naar dit ingress eindpunt versturen, omdat de loadbalancer de route zal moeten bepalen.
In deze set-up zijn er twee ingress eindpunten: één voor de administratieve API’s (wso2ei-scalable-integrator) en één voor de services die op de EI instantie deployed worden (wso2ei-scalable-integrator-gateway-service).
Stap 8. Eindpunt instellingen
Als we naar de clusterconfiguratie kijken, kunnen we zien dat er een ‘Loadbalancer listening on localhost’ is.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/nginx-wso2ei-nginx-ingress-controller LoadBalancer 10.106.232.56 localhost 80:30706/TCP,443:30784/TCP 1h |
Met dit eindpunt, samen met de name-based virtual hosting routes, kunnen we misschien toegang krijgen tot de admin console en de services.
Je kunt testen of dit werkt door curl te gebruiken of door de hosts bestanden op je machine aan te passen.
Laten we met curl beginnen:
curl -k https://localhost/carbon -H ‘Host: wso2ei-scalable-integrator’ -v |
En opnieuw slagen we er niet in…
We krijgen een lege HTTP/2 respons.
Dit geeft aan dat we wel bij onze ingress controller komen, maar dat er in die controller iets fout gaat.
Laten we bekijken wat daar mis gaat.
We openen het logbestand met de pod-logs. Daarvoor bepalen we eerst de naam van de pod en openen dan de logs.
kubectl get pods -n wso2 |
NAME READY STATUS RESTARTS AGE nginx-wso2ei-nginx-ingress-controller-6bd6db7876-4m7gd 1/1 Running 0 3m |
Als ik wil analyseren wat er aan de hand is, dan open ik de terminal en log doorlopend de logs van de ingress controller.
kubectl logs -n wso2 nginx-wso2ei-nginx-ingress-controller-6bd6db7876-4m7gd -f |
Als ik nu opnieuw het curl commando gebruik, dan zie ik dat ik een onverwachte respons terugkrijg van de downstream service.
Het bericht van de foutmelding luidt: ‘…upstream sent no valid HTTP/1.0 header while reading response header from upstream…’.
Stap 9. WSO2 EI logs
Het lijkt erop dat de request naar de WSO2EI instantie uitloopt op een fout, waardoor Nginx me deze foutmelding geeft. Laten we de WSO2 EI logs erbij pakken.
Hiervoor heb ik eerst weer de namen van de pods nodig.
kubectl get pods -n wso2 |
pod/wso2ei-scalable-integrator-deployment-7dbc5df68b-p997c 1/1 Running 0 22m pod/wso2ei-scalable-integrator-deployment-7dbc5df68b-szmq2 1/1 Running 0 22m |
Om de logs op fir te open:
kubectl logs -n wso2 wso2ei-scalable-integrator-deployment-7dbc5df68b-p997c -f |
en in een andere terminal de andere nodes logs:
kubectl logs -n wso2 wso2ei-scalable-integrator-deployment-7dbc5df68b-szmq2 -f |
Als ik de curl opnieuw run dan krijg ik…. niks.
Het lijkt erop dat de ingress controller niet in staat is om correct te communiceren met de downstream services.
Stap 10. SSL issues
Onze ingress controller is geconfigureerd voor puur passthrough SSL-verkeer wat de Ingress configuratie (integrator-ingress.yaml) ons precies laat zien.
Zou het kunnen zijn dat er een SSL handshake issue is en zouden we daarom de configuratie van de Nginx aan moeten passen om het SSL-verkeer correct te laten verlopen!?
De documentatie voor ingress-nginx [2] heeft lange keuzelijst met annotaties die de SSL/TLS en HTTPS beïnvloeden.
Toen ik de annotaties doorzocht op onderdelen die met HTTPS-verkeer te maken hebben was er één die me opviel: ‘Backend protocol’.
Deze annotatie is te gebruiken om Nginx te vertellen hoe het met backend communicatie om moet gaan en, zoals daar vermeld wordt, dat Nginx standaard HTTP gebruikt.
Laten we de configuratie van de ingress controller en deze instelling toevoegen om te zien wat er gebeurt.
Omdat ik er zeker van wil zijn dat mijn instellingen veranderen bij het opnieuw opstarten en bij nieuwe deployments, pas ik de helm configuratie aan voor deze wijziging.
In de integrator-gateway-ingress.yaml en integrator-ingress.yaml voeg ik de volgende annotatie toe in het deel met ‘annotations’ van beide config-bestanden:
nginx.ingress.kubernetes.io/backend-protocol: “HTTPS” |
Daarna verwijder ik de helm release en maak die opnieuw aan:
helm delete –purge wso2ei-scalable-integrator helm install –name wso2ei-scalable-integrator . –namespace wso2 |
De K8s cluster informatie laat enkele seconden later zien dat het cluster weer draait.
Ik open de kubectl logs opnieuw voor de Nginx ingress controller en de twee WSO2 EI instanties om te zien wat er gebeurt als ik het nog een keer probeer. Wanneer ik zie dat de instanties volledig opgestart zijn, voer ik opnieuw de curl uit.
curl -k https://localhost/carbon -H ‘Host: wso2ei-scalable-integrator’ -v |
Dit curl commando geeft verschillende regels terug, waaronder:
< HTTP/2 302 |
en:
< location: https://wso2ei-scalable-integrator/carbon/admin/index.jsp |
Stap 11. Gelukt!
Het werkt! Omdat er een directe locatie terugkomt, kan ik afleiden dat we nu met succes contact hebben weten te leggen met een WSO2 EI instantie, omdat de doorverwijzing geïnitieerd is door het WSO2 inlogproces.
Ik test een andere curl om te zien of we ook toegang kunnen krijgen tot de eindpunten van de services. Ik zie:
curl -k https://localhost/services -H ‘Host: wso2ei-scalable-integrator-gateway’ -vvv < HTTP/2 200 < content-type: text/html |
en in de body zien we een HTML pagina die de deployed services laat zien.
Geweldig! Het is ons gelukt om het eindpunt van de admin console en van de services op te vragen.
Het is eenvoudig om dit goed te laten werken in een browser. Voeg daarvoor deze hostname voor het 127.0.0.1 IP-adres toe aan het hosts-bestand. En als je daar toch bent, kun je ook de andere hostname toevoegen die we nodig hebben om bij de services op de WSO2 Enterprise Integrator instantie te kunnen (wso2ei-scalable-integrator-gateway):
127.0.0.1 localhost wso2ei-scalable-integrator wso2ei-scalable-integrator-gateway |
Als je nu je browser opent en deze URL gebruikt: https://wso2ei-scalable-integrator/carbon, krijg je een inlogscherm te zien van de EI instance.
Hiermee heb ik mijn reis om een two-node WSO2 Enterprise Integrator cluster te laten draaien in een Kubernetes cluster tot een goed einde gebracht.
Samenvatting
In deze blog beschrijf ik de stappen die ik genomen heb om in een Kubernetes (K8s) cluster een WSO2 Enterprise Integrator service te installeren. Ik liep tegen verschillende problemen aan in mijn aanpak bij het het instellen van de K8s cluster en beschrijf de manieren en de commando’s die ik gebruikt heb om te achterhalen waar het probleem zit en hoe ik tot oplossingen heb kunnen komen.
Deze set-up is nog verre van productief te noemen, omdat er een flink aantal dingen missen. Ik heb de NFS-persistent volume mapping uitgezet en de image die voor de WSO2 Enterprise Integrator gebruikt wordt volledig op default laten staan zonder persoonlijke aanpassingen voor veiligheid en andere optimalisaties wat betreft prestaties.
Maar het feit dat het me gelukt is laat zien dat de aanpak werkt en de WSO Enterprise Integrator daadwerkelijk op Kubernetes kan draaien.
Links:
[1]: https://kubernetes.io/docs/concepts/services-networking/ingress/#types-of-ingress
[2]: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md
[3]: https://github.com/helm/helm/releases/tag/v2.14.1
Wil je meer leren over hoe je met WSO2 kunt werken? Neem dan deel aan een van onze trainingen!