Im ersten Teil landeten wir bei einem funktionierenden cmon HA-Cluster:
[email protected]:~# s9s controller --list --long
S VERSION OWNER GROUP NAME IP PORT COMMENT
l 1.7.4.3565 system admins 10.0.0.101 10.0.0.101 9501 Acting as leader.
f 1.7.4.3565 system admins 10.0.0.102 10.0.0.102 9501 Accepting heartbeats.
f 1.7.4.3565 system admins 10.0.0.103 10.0.0.103 9501 Accepting heartbeats.
Total: 3 controller(s)
Wir haben drei Nodes in Betrieb, einer fungiert als Leader und die restlichen sind Follower, die zugänglich sind (sie empfangen Heartbeats und antworten darauf). Die verbleibende Herausforderung besteht darin, den UI-Zugriff so zu konfigurieren, dass wir immer auf die UI auf dem Leader-Knoten zugreifen können. In diesem Blogbeitrag stellen wir Ihnen eine der möglichen Lösungen vor, mit der Sie genau das erreichen können.
HAProxy einrichten
Dieses Problem ist uns nicht neu. Bei jedem Replikationscluster, MySQL oder PostgreSQL, spielt es keine Rolle, es gibt einen einzelnen Knoten, an den wir unsere Schreibvorgänge senden sollten. Eine Möglichkeit, dies zu erreichen, wäre die Verwendung von HAProxy und das Hinzufügen einiger externer Prüfungen, die den Status des Knotens testen und darauf basierend die richtigen Werte zurückgeben. Dies ist im Grunde das, was wir verwenden werden, um unser Problem zu lösen. Wir werden HAProxy als gut getesteten Layer-4-Proxy verwenden und ihn mit Layer-7-HTTP-Prüfungen kombinieren, die wir genau für unseren Anwendungsfall schreiben werden. Das Wichtigste zuerst, lassen Sie uns HAProxy installieren. Wir werden es mit ClusterControl verbinden, aber es kann auch auf einem separaten Knoten installiert werden (idealerweise Knoten - um HAProxy als Single Point of Failure zu entfernen).
apt install haproxy
Damit wird HAProxy eingerichtet. Sobald dies erledigt ist, müssen wir unsere Konfiguration vorstellen:
global
pidfile /var/run/haproxy.pid
daemon
user haproxy
group haproxy
stats socket /var/run/haproxy.socket user haproxy group haproxy mode 600 level admin
node haproxy_10.0.0.101
description haproxy server
#* Performance Tuning
maxconn 8192
spread-checks 3
quiet
defaults
#log global
mode tcp
option dontlognull
option tcp-smart-accept
option tcp-smart-connect
#option dontlog-normal
retries 3
option redispatch
maxconn 8192
timeout check 10s
timeout queue 3500ms
timeout connect 3500ms
timeout client 10800s
timeout server 10800s
userlist STATSUSERS
group admin users admin
user admin insecure-password admin
user stats insecure-password admin
listen admin_page
bind *:9600
mode http
stats enable
stats refresh 60s
stats uri /
acl AuthOkay_ReadOnly http_auth(STATSUSERS)
acl AuthOkay_Admin http_auth_group(STATSUSERS) admin
stats http-request auth realm admin_page unless AuthOkay_ReadOnly
#stats admin if AuthOkay_Admin
listen haproxy_10.0.0.101_81
bind *:81
mode tcp
tcp-check connect port 80
timeout client 10800s
timeout server 10800s
balance leastconn
option httpchk
# option allbackups
default-server port 9201 inter 20s downinter 30s rise 2 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
server 10.0.0.101 10.0.0.101:443 check
server 10.0.0.102 10.0.0.102:443 check
server 10.0.0.103 10.0.0.103:443 check
Vielleicht möchten Sie einige der Dinge hier ändern, wie die Knoten- oder Backend-Namen, die hier die IP unseres Knotens enthalten. Sie werden auf jeden Fall die Server ändern wollen, die Sie in Ihren HAProxy aufgenommen haben.
Die wichtigsten Bits sind:
bind *:81
HAProxy lauscht auf Port 81.
option httpchk
Wir haben die Layer-7-Prüfung auf den Backend-Knoten aktiviert.
default-server port 9201 inter 20s downinter 30s rise 2 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
Die Schicht-7-Prüfung wird auf Port 9201 ausgeführt.
Sobald dies erledigt ist, starten Sie HAProxy.
xinetd einrichten und Skript prüfen
Wir werden xinetd verwenden, um die Prüfung durchzuführen und korrekte Antworten an HAProxy zurückzugeben. Die in diesem Abschnitt beschriebenen Schritte sollten auf allen cmon HA-Clusterknoten ausgeführt werden.
Installieren Sie zuerst xinetd:
[email protected]:~# apt install xinetd
Sobald dies erledigt ist, müssen wir die folgende Zeile hinzufügen:
cmonhachk 9201/tcp
nach /etc/services - dies ermöglicht xinetd, einen Dienst zu öffnen, der auf Port 9201 lauscht. Dann müssen wir die Dienstdatei selbst hinzufügen. Es sollte sich in /etc/xinetd.d/cmonhachk:
befinden# default: on
# description: cmonhachk
service cmonhachk
{
flags = REUSE
socket_type = stream
port = 9201
wait = no
user = root
server = /usr/local/sbin/cmonhachk.py
log_on_failure += USERID
disable = no
#only_from = 0.0.0.0/0
only_from = 0.0.0.0/0
per_source = UNLIMITED
}
Zu guter Letzt brauchen wir noch das Check-Skript, das vom xinetd aufgerufen wird. Wie in der Dienstdatei definiert, befindet es sich in /usr/local/sbin/cmonhachk.py.
#!/usr/bin/python3.5
import subprocess
import re
import sys
from pathlib import Path
import os
def ret_leader():
leader_str = """HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 48\r\n
\r\n
<html><body>This node is a leader.</body></html>\r\n
\r\n"""
print(leader_str)
def ret_follower():
follower_str = """
HTTP/1.1 503 Service Unavailable\r\n
Content-Type: text/html\r\n
Content-Length: 50\r\n
\r\n
<html><body>This node is a follower.</body></html>\r\n
\r\n"""
print(follower_str)
def ret_unknown():
unknown_str = """
HTTP/1.1 503 Service Unavailable\r\n
Content-Type: text/html\r\n
Content-Length: 59\r\n
\r\n
<html><body>This node is in an unknown state.</body></html>\r\n
\r\n"""
print(unknown_str)
lockfile = "/tmp/cmonhachk_lockfile"
if os.path.exists(lockfile):
print("Lock file {} exists, exiting...".format(lockfile))
sys.exit(1)
Path(lockfile).touch()
try:
with open("/etc/default/cmon", 'r') as f:
lines = f.readlines()
pattern1 = "RPC_BIND_ADDRESSES"
pattern2 = "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
m1 = re.compile(pattern1)
m2 = re.compile(pattern2)
for line in lines:
res1 = m1.match(line)
if res1 is not None:
res2 = m2.findall(line)
i = 0
for r in res2:
if r != "127.0.0.1" and i == 0:
i += 1
hostname = r
command = "s9s controller --list --long | grep {}".format(hostname)
output = subprocess.check_output(command.split())
state = output.splitlines()[1].decode('UTF-8')[0]
if state == "l":
ret_leader()
if state == "f":
ret_follower()
else:
ret_unknown()
finally:
os.remove(lockfile)
Sobald Sie die Datei erstellt haben, vergewissern Sie sich, dass sie ausführbar ist:
chmod u+x /usr/local/sbin/cmonhachk.py
Die Idee hinter diesem Skript ist, dass es den Status der Knoten mit dem Befehl „s9s controller --list --long“ testet und dann die Ausgabe überprüft, die für die IP relevant ist, die es auf der finden kann lokaler Knoten. Dadurch kann das Skript feststellen, ob der Host, auf dem es ausgeführt wird, ein Leader ist oder nicht. Wenn der Knoten der Leader ist, gibt das Skript den Code „HTTP/1.1 200 OK“ zurück, den HAProxy als verfügbaren Knoten interpretiert und den Datenverkehr an ihn weiterleitet. Andernfalls gibt es „HTTP/1.1 503 Service Unavailable“ zurück, was so behandelt wird ein Knoten, der nicht fehlerfrei ist und der Datenverkehr nicht dorthin geleitet wird. Unabhängig davon, welcher Knoten zum Leader wird, erkennt HAProxy ihn und markiert ihn im Backend als verfügbar:
Möglicherweise müssen Sie HAProxy und xinetd neu starten, um die Konfigurationsänderungen vor allen Änderungen zu übernehmen Teile werden richtig funktionieren.
Das Vorhandensein von mehr als einem HAProxy stellt sicher, dass wir eine Möglichkeit haben, auf die ClusterControl-Benutzeroberfläche zuzugreifen, selbst wenn einer der HAProxy-Knoten ausfallen würde, aber wir haben immer noch zwei (oder mehr) verschiedene Hostnamen oder IPs, um eine Verbindung zur ClusterControl-Benutzeroberfläche herzustellen. Um es bequemer zu machen, werden wir Keepalived zusätzlich zu HAProxy einsetzen. Es überwacht den Zustand der HAProxy-Dienste und weist einem von ihnen eine virtuelle IP zu. Wenn dieser HAProxy nicht mehr verfügbar ist, wird VIP auf einen anderen verfügbaren HAProxy verschoben. Als Ergebnis haben wir einen einzigen Einstiegspunkt (VIP oder ein damit verbundener Hostname). Die Schritte, die wir hier unternehmen, müssen auf allen Knoten ausgeführt werden, auf denen HAProxy installiert wurde.
Lass uns zuerst Keepalived installieren:
apt install keepalived
Dann müssen wir es konfigurieren. Wir verwenden folgende Konfigurationsdatei:
vrrp_script chk_haproxy {
script "killall -0 haproxy" # verify the pid existance
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_HAPROXY {
interface eth1 # interface to monitor
state MASTER
virtual_router_id 51 # Assign one ID for this route
priority 102
unicast_src_ip 10.0.0.101
unicast_peer {
10.0.0.102
10.0.0.103
}
virtual_ipaddress {
10.0.0.130 # the virtual IP
}
track_script {
chk_haproxy
}
# notify /usr/local/bin/notify_keepalived.sh
}
Sie sollten diese Datei auf verschiedenen Knoten ändern. IP-Adressen müssen richtig konfiguriert werden und die Priorität sollte auf allen Knoten unterschiedlich sein. Bitte konfigurieren Sie VIP auch so, wie es in Ihrem Netzwerk sinnvoll ist. Möglicherweise möchten Sie auch die Schnittstelle ändern - wir haben eth1 verwendet, wo die IP auf von Vagrant erstellten virtuellen Maschinen zugewiesen wird.
Starten Sie Keepalived mit dieser Konfigurationsdatei und Sie sollten loslegen können. Solange VIP auf einem HAProxy-Knoten aktiv ist, sollten Sie ihn verwenden können, um sich mit der richtigen ClusterControl-Benutzeroberfläche zu verbinden:
Damit ist unsere zweiteilige Einführung in ClusterControl hochverfügbare Cluster abgeschlossen. Wie eingangs erwähnt, befindet sich dies noch im Beta-Stadium, aber wir freuen uns auf Feedback von Ihren Tests.