Blog

Eine hochverfügbare Docker-Container-Plattform mit CoreOS und Consul

Mark van Holsteijn

Mark van Holsteijn

Aktualisiert Oktober 22, 2025
11 Minuten

Docker-Container sind heiß, aber Container an sich sind nicht sehr interessant. Sie brauchen ein Ökosystem, um in der 24x7-Produktion eingesetzt werden zu können. Es reicht nicht aus, wenn Sie Ihre Containernamen an den Betrieb weitergeben.

In diesem Blog-Beitrag zeigen wir Ihnen, wie CoreOS verwendet werden kann, um eine hochverfügbare Docker-Container-Plattform als Service bereitzustellen, mit einem Standardverfahren zur Bereitstellung von Docker-Containern. Consul wird dem Mix hinzugefügt, um einen leichtgewichtigen HTTP-Router für jede Docker-Anwendung zu schaffen, die einen HTTP-Dienst anbietet.

Wir werden auf dem Weg dorthin ein paar Prozesse und Maschinen zerstören, um unseren Standpunkt zu beweisen...

Architektur

Die grundlegende Architektur für unsere Docker Container Platform as a Service besteht aus den folgenden Komponenten

coreos-caas
  • CoreOS-Cluster Der CoreOS-Cluster stellt uns einen Cluster von hochverfügbaren Docker-Hosts zur Verfügung. CoreOS ist ein quelloffenes, leichtgewichtiges Betriebssystem, das auf dem Linux-Kernel basiert und eine Infrastruktur für die geclusterte Bereitstellung von Anwendungen bietet. Der interessante Teil von CoreOS ist, dass Sie keine Anwendungen oder Pakete auf CoreOS selbst installieren können. Jede benutzerdefinierte Anwendung muss gepackt und als Docker-Container bereitgestellt werden. Gleichzeitig bietet CoreOS nur grundlegende Funktionen für die Verwaltung dieser Anwendungen.
  • Etcd etcd ist der verteilte Schlüsselwertspeicher von CoreOS und bietet einen zuverlässigen Mechanismus zur Verteilung von Daten im Cluster.
  • Fleet Fleet ist das clusterweite Init-System von CoreOS, mit dem Sie die Ausführung von Anwendungen innerhalb des Clusters planen können und das das dringend benötigte Nanny-System für Ihre Anwendungen bereitstellt.
  • Konsul Consul von Hashicorp ist ein Tool, das die Erkennung und Konfiguration von Diensten erleichtert. Consul ermöglicht die Erkennung von Diensten über DNS und HTTP und bietet uns die Möglichkeit, auf Änderungen bei der Dienstregistrierung zu reagieren.
  • Registrator Der Registrator von Gliderlabs registriert und deregistriert automatisch jeden Docker-Container als Dienst in Consul. Der Registrator läuft auf jedem Docker-Host.
  • HttpRouter leitet den HTTP-Verkehr dynamisch an jede Anwendung weiter, die HTTP-Dienste anbietet und irgendwo im Cluster läuft. Er lauscht auf Port 80.
  • Load Balancer Ein externer Load Balancer, der den HTTP-Verkehr an einen der CoreOS-Knoten weiterleitet, die auf Port 80 hören.
  • Apps Dies sind die eigentlichen Anwendungen, die HTTP-Dienste für die Erkennung und den Zugriff bewerben können. Diese werden von Ihnen bereitgestellt.

 

Erste Schritte

Um Ihre eigene Container-Plattform als Service zum Laufen zu bringen, haben wir eine Amazon AWS CloudFormation-Datei erstellt, in der die grundlegenden Services installiert sind: Consul, Registrator, HttpRouter und den Load Balancer. In der Infrastruktur erstellen wir zwei Autoscaling-Gruppen: eine für die Consul Server, die auf 3 bis 5 Maschinen beschränkt ist, und eine von den Consul Clients, die im Grunde unbegrenzt ist und von Ihrem Bedarf abhängt. Das Schöne an der Autoscaling-Gruppe ist, dass sie automatisch eine neue Maschine startet, wenn die Anzahl der Maschinen unter die minimale oder gewünschte Anzahl fällt. Dies verleiht der Plattform zusätzliche Robustheit. Der Amazon Elastic Load Balancer gleicht den eingehenden Datenverkehr zu jedem Portrechner in einer der beiden Autoscaling-Gruppen aus. Wir haben ein kleines Skript erstellt, das Ihren CoreOS-Cluster erstellt. Voraussetzung dafür ist, dass Sie MacOS verwenden und installiert haben:

Außerdem geht die CloudFormation-Datei davon aus, dass Sie über eine Route53 HostedZone verfügen, in der wir Einträge für Ihre Domain hinzufügen können. Möglicherweise funktioniert sie auch auf anderen Linux-Plattformen, aber das habe ich nicht getestet.

[bash]
git clone https://github.com/mvanholsteijn/coreos-container-platform-as-a-service
cd coreos-container-platform-as-a-service
./bin/create-stack.sh -d cargonauts.dutchdevops.net
...
{
"StackId": "arn:aws:cloudformation:us-west-2:233211978703:stack/cargonautsdutchdevopsnet/b4c802f0-d1ff-11e4-9c9c-5088484a585d"
}
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
INFO: create in progress. sleeping 15 seconds...
CoreOSServerAutoScale 54.185.55.139 10.230.14.39
CoreOSServerAutoScaleConsulServer 54.185.125.143 10.230.14.83
CoreOSServerAutoScaleConsulServer 54.203.141.124 10.221.12.109
CoreOSServerAutoScaleConsulServer 54.71.7.35 10.237.157.117
[/bash]

Jetzt können Sie sich umsehen. Verwenden Sie eine der externen IP-Adressen, um einen Tunnel für fleetctl einzurichten.

[bash]
export FLEETCTL_TUNNEL=54.203.141.124
[/bash]

fleetctl ist das Kommandozeilenprogramm, mit dem Sie die Einheiten verwalten können, die Sie auf CoreOS einsetzen.

[bash]
fleetctl list-machines
....
MACHINE IP METADATA
1cdadb87... 10.230.14.83 consul_role=server,region=us-west-2
2dde0d31... 10.221.12.109 consul_role=server,region=us-west-2
7f1f2982... 10.230.14.39 consul_role=client,region=us-west-2
f7257c36... 10.237.157.117 consul_role=server,region=us-west-2
[/bash]

werden alle Rechner der Plattform mit ihren privaten IP-Adressen und Rollen aufgelistet. Wie Sie sehen können, haben wir 3 Rechner für die consul Serverrolle und 1 Rechner für die consul Clientrolle markiert. Um alle Docker-Container zu sehen, die auf den einzelnen Rechnern gestartet wurden, können Sie das folgende Skript ausführen:

[bash]
for machine in $(fleetctl list-machines -fields=machine -no-legend -full) ; do
fleetctl ssh $machine docker ps
done
...
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ccd08e8b672f cargonauts/consul-http-router:latest "/consul-template -c 6 minutes ago Up 6 minutes 10.221.12.109:80->80/tcp consul-http-router
c36a901902ca progrium/registrator:latest "/bin/registrator co 7 minutes ago Up 7 minutes registrator
fd69ac671f2a progrium/consul:latest "/bin/start -server 7 minutes ago Up 7 minutes 172.17.42.1:53->53/udp, 10.221.12.109:8300->8300/tcp, 10.221.12.109:8301->8301/tcp, 10.221.12.109:8301->8301/udp, 10.221.12.109:8302->8302/udp, 10.221.12.109:8302->8302/tcp, 10.221.12.109:8400->8400/tcp, 10.221.12.109:8500->8500/tcp consul
....
[/bash]

Um die Consul-Konsole zu inspizieren, müssen Sie zunächst einen Tunnel zu Port 8500 auf einem Serverknoten im Cluster einrichten:

[bash]
ssh-add stacks/cargonautsdutchdevopsnet/cargonauts.pem
ssh -A -L 8500:10.230.14.83:8500 core@54.185.125.143
open xebia.com/blog:8500
[/bash]
Konsolenkonsole

Sie sehen nun, dass zwei Dienste registriert sind: consul und der consul-http-router. Consul registriert sich selbst und der http-Router wurde vom Registrator auf 4 Rechnern erkannt und registriert.

Eine Anwendung bereitstellen

Jetzt können wir eine Anwendung bereitstellen und wir haben eine wunderbare Anwendung dafür: den paas-monitor. Es handelt sich um eine einfache Webanwendung, die kontinuierlich den Status eines Backend-Dienstes abfragt und in einer Tabelle anzeigt, wer antwortet. Um diese Anwendung bereitzustellen, müssen wir eine Fleet-Unit-Datei erstellen, die im Grunde eine systemd-Unit-Datei ist. Sie beschreibt alle Befehle, die zur Verwaltung des Lebenszyklus einer Unit ausgeführt werden müssen. Die paas-monitor Unit-Datei sieht wie folgt aus:

[code]
[Unit]
Description=paas-monitor
[Service]
Restart=always
RestartSec=15
ExecStartPre=-/usr/bin/docker kill paas-monitor-%i
ExecStartPre=-/usr/bin/docker rm paas-monitor-%i
ExecStart=/usr/bin/docker run --rm --name paas-monitor-%i --env SERVICE_NAME=paas-monitor --env SERVICE_TAGS=http -P --dns 172.17.42.1 --dns-search=service.consul mvanholsteijn/paas-monitor
ExecStop=/usr/bin/docker stop paas-monitor-%i
[/code]

Sie besagt, dass diese Einheit immer neu gestartet werden sollte, und zwar in einem Intervall von 15 Sekunden. Bevor er startet, hält er an und entfernt den vorherigen Container (wobei er alle Fehler ignoriert) und wenn er startet, führt er einen Docker-Container aus, der nicht gebunden ist. So kann systemd erkennen, dass der Prozess angehalten wurde. Schließlich gibt es auch einen Befehl zum Anhalten.

Die Datei enthält auch %i: Dies ist eine Vorlagendatei, was bedeutet, dass mehrere Instanzen der Einheit gestartet werden können.

In den Umgebungseinstellungen des Docker-Containers werden Hinweise für den Registrator festgelegt. Die Umgebungsvariable SERVICE_NAME gibt den Namen an, unter dem der Dienst in Consul registriert werden soll, und SERVICE_TAGS gibt an, welche Tags an den Dienst angehängt werden sollen. Mit diesen Tags können Sie die 'http'-Dienste in einer Domäne oder sogar in einem einzelnen Container auswählen. Wenn der Container mehr Ports wie z.B. 8080 und 8081 für http und administrativen Verkehr freigeben soll, können Sie Umgebungsvariablen angeben.

[code]
SERVICE_8080_NAME=paas-monitor
SERVICE_8080_TAGS=http
SERVICE_8081_NAME=paas-monitor=admin
SERVICE_8081_TAGS=admin-http
[/code]

Die Bereitstellung der Datei erfolgt in zwei Schritten: Einreichen der Vorlagendatei und Starten einer Instanz:

[bash]
cd fleet-units/paas-monitor
fleetctl submit paas-monitor@.service
fleetctl start paas-monitor@1
Unit paas-monitor@1.service launched on 1cdadb87.../10.230.14.83
[/bash]

Jetzt meldet die Flotte, dass sie gestartet ist, aber das bedeutet nicht, dass sie läuft. Im Hintergrund muss Docker das Image ziehen, was eine Weile dauert. Sie können den Fortschritt mit fleetctl status überwachen.

[bash]
fleetctl status paas-monitor@1
paas-monitor@1.service - paas-monitor
Loaded: loaded (/run/fleet/units/paas-monitor@1.service; linked-runtime; vendor preset: disabled)
Active: active (running) since Tue 2015-03-24 09:01:10 UTC; 2min 48s ago
Process: 3537 ExecStartPre=/usr/bin/docker rm paas-monitor-%i (code=exited, status=1/FAILURE)
Process: 3529 ExecStartPre=/usr/bin/docker kill paas-monitor-%i (code=exited, status=1/FAILURE)
Main PID: 3550 (docker)
CGroup: /system.slice/system-paasx2dmonitor.slice/paas-monitor@1.service
└─3550 /usr/bin/docker run --rm --name paas-monitor-1 --env SERVICE_NAME=paas-monitor --env SERVICE_TAGS=http -P --dns 172.17.42.1 --dns-search=service.consul mvanholsteijn/paas-monitor
Mar 24 09:02:41 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: 85071eb722b3: Pulling fs layer
Mar 24 09:02:43 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: 85071eb722b3: Download complete
Mar 24 09:02:43 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: 53a248434a87: Pulling metadata
Mar 24 09:02:44 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: 53a248434a87: Pulling fs layer
Mar 24 09:02:46 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: 53a248434a87: Download complete
Mar 24 09:02:46 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: b0c42e8f4ac9: Pulling metadata
Mar 24 09:02:47 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: b0c42e8f4ac9: Pulling fs layer
Mar 24 09:02:49 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: b0c42e8f4ac9: Download complete
Mar 24 09:02:49 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: b0c42e8f4ac9: Download complete
Mar 24 09:02:49 ip-10-230-14-83.us-west-2.compute.internal docker[3550]: Status: Downloaded newer image for mvanholsteijn/paas-monitor:latest
[/bash]

Sobald es läuft, können Sie zu paas-monitor.cargonauts.dutchdevops.net navigieren und auf Start klicken.

Sie können jetzt neue Instanzen hinzufügen und beobachten, wie sie im paas-Monitor erscheinen! Es dauert zwar eine Weile, weil die Docker-Images erst aus der Registry gezogen werden müssen, bevor sie gestartet werden können, aber am Ende werden sie alle erscheinen!

[bash]
fleetctl start paas-monitor@{2..10}
Unit paas-monitor@2.service launched on 2dde0d31.../10.221.12.109
Unit paas-monitor@4.service launched on f7257c36.../10.237.157.117
Unit paas-monitor@3.service launched on 7f1f2982.../10.230.14.39
Unit paas-monitor@6.service launched on 2dde0d31.../10.221.12.109
Unit paas-monitor@5.service launched on 1cdadb87.../10.230.14.83
Unit paas-monitor@8.service launched on f7257c36.../10.237.157.117
Unit paas-monitor@9.service launched on 1cdadb87.../10.230.14.83
Unit paas-monitor@7.service launched on 7f1f2982.../10.230.14.39
Unit paas-monitor@10.service launched on 2dde0d31.../10.221.12.109
[/bash]

um alle eingesetzten Einheiten zu sehen, verwenden Sie den Befehl list-units

[bash]
fleetctl list-units
...
UNIT MACHINE ACTIVE SUB
paas-monitor@1.service 94d16ece.../10.90.9.78 active running
paas-monitor@2.service f7257c36.../10.237.157.117 active running
paas-monitor@3.service 7f1f2982.../10.230.14.39 active running
paas-monitor@4.service 94d16ece.../10.90.9.78 active running
paas-monitor@5.service f7257c36.../10.237.157.117 active running
paas-monitor@6.service 7f1f2982.../10.230.14.39 active running
paas-monitor@7.service 7f1f2982.../10.230.14.39 active running
paas-monitor@8.service 94d16ece.../10.90.9.78 active running
paas-monitor@9.service f7257c36.../10.237.157.117 active running
[/bash]

Wie funktioniert das?

Bei jeder Änderung der consul Service-Registrierung wird der consul-http-router benachrichtigt, wählt alle http-getaggten Dienste aus und generiert eine neue nginx.conf. Nachdem die Konfiguration generiert wurde, wird sie von nginx neu geladen, so dass es kaum Auswirkungen auf den aktuellen Datenverkehr gibt.Der consul-http-router verwendet die Go-Vorlagensprache, um die Konfiguration zu regenerieren. Sie sieht wie folgt aus:

[code]
events {
worker_connections 1024;
}
http {
{{range $index, $service := services}}{{range $tag, $services := service $service.Name | byTag}}{{if eq "http" $tag}}
upstream {{$service.Name}} {
least_conn;
{{range $services}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{end}}
}
{{end}}{{end}}{{end}}
{{range $index, $service := services}}{{range $tag, $services := service $service.Name | byTag}}{{if eq "http" $tag}}
server {
listen 80;
server_name {{$service.Name}}.*;
location / {
proxy_pass https:// {{$service.Name}};
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
{{end}}{{end}}{{end}}
server {
listen 80 default_server;
location / {
root /www;
index index.html index.htm Default.htm;
}
}
}
[/code]

Es durchläuft alle Dienste in einer Schleife und wählt alle Dienste mit der Kennzeichnung 'http' aus und erstellt einen virtuellen Host für servicename.*, der alle Anfragen an die registrierten Upstream-Dienste sendet. Mit den folgenden beiden Befehlen können Sie die aktuelle Konfigurationsdatei einsehen.

[bash]
AMACHINE=$(fleetctl list-machines -fields=machine -no-legend -full | head -1)
fleetctl ssh $AMACHINE docker exec consul-http-router cat /etc/nginx/nginx.conf
...
events {
worker_connections 1024;
}
http {
upstream paas-monitor {
least_conn;
server 10.221.12.109:49154 max_fails=3 fail_timeout=60 weight=1;
server 10.221.12.109:49153 max_fails=3 fail_timeout=60 weight=1;
server 10.221.12.109:49155 max_fails=3 fail_timeout=60 weight=1;
server 10.230.14.39:49153 max_fails=3 fail_timeout=60 weight=1;
server 10.230.14.39:49154 max_fails=3 fail_timeout=60 weight=1;
server 10.230.14.83:49153 max_fails=3 fail_timeout=60 weight=1;
server 10.230.14.83:49154 max_fails=3 fail_timeout=60 weight=1;
server 10.230.14.83:49155 max_fails=3 fail_timeout=60 weight=1;
server 10.237.157.117:49153 max_fails=3 fail_timeout=60 weight=1;
server 10.237.157.117:49154 max_fails=3 fail_timeout=60 weight=1;
}
server {
listen 80;
server_name paas-monitor.*;
location / {
proxy_pass https:// paas-monitor;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80 default_server;
location / {
root /www;
index index.html index.htm Default.htm;
}
}
}
[/code]

Dies geschieht auch, wenn Sie eine Instanz anhalten oder beenden. Stoppen Sie einfach eine Instanz und beobachten Sie, wie Ihr Monitor reagiert.

[bash]
fleetctl destroy paas-monitor@10
...
Destroyed paas-monitor@10.service
[/bash]

Töten einer Maschine

Seien Sie jetzt ganz mutig und halten Sie die gesamte Maschine an!

[bash]
ssh core@$FLEETCTL_TUNNEL sudo shutdown -h now.
...
Connection to 54.203.141.124 closed by remote host.
[/bash]

Beobachten Sie weiterhin Ihren paas-Monitor. Sie werden eine Verlangsamung feststellen und auch bemerken, dass einige Backend-Dienste nicht mehr reagieren. Nach einer kurzen Weile (1 oder 2 Minuten) werden Sie neue Instanzen in der Liste sehen.

paas-monitor nach Neustart

Was passiert ist, ist, dass Amazon AWS eine neue Instanz in den Cluster neu gestartet hat und alle Einheiten, die auf dem gestoppten Knoten liefen, auf laufende Instanzen verschoben wurden - mit nur 6 HTTP-Fehlern! Bitte beachten Sie, dass CoreOS nicht in der Lage ist, den Ausfall einer Mehrheit der Server gleichzeitig automatisch wiederherzustellen. In diesem Fall ist eine manuelle Wiederherstellung durch Operationen erforderlich.

Fazit

CoreOS bietet alle grundlegenden Funktionen zur Verwaltung von Docker-Containern und zur Bereitstellung von Hochverfügbarkeit für Ihre Anwendung mit einem Minimum an Aufwand. Consul und Consul-Vorlagen machen es sehr einfach, benutzerdefinierte Komponenten wie NGiNX zur Implementierung einer dynamischen Service-Erkennung zu verwenden.

Ausblick

Im nächsten Blog werden wir eine mehrschichtige Anwendung implementieren, die Consul DNS verwendet, um Anwendungsteile mit Datenbanken zu verbinden!

Referenzen

Dieser Blog basiert auf Informationen, Ideen und Quellcode-Schnipseln der Cloud-Anbieter ec2, mitchellh auto dc und How To Stand Up A 10-Node CoreOS Cluster With Consul+Registrator In AWS Using Terraform

Verfasst von

Mark van Holsteijn

Mark van Holsteijn is a senior software systems architect at Xebia Cloud-native solutions. He is passionate about removing waste in the software delivery process and keeping things clear and simple.

Contact

Let’s discuss how we can support your journey.