Microservice-Deployment ganz einfach mit Docker Compose

Keine Kommentare

In dem Artikel “Microservice-Deployment ganz einfach mit Giant Swarm” habe ich die PaaS-Lösung Giant Swarm als Rundum-sorglos-Paket für das Deployment von Microservice-Anwendungen vorgestellt. In einem weiteren Artikel “Microservice-Deployment ganz einfach mit Kubernetes” habe ich vorgestellt, wie man mit Kubernetes einen Cluster aus Docker-Containern aufbauen kann. Heute möchte ich vorstellen, wie man eine Microservice-Anwendung mit Docker-Bordmitteln aufbauen kann, um eine Microservice-Anwendung auf einem Entwicklerrechner oder einer AWS-Instanz zu betreiben, was sehr praktisch ist, wenn man schnell eine Produktpräsentation oder einem Integrationstest durchführen möchte.

Docker baut ein internes Netzwerk für alle Container auf, in dem jeder Container eine eigene IP-Adresse bekommt. Die IP-Adresse kann mit docker inspect angezeigt werden. Um die verschiedenen Container miteinander zu verlinken, wird Port-Mapping eingesetzt. Das Linking-System von Docker ermöglicht es beliebig viele Container miteinander zu verlinken. Wenn Container miteinander verbunden sind, setzt Docker entsprechende Umgebungsvariablen in den Zielcontainern. In diesen sind IP-Adressen und Ports der anderen Containern enthalten. Wie das aussieht, kann man im folgenden Listing sehen:

bz@cc $ docker ps
CONTAINER ID        IMAGE                               COMMAND                CREATED             STATUS              PORTS                                                NAMES
87bb5524067d        zutherb/product-service:latest      "/product-0.6/bin/pr   14 seconds ago      Up 13 seconds       0.0.0.0:18080->18080/tcp                          compose_product_1  
bz@cc $ docker exec 87bb5524067d env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=87bb5524067d
MONGODB_PORT_27017_TCP=tcp://172.17.0.28:27017
MONGODB_PORT_27017_TCP_ADDR=172.17.0.28
MONGODB_PORT_27017_TCP_PORT=27017
MONGODB_PORT_27017_TCP_PROTO=tcp

Das folgende Listing zeigt die Verlinkung von vier Containern:

  • einer mit einem Online-Shop,
  • einer mit einem REST-basierten Warenkorb-Microservice,
  • jeweils einer mit den Datenbanken MongoDB und
  • Redis.

Für den Endbenutzer bedeutet das Verlinken von Containern das Ausführen mehrerer Docker-Kommandos.

bz@cc ~$ docker run -d --name mongodb mongo
705084daa3f852ec796c8d6b13bac882d56d95c261b4a4f8993b43c5fb2f846c
bz@cc ~$ docker run -d --name redis redis
784ebde0e867adb18663e3011b3c1cabe990a0c906396fc306eac669345628cf
bz@cc ~$ docker run -d -P --name cart --link redis:redis zutherb/cart-service
438b2657c7a5c733787fb32b7d28e1a0b84ba9e10d19a8a015c6f24085455011
bz@cc ~$ docker run -d -P -p 8080:8080 --name shop --link cart:cart --link mongodb:mongodb zutherb/monolithic-shop
9926e187faa215ac9044603d51adbd8d679d8076b4a349ebbc9917dade6d560e

Wie man durch das vorherige Listing sieht, sind schon zum Erstellen von einfachen Anwendungen mehrere Kommandos nötig. Das folgende Verteilungsdiagramm lässt erahnen, wie kompliziert das Ganze mit einer wachsenden Zahl von Microservices wird. Es wäre doch schön, wenn man eine Möglichkeit hätte, um solche komplexen Deployment-Szenarien zu beschreiben.

Deployment Diagramm Online Shop Docker

Verteilungsdiagramm eines Online-Shop mit Docker

Abhilfe schafft an dieser Stelle Docker Compose (früher Fig), mit dem sich ganze Microservice-Anwendungen in einer Datei beschreiben und mit einem einzelnen Kommando starten lassen. Hierfür definiert man alle Microservices einer Anwendung in einer docker-compose.yml Datei (früher fig.yml). Im folgenden Listing kann man die Beschreibung einer Online-Shop-Anwendung sehen, die man direkt auf jeden Rechner, auf dem Docker läuft, ausführen kann. Das komplette Beispiel findet sich auch in meinem GitHub-Repository:

mongodb:
  image: mongo
  ports:
     - "27017"
redis:
  image: redis
  ports:
     - "6379"
checkout:
  image: zutherb/monolithic-shop
  ports:
     - "8080"
  links:
     - mongodb
     - cart
product:
  image: zutherb/product-service
  ports:
     - "18080"
  links:
     - mongodb
navigation:
  image: zutherb/navigation-service
  ports:
     - "18090"
  links:
     - mongodb
cart:
  image: zutherb/cart-service
  ports:
     - "18100"
  links:
     - redis
catalog:
  image: zutherb/catalog-frontend
  ports:
     - "80:80"
  links:
     - product
     - navigation
     - cart
     - shop

Letztlich kann man mit dieser docker-compose.yml Datei und dem Kommando docker-compose up die komplette Umgebung starten. Das Konsolen-Programm docker-compose lässt sich sehr einfach mit Brew auf einem Mac installieren und es bietet Kommandos an, mit denen man den kompletten Lifecycle unserer Applikation steuern kann, wie z.B.:

  • Start, Stop und Rebuild eine Services,
  • Anzeigen der Stati der laufenden Services,
  • Anzeigen der Logs der laufenden Services und
  • An/Ausschalten von Services.

Im folgenden Listing sind die Phasen Starten und Stoppen des Online-Shop-Beispiels in der Shell zu sehen:

bz@cc ~$ docker-compose up -d
....
bz@cc ~$ docker ps
CONTAINER ID        IMAGE                               COMMAND                CREATED             STATUS              PORTS                                 NAMES
2730bad656eb        zutherb/catalog-frontend:latest     "dockerize -template   8 seconds ago       Up 7 seconds        443/tcp, 0.0.0.0:80->80/tcp           fig_catalog_1       
3ba6e424506e        zutherb/navigation-service:latest   "/navigation-0.6/bin   10 seconds ago      Up 8 seconds        0.0.0.0:18090->18090/tcp              fig_navigation_1    
db169f173cef        zutherb/monolithic-shop:latest      "/sbin/my_init"        12 seconds ago      Up 10 seconds       0.0.0.0:8080->8080/tcp                fig_shop_1          
4db1ae8b366e        zutherb/cart-service:latest         "/cart-0.6/bin/cart"   13 seconds ago      Up 12 seconds       0.0.0.0:18100->18100/tcp              fig_cart_1          
392fc3da4cfe        zutherb/product-service:latest      "/product-0.6/bin/pr   15 seconds ago      Up 13 seconds       0.0.0.0:18080->18080/tcp              fig_product_1       
fd0ed6323975        redis:latest                        "redis-server /etc/r   16 seconds ago      Up 14 seconds       0.0.0.0:6379->6379/tcp                fig_redis_1         
dbcbc99d4fb6        mongodb:latest                      "mongod"               17 seconds ago      Up 16 seconds       28017/tcp, 0.0.0.0:27017->27017/tcp   fig_mongodb_1       
5efc445dbbbd        dockerui/dockerui:latest            "./dockerui"           19 seconds ago      Up 17 seconds       0.0.0.0:9000->9000/tcp                fig_dockerui_1
bz@cc ~$ docker-compose stop

Betrachten wir einen praktischen Anwendungsfall für Docker Compose. Möchte man beispielsweise einen A/B Test vom Deployment her integrativ testen, ist es nötig zwei unterschiedliche Versionen einer Microservice-Umgebung auszuliefern. Es gibt verschiedene Möglichkeiten für das Deployment von A/B-Tests. Entweder man baut eine neue Version des Microservice und pusht diese entsprechend in eine öffentliche oder private Docker-Registry oder man steuert den Test mit Umgebungsvariablen, die dann bestimmte Feature Toggles in der Applikation umschalten. Die folgenden Listings zeigen, wie diese beiden Alternativen in der docker-compose.yml Datei aussehen würden.

#Alternative Version des Service
catalog:
  image: zutherb/catalog-frontend:latest-b
  ports:
     - "80:80"
  links:
     - product
     - navigation
     - cart
     - checkout
#Umgebungsvariable für die Steuerung von FeatureToggles
catalog:
  image: zutherb/catalog-frontend
  ports:
     - "80:80"
  links:
     - product
     - navigation
     - cart
     - checkout
  environment:
     - CHECKOUT_DESIGN=amelia

Um das Deployment von unterschiedlichen Produkt-Konfigurationen mit Docker Compose zu verdeutlichen, habe ich das folgende Video erstellt, das noch fig als Kommando benutzt. Das fig-Kommando kann man jetzt einfach durch docker-compose ersetzen. Auch die Images wurden im dem Video schon vorher aus der zentralen Docker-Registry heruntergeladen. Deshalb sind die beiden Deployments von Variante A und Variante B recht schnell. Wenn man das Beispiel auf dem eigenen Rechner ausprobiert, müssen die Images noch aus der Docker-Registry heruntergeladen werden, das kann ein paar Minuten dauern. Das Beispiel selbst befindet sich in dem folgenden Github-Repository.

Zusammenfassend kann man sagen, dass Docker Compose das Deployment einer Microservice-Anwendung stark vereinfacht, die aus mehreren auf einem Host zu deployenden Einzelservices besteht. Man erstellt einfach eine docker-compose.yml Datei, in der man die Verbindungen der einzelnen Docker-Containern definiert und kann mit dem Konsolen-Programm docker-compose eine komplette Microservice-Umgebung starten. Noch viel einfacher kann das Deployment von komplexen Microservice-Anwendungen kaum sein.

Bernd Zuther

Kampferprobter Projektveteran, der immer fokussiert auf die Lieferung von funktionierender Software in der vorgegebenen Zeit ist. Zu seinen stärksten Waffen gehören ein sicherer Umgang mit agilen Methoden wie Scrum und sein breit gestreutes IT-Wissen, das er gezielt dazu einsetzt, auch die schwierigsten Problemstellungen pragmatisch und einfach zu lösen.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

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