Openshift: Service Discovery

22.06.2016

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.

Zurück zur Übersicht

2 Kommentare zu “Openshift: Service Discovery

  1. 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

  2. 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?

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*