In Triton-Umgebungen wird ein interner DNS-Service verwendet, der binder heisst. Der Dienst ist relativ wichtig, weil er dazu dient, dass sich die verschiedenen Triton-Komponenten per DNS finden können. Deshalb wird er auch für gewöhnlich ausfallsicher aufgebaut: Drei Instanzen auf drei verschiedenen Compute Nodes mit je einer Zookeeper-Instanz als "Sidecar". Für die Einrichtung gibt es ein simples Kommando: sdcadm post-setup ha-binder <headnode> <CN2> <CN3>
.
Nun war mir schon vor Jahren ein Diskset in einem Compute Node kaputt gegangen - und damit auch die binder-Zone, die auf diesem Compute Node gelaufen war. Alles kein Problem - Triton kann auch mit einem binder-Cluster laufen, in welchem eine Instanz nicht mehr existiert. Es stellte aber eine gewisse Unbequemlichkeit dar, dass insbesondere bei Updates immer Rücksicht auf diese jetzt fehlende binder-Instanz genommen werden mußte. Insofern war ich überrascht und erfreut, dass obige Kommando offenbar zwischenzeitlich neue Parameter bekommen hat:
[root@headnode (de-gt-4) ~]# sdcadm post-setup ha-binder --help
Setup the binder service for high availability (HA).
The binder service provides internal DNS to Triton core services.
It also holds a zookeeper (ZK) cluster used by some Triton core
services. To best support ZK availability we want an odd number of
binder instances. One, three, or five instances are supported.
Usage:
sdcadm post-setup ha-binder SERVER1 SERVER2 ...
Options:
-h, --help Show this help.
--allow-delete Allow replacement/deletion of existing binder
instances.
--dev-allow-repeat-servers For development, allow a binder cluster with
multiple instances on the same server.
-y, --yes Answer yes to all confirmations.
"SERVER ..." should list one, three, or five setup servers (hostname
or UUID) on which a binder instance is desired. Note that this
*includes* existing binder instances, e.g. the "binder0" instance
typically on the initial headnode.
For backward compatibility,
`sdcadm post-setup ha-binder -s SERVER2 -s SERVER3` is accepted
(a) when there is only a single binder on the headnode and
(b) to mean that two binder instances should be added for a total of
three instances. The new calling form is preferred because it is
idempotent.
Examples:
# Ensure a 3-instance binder cluster on the given 3 servers.
sdcadm post-setup ha-binder headnode SERVER2 SERVER3
# Deprecated. Same result as preview example.
sdcadm post-setup ha-binder -s SERVER2 -s SERVER3
At least one of the existing binder instances must remain unchanged
during the process. In case the desired configuration does not
include any of the existing instances, the recommended procedure is
to complete the removal or replacement of all the desired instances
in two steps, achieving the replacement of the instance that must
remain unchanged during the first execution of the command during
the second execution. For example, say we want to "move" our binder
instances from servers "headnode", "SERVER1" and "SERVER2" to the
new servers "SERVER4", "SERVER5" and "new-headnode". We can proceed
as follows:
# Replace all the instances but the first one:
sdcadm post-setup ha-binder headnode SERVER4 SERVER5
# Replace the first one while keeping the new ones:
sdcadm post-setup ha-binder new-headnode SERVER4 SERVER5
Insbesondere das --allow-delete
war genau das, was ich gesucht hatte. Ich habe den alten Compute Node (der inzwischen zwar neue Platten erhalten hatte aber nur noch unzuverlässig startete) durch eine andere Maschine ausgetauscht und bei obigem Kommando als neuen binder-Server angegeben. Der neue Parameter hat dann automatisch die nicht mehr vorhandene Instanz gelöscht.
Offensichtlich kann man dies so lange machen wie man mindestens eine überlebende binder-Instanz zur Verfügung hat. In meinem Fall gab es noch das Problem, dass die "Geisterinstanz" weiterhin mit sdc-role list
angezeigt wurde, was auch weiterhin eine Sonderbehandlung bei Updates erforderlich machte.
Auch dieses Problem liess sich per Anfrage auf der Mailingliste lösen:
I think that's just a stale entry in vmapi.
You can do this:
sdc-vmapi /vms/<uuid>?sync=true
Then it should clear it up, and it shouldn't show up in sdc-role list
anymore. You'll probably want to do that with all instances that were
on the failed CN.
Damit war die vmapi dann auch wieder auf dem letzten Stand. Updates können jetzt wieder ohne besondere Klimmzüge durchgeführt werden.
War aber klar, dass das nochmal hochkommen würde: Nach einem Reboot des Headnodes kamen die wichtigen Dienste leider nicht wieder hoch. Es stellte sich heraus, dass der Zookeeper-Cluster in den binder-Zones sich nicht wieder aufbaute. Mit der obigen Aktion wurde ja eine neue binder-Zone auf einem "neuen" Compute-Node erstellt und in den Cluster eingebunden. Das hatte ich aber nie kontrolliert. De facto wurde einfach nur das Image der binder0-Zone verwendet, um die neue Zone aufzubauen - und damit auch die Konfiguration, die sich in dieser Zone befand. Offenbar gibt/gab es auch keinen Mechanismus, diese Konfiguration anzupassen - denn das war notwendig, da die neue Zone auch eine neue IP-Adresse bekommen hat.
Die Zookeeper-Konfiguration befindet sich in der binder-Zone in /opt/local/etc/zookeeper/zoo.cfg
:
[root@e0b6fef5-9af1-4b60-9cd8-10b2947a2977 (de-gt-4:binder0) /opt/local/etc/zookeeper]# cat zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
dataDir=/zookeeper/zookeeper
# the port at which the clients will connect
clientPort=2181
maxClientCnxns=0
server.1=10.65.72.9:2888:3888
server.3=10.65.72.45:2888:3888
server.4=10.65.72.108:2888:3888
In der zoo.cfg stand noch die alte Adresse der dritten binder-Zone drin. Eintragen der neuen IP-Adresse und Neustart von Zookeeper ( svcadm restart svc:/smartdc/application/zookeeper:default
) hat dann das Cluster wiederhergestellt. Daraufhin konnten auch alle davon abhängenden Dienste wieder starten. Die Logs von Zookeeper sind unter /var/log/zookeeper zu finden. Der Status des Zookeeper-Clusters kann man ermitteln, in dem man herausfindet, welche Rolle die beteiligten Nodes eingenommen haben:
[root@d32b44e1-9a44-4fb6-a344-7facc8fb5910 (de-gt-4:binder3) ~]# echo stat | nc localhost 2181 | grep Mode
Mode: leader
[root@3953bf8f-2d0d-4896-8f4d-62c2c054a731 (de-gt-4:binder1) ~]# echo stat | nc localhost 2181 | grep Mode
Mode: follower
[root@e0b6fef5-9af1-4b60-9cd8-10b2947a2977 (de-gt-4:binder0) ~]# echo stat | nc localhost 2181 | grep Mode
Mode: follower
Alternativ geht auch:
[root@e0b6fef5-9af1-4b60-9cd8-10b2947a2977 (de-gt-4:binder0) ~]# zkServer.sh status
JMX enabled by default
Using config: /opt/local/sbin/../etc/zookeeper/zoo.cfg
Mode: follower
Noch mehr Informationen gibt es mit:
[root@d32b44e1-9a44-4fb6-a344-7facc8fb5910 (de-gt-4:binder3) ~]# echo mntr | nc localhost 2181
zk_version 3.4.3--1, built on 04/18/2012 19:16 GMT
zk_avg_latency 0
zk_max_latency 29
zk_min_latency 0
zk_packets_received 353
zk_packets_sent 352
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 306
zk_watch_count 90
zk_ephemerals_count 28
zk_approximate_data_size 163442
zk_open_file_descriptor_count 21
zk_max_file_descriptor_count 65536
zk_followers 2
zk_synced_followers 2
zk_pending_syncs 0
Die obige Information gibt es auch abgespeckt auf den Followern.
Natürlich reicht es nicht, einfach die IP-Adressen in der zoo.cfg
in den drei binder-Zonen einzutragen. Die IP-Adressen der ZK-Server müssen auch in der SAPI persistiert werden, damit die IP-Adressen das nächste Zonen-Update überstehen. Die IPs sind dabei in den Metadaten der SDC-Applikation gespeichert:
[root@headnode (de-gt-4) /opt/root]# sdc-sapi /applications?name=sdc | json -Ha metadata.ZK_SERVERS
[
{
"host": "10.65.72.9",
"port": 2181,
"num": 1
},
{
"host": "10.65.72.45",
"port": 2181,
"num": 3
},
{
"host": "10.65.72.46",
"port": 2181,
"num": 4,
"last": true
}
]
Um hier die richtige IP einzutragen, muss man zunächst ein korrektes JSON-Dokument erzeugen, welches man dann an sapiadm
übergeben kann. Dazu sieht man sich zunächst die metadata-Struktur in der kompletten Applikationsbeschreibung an und erzeugt dann die folgende Datei als Update:
{ "metadata": {
"ZK_SERVERS": [
{
"host": "10.65.72.9",
"port": 2181,
"num": 1
},
{
"host": "10.65.72.45",
"port": 2181,
"num": 3
},
{
"host": "10.65.72.108",
"port": 2181,
"num": 4,
"last": true
}
]
}
}
Diese wird dann per
[root@headnode (de-gt-4) /opt/root]# sapiadm
Administer SAPI objects
Usage:
sapiadm [OPTIONS] COMMAND [ARGS...]
sapiadm help COMMAND
Options:
-h, --help Print help and exit.
--version Print version and exit.
-v, --verbose More verbose logging.
Commands:
help (?) Help on a specific sub-command.
get Get object details.
showapp Show services and instances inside an application.
update Update a SAPI object.
provision Provision a new instance the given service.
reprovision Reprovision an existing instance with a new image.
edit-manifest Edit a manifest tied to a service or application and save it back.
sapiadm: error: no command given
[root@headnode (de-gt-4) /opt/root]# sapiadm update
Update a SAPI object.
Usage:
sapiadm update UUID metadata.foo=bar
sapiadm update UUID -f /tmp/changes.json
echo '{ "metadata": { "foo": "bar" } }' |
sapiadm update UUID
Options:
-f FILE file containing update JSON.
[root@headnode (de-gt-4) /opt/root]# sapiadm update 8b7af59b-390e-4537-982e-8bc5584533dd -f /opt/root/zk-servers
[root@headnode (de-gt-4) /opt/root]#
eingespielt.