Openshift: Service Discovery
In meinem vorherigen Blogpost https://blog.doubleslash.de/neue-anwendungen-openshift-origin-erstellen/ habe ich eine kleine Beispielanwendung mit zwei Pods (Wildfly/MySQL) erstellt.
Das Wildfly Image unterstützt von Haus aus sogenannte ServiceDiscovery. Aber was ist das und wozu brauche ich das?
ServiceDiscovery beschreib bei Openshift eine Möglichkeit Services automatisch zu finden.
In Openshift werden IP Adressen dynamisch vergeben. Das bedeutet, dass ein Pod, der einmal verfügbar war einen Endpunkt im IP Bereich 10.168.* bekommt. Beim nächsten Start oder bei Skalierung wird ein neuer Endpunkt generiert und dem Container zugewiesen.
Somit kann ein Zusammenspiel von Containern nicht zuverlässig funktionieren. Ausserdem würde das Loadbalancing zum Container keinen Effekt haben, wenn es lediglich möglich ist einen Pod als Ziel zu konfigurieren.
Openshift stellt hier sogenannte Services als Bindeglied zwischen Routing und Container bereit. Ein Service bekommt wie ein Container eine IP. Diese ist jedoch in einem anderen Bereich (per Default 172.30.*). Der Vorteil der Service IP ist, dass diese einmal für die Laufzeit des Services vergeben wird. Über die eine Service IP wird auch das Loadbalanceing zum eigentlichen Pod durchgeführt.
Über nachfolgenden Befehl kann man sehen, dass die Beispielanwendung zwei Services beinhaltet (bitte vorher einen Login machen und in das Projekt „real-life-app“ wechseln). Für das Beispiel habe ich den Wildfly auf zwei Pods skaliert.
[root@master ~]# oc scale --replicas=2 dc real-life-app [root@master ~]# oc describe services Name: mysql Namespace: cbrugger Labels: template=mysql-ephemeral-template Selector: name=mysql Type: ClusterIP IP: 172.30.44.182 Port: mysql 3306/TCP Endpoints: 10.1.2.5:3306 Session Affinity: None No events. Name: real-life-app Namespace: cbrugger Labels: app=real-life-app Selector: deploymentconfig=real-life-app Type: ClusterIP IP: 172.30.155.3 Port: 8080-tcp 8080/TCP Endpoints: 10.1.1.4:8080,10.1.2.6:8080 Session Affinity: None
In der Übersicht sieht man zum einen die zugewiesene IP des Services und die IPs der Endpoints.
Um zu zeigen, wie die mysql Service IP im Wildfly über das Environmen ausgelesen werden kann, logge ich mich auf einen der Pods mit dem Befehl „oc rsh“ ein.
# Pods auslesen [root@master ~]# oc get pod NAME READY STATUS RESTARTS AGE mysql-1-lhufr 1/1 Running 0 20m real-life-app-1-build 0/1 Completed 0 20m real-life-app-1-d82uw 1/1 Running 0 13m real-life-app-1-jwuir 1/1 Running 0 16m # Konsole auf Pod öffnen [root@FDHRHEL7BETA03 ~]# oc rsh real-life-app-1-d82uw # Environment Variablen auslesen sh-4.2$ env | grep MYSQL MYSQL_DATABASE=reallifedb MYSQL_PASSWORD=password MYSQL_PORT_3306_TCP_PORT=3306 MYSQL_PORT_3306_TCP=tcp://172.30.44.182:3306 MYSQL_SERVICE_PORT_MYSQL=3306 MYSQL_PORT_3306_TCP_PROTO=tcp MYSQL_PORT_3306_TCP_ADDR=172.30.44.182 MYSQL_SERVICE_PORT=3306 MYSQL_USER=admin MYSQL_PORT=tcp://172.30.44.182:3306 MYSQL_SERVICE_HOST=172.30.44.182
Alle Variablen, die aus einem Serice kommen haben folgendes Muster <SERVICE_NAME>_.
Der Wildfly geht beim Start her und analysiert die Environment-Variablen. Hier ein Auszug aus der Datei „/wildfly/bin/standalone.conf“ der dafür zuständig ist.
# mysql db container must be linked w/ alias "mysql" export MYSQL_ENABLED="false" if [ -n "$MYSQL_DATABASE" ] then export OPENSHIFT_MYSQL_DB_PORT=$MYSQL_SERVICE_PORT export OPENSHIFT_MYSQL_DB_HOST=$MYSQL_SERVICE_HOST export OPENSHIFT_MYSQL_DB_PASSWORD=$MYSQL_PASSWORD export OPENSHIFT_MYSQL_DB_USERNAME=$MYSQL_USER export OPENSHIFT_MYSQL_DB_URL=mysql://${OPENSHIFT_MYSQL_DB_USERNAME}:${OPENSHIFT_MYSQL_DB_PASSWORD}@${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/ export OPENSHIFT_MYSQL_DB_NAME=$MYSQL_DATABASE if [ -n "$MYSQL_DATASOURCE" ] then export OPENSHIFT_MYSQL_DATASOURCE=$MYSQL_DATASOURCE else export OPENSHIFT_MYSQL_DATASOURCE="MySQLDS" fi if [ ! -n "${OPENSHIFT_DEFAULT_DATASOURCE}" ] then export OPENSHIFT_DEFAULT_DATASOURCE=${OPENSHIFT_MYSQL_DATASOURCE} fi export MYSQL_ENABLED="true" fi
Die Datasource in der Datei /wildfly/standalone/configuration/standalone.xml wird ebenfalls über die Datei „/wildfly/bin/standalone.conf“ vor dem Start manipuliert, in dem mit „sed“ Platzhalter ersetzt werden.
Solange die Service IP verfügbar ist funktioniert das einwandfrei. Beim Wechsel der Service IP (passiert nur durch Neuanlage des Services) müssen lediglich die Wildfly Pods neu gestartet werden. Leider ergibt sich hieraus eine Reihenfolge was die Starts der Services angeht. Der MySQL Service muss vor dem Start der Wildfly Pods verfügbar sein.
Eine weitere Art der Service Discovery bietet Kubernetes im Zusammenspiel mit dem Cluster-Addon DNS. Hier wird zusätzlich ein DNS Server verwendet um Services unter ihrem Namen zu registrieren.
Hallo Ingo,
leider ist es nicht ganz einfach, mit den Verfügbaren Informationen, den Fehler zu finden.
Was mir jedoch auffällt, dass du von drei Routen sprichst. Bei den meisten Datenbanken ist der Zugriff über eine Route nicht möglich, da dies meist nur für http Zugriffe geht. Der Zugriff auf die DB müsste direkt auf den Service eingerichtet werden.
Viele Grüße,
Sebastian
Hallo zusammen,
ich stehe vor dem ähnlichen Dilemma und komme aktuell nicht weiter.
Der Openshift-Cluster von Azure gehostet ist nur bedingt erreichbar.
Die Applikation besteht aus 3 Containern: App, Api und DB.
Alle 3 Container sind durch eine Route erreichbar gemacht worden, ich erreiche also den APP Container beispielsweise über Port 80 und kann so auf die Webanwendung zugreifen.
Wenn ich mich in der Webanwendung jedoch anmelden möchte, funktioniert anscheinend das Zusammenspiel der Container nicht wirklich. Eigentlich müssten alle Container beim Anmeldeprozess einbezogen werden.
Was könnte bzw. worin könnte die Ursache für das Problem liegen? Kann das eventuell ein Netzwerkproblem sein oder sonst was?