Vous pouvez facilement le créer en lisant le Guide du développeur de l'agent de ressources OCF, mais comme la quantité de texte est importante, "quelque chose qui fonctionne pour le moment" Pour les personnes qui veulent réussir.
OCF est une abréviation pour OpenCluster Framework, qui définit l'interface pour les applications de clustering. Les gestionnaires de cluster tels que Pacemaker, qui gère les clusters, gèrent les applications gérées et les adresses IP virtuelles en tant que «ressources». Pacemaker commande aux ressources de démarrer, d'arrêter, de migrer, de promouvoir en maître, de rétrograder en esclave, etc. Vous pouvez mettre en cluster vos propres applications à l'aide de Pacemaker en créant un programme compatible OCF avec un logiciel de gestion de cluster tel que Pacemaker et l'interface entre les ressources. Le but de cette fois est de créer moi-même cet agent de ressources.
Plus précisément, le logiciel de gestion de cluster compatible OCF lance l'agent de ressources en mettant une action à entreprendre dans la variable d'environnement $ __ OCF_ACTION
.
Les actions incluent le démarrage / l'arrêt / la migration / la promotion vers le maître / la rétrogradation vers l'esclave, et certaines actions nécessitent une définition et d'autres pas (facultatif).
Les fichiers d'exécution sont lancés lors du contrôle des ressources. Ce fichier exécutable est appelé un agent de ressources et gère en fait le fonctionnement des ressources.
L'agent de ressources examine la variable d'environnement $ __ OCF_ACTION
et agit pour effectuer réellement cette action.
Si des paramètres sont requis pour chaque action, ils sont passés dans une variable d'environnement préfixée par $ OCF_RESKEY
.
Tant que le format du fichier d'exécution répond aux exigences de l'API d'OCF, il n'y a aucune restriction sur le langage, etc., mais il semble qu'il soit généralement implémenté par un script shell.
sample-resource
#!/bin/sh
#Initialize
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
RUNNING_FILE=/tmp/.running
sample_meta_data() {
cat << EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="sample-resource" version="0.1">
<version>0.1</version>
<longdesc lang="en">sample resource</longdesc>
<shortdesc lang="en">sample resource</shortdesc>
<parameters>
</parameters>
<actions>
<action name="meta-data" timeout="5" />
<action name="start" timeout="5" />
<action name="stop" timeout="5" />
<action name="monitor" timeout="5" />
<action name="validate-all" timeout="5" />
</actions>
</resource-agent>
EOF
return $OCF_SUCCESS
}
sample_validate(){
return $OCF_SUCCESS
}
sample_start(){
touch ${RUNNING_FILE}
return $OCF_SUCCESS
}
sample_stop(){
rm -f ${RUNNING_FILE}
return $OCF_SUCCESS
}
sample_monitor(){
if [ -f ${RUNNING_FILE} ];
then
return $OCF_SUCCESS
fi
return $OCF_NOT_RUNNING
}
sample_usage(){
echo "Test Resource."
return $OCF_SUCCESS
}
# Translate each action into the appropriate function call
case $__OCF_ACTION in
meta-data) sample_meta_data
exit $OCF_SUCCESS
;;
start) sample_start;;
stop) sample_stop;;
monitor) sample_monitor;;
validate-all) sample_validate;;
*) sample_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
C'est une magie qui est également décrite dans le Guide du développeur de l'agent de ressources OCF.
#Initialize
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
Voici les actions qui doivent être mises en œuvre. En dehors de cela, il est traité comme une option, définissons donc les actions suivantes pour le moment.
Des valeurs de retour appropriées doivent être renvoyées lorsque chaque action est effectuée. La valeur de retour est définie dans OCF.
Décrit les variables d'environnement à utiliser avant d'entrer dans la définition concrète de chaque action requise.
Contient le traitement demandé à l'agent de ressources et est défini lorsque l'agent de ressources est appelé. L'agent de ressources lit d'abord cette variable d'environnement et distribue chaque action.
Exemple d'implémentation Guide du développeur de l'agent de ressources OCF
case $__OCF_ACTION in
meta-data) sample_meta_data
exit $OCF_SUCCESS
;;
start) sample_start;;
stop) sample_stop;;
monitor) sample_monitor;;
validate-all) sample_validate;;
*) sample_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
Une variable qui contient les paramètres définis lors de la création de la ressource. Il n'est pas utilisé dans cet exemple, mais il est utilisé lors de la mise en cluster du démon de serveur TCP décrit plus loin.
meta-data Les métadonnées fournissent des informations de base sur l'agent de ressources, telles que le nom de l'agent de ressources, les actions qu'il fournit et les paramètres qu'il peut recevoir. Écrit en XML, l'agent de ressources renvoie les métadonnées dans la sortie standard sur demande.
start
Implémentez le processus de démarrage des ressources. Plus précisément, écrivez le script de démarrage du démon.
Cette fois, le démon réel ne sera pas démarré et seul un certain fichier sera créé.
Si le démarrage réussit, il renvoie $ OCF_SUCCESS
.
stop Mettre en œuvre l'arrêt des ressources. Décrit l'arrêt du démon. Cette fois, nous supprimerons le fichier créé par start.
S'il n'y a pas de problème avec l'arrêt du traitement, $ OCF_SUCCESS
est renvoyé. (Notez que ce n'est pas $ OCF_NOT_RUNNING
)
Notez que l'action d'arrêt signifie "arrêt forcé" de la ressource. Même si la ressource ne peut pas être arrêtée en toute sécurité, c'est une action pour l'arrêter quand même. Si l'action d'arrêt échoue, elle peut entraîner des problèmes fatals et le gestionnaire de cluster peut effectuer une séparation des nœuds (isolation, telle qu'un arrêt forcé). L'action d'arrêt doit utiliser tous les moyens possibles pour arrêter une ressource et ne renvoyer un code d'erreur que si l'arrêt échoue toujours.
monitor
Implémentez le processus pour obtenir l'état de la ressource.
S'il est en cours d'exécution, il renvoie $ OCF_SUCCESS
, et s'il n'est pas en cours d'exécution, il renvoie $ OCF_NOT_RUNNING
.
S'il y a une erreur, la constante d'erreur appropriée commençant par $ OCF_ERR_
est renvoyée en fonction du contenu de l'erreur.
validate-all Validez les paramètres des ressources. Vérifiez que les paramètres sont correctement définis, que les autorisations des fichiers utilisés par la ressource sont appropriées, etc. La valeur de retour doit être l'une des suivantes:
Valeur de retour | sens |
---|---|
$OCF_SUCCESS | aucun problème |
$OCF_ERR_CONFIGURED | Il y a un problème avec les paramètres |
$OCF_ERR_INSTALLED | Les composants requis n'existent pas (par exemple, le démon à démarrer n'est pas installé) |
$OCF_ERR_PERM | Il y a un problème avec les autorisations d'accès aux fichiers requis pour la gestion des ressources |
(Cette fois c'est facile, donc il renvoie toujours $ OCF_SUCCESS
.)
Vous pouvez tester avec ocf-tester.
#ocf-tester -n [Nom de la ressource] [Chemin de l'agence de ressources]
salacia@ha1:~/ocf-scr$ sudo ocf-tester -n sample-resource ./sample-resource
Beginning tests for ./sample-resource...
* Your agent does not support the notify action (optional)
* Your agent does not support the demote action (optional)
* Your agent does not support the promote action (optional)
* Your agent does not support master/slave (optional)
* Your agent does not support the reload action (optional)
./sample-resource passed all tests
L'emplacement de l'agent de ressources de Pacemaker est sous / usr / lib / ocf / resource.d /
.
Créez ici un répertoire avec le nom du fournisseur et placez-y l'agent de ressources créé.
Puisque mon pseudo est Kamaboko, le nom du fournisseur est kamaboko et l'exemple de ressource ci-dessus est placé. (Les agents de ressources doivent être placés sur tous les nœuds du cluster)
salacia@ha1:~/ocf-scr$ ls -al /usr/lib/ocf/resource.d/kamaboko/
total 16
drwxrwxr-x 2 root root 4096 Aug 11 14:07 .
drwxr-xr-x 6 root root 4096 Jun 21 03:36 ..
-rwxr-xr-x 1 root root 1547 Aug 11 14:07 sample-resource
-rwxrwxr-x 1 root root 2103 Jun 21 03:36 sample-tcp-server
Maintenant que l'agent de ressources est disponible depuis Pacemaker, créons une ressource à partir de la commande pcs.
salacia@ha1:~/ocf-scr$ sudo pcs resource create SAMPLE ocf:kamaboko:sample-resource
salacia@ha1:~$ sudo pcs status
Cluster name: c1
Stack: corosync
Current DC: ha2 (version 1.1.18-2b07d5c5a9) - partition with quorum
Last updated: Tue Aug 11 14:15:47 2020
Last change: Tue Aug 11 14:15:45 2020 by root via cibadmin on ha1
2 nodes configured
1 resource configured
Online: [ ha1 ha2 ]
Full list of resources:
SAMPLE (ocf::kamaboko:sample-resource): Started ha1
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
J'ai pu exécuter mon propre agent de ressources sur Pacemaker.
Voici l exemple de code. OCF Resource Agent Samle
Pour le moment, seul le paquet .deb est pris en charge, donc je pense qu'il peut fonctionner sur Debian, Ubuntu, etc. (L'environnement de développement est Ubuntu 18.04) Un stimulateur cardiaque est une condition préalable à l'installation.
Je viens de créer un démon approprié, j'ai donc créé une application qui me salue lorsque je me connecte avec TCP. (Ne mentionnez pas le code lui-même car ce n'est qu'un exemple ...) Lorsque vous démarrez l'application et que vous vous connectez à telnet, etc., le texte de bienvenue défini dans la variable d'environnement et votre propre nom de nœud sont renvoyés.
daemon/tcp-server.py.py
#!/usr/bin/python3
import os
import socket
import threading
import time
import signal
import sys
PORT = 5678
PID_FILE_DIR = "/var/run/sample-tcp-server"
PID_FILE_NAME = "tcp-server.pid"
PID_FILE = "%s/%s" % (PID_FILE_DIR, PID_FILE_NAME)
EXIT = False
GREET = os.environ.get("GREET", "Hello!")
def signal_handler(signum, stack):
EXIT = True
def server():
os.makedirs(PID_FILE_DIR, exist_ok=True)
if os.path.isfile(PID_FILE):
raise Exception("Already running")
with open(PID_FILE, "w") as f:
f.write(str(os.getpid()))
print("Create Socket")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', PORT))
s.listen(5)
try:
while True:
if EXIT:
raise Exception("Stop daemon due to receive signal")
(con, addr) = s.accept()
t = threading.Thread(
target=handler,
args=(con, addr),
daemon=False
)
t.start()
except Exception as e:
sys.stderr.write("%s\n" % e)
finally:
print("Close Socket")
s.close()
os.remove(PID_FILE)
return
def handler(con, addr):
con.send(("%s This is %s!\n" % (GREET, socket.gethostname())).encode())
con.close()
if __name__ == '__main__':
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
server()
Comme il a été réalisé uniquement avec des modules standard, il n'est pas nécessaire d'installer des bibliothèques. J'essaye de générer un fichier PID pour confirmer le début du processus. Étant donné que le fichier PID est supprimé lorsque l'application est fermée, vous pouvez vérifier le démarrage de l'application par l'existence du fichier PID, mais s'il est déposé par SIGKILL etc., il ne sera pas supprimé, donc je pense que ce n'est pas très bon. (Cette fois c'est juste un test, donc je fais ça pour simplifier)
Commencez
GREET=Hii! python3 tcp-server.py
Essayez de vous connecter avec telnet
salacia@ha1:~$ telnet localhost 5678
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hi!, This is ha1!
Connection closed by foreign host.
L'exemple de code comprend un fichier de service pour permettre à systemd de démarrer et d'arrêter cette application. Cette fois, exécutons cette application dans un cluster haute disponibilité pour la rendre redondante.
Vous pouvez télécharger et créer un package avec make, donc tout ce que vous avez à faire est de l'installer depuis dpkg. (Doit être installé sur tous les nœuds du cluster)
git clone https://github.com/kamaboko123/OCF_resource_agent_sample.git
cd OCF_resource_agent_sample
make
sudo dpkg -i dist/sampletcpserver_1.0_amd64.deb
Pour le moment, définissez VIP (VRRP) entre les deux nœuds et provoquer un basculement en cas de panne.
#Inscrivez-vous VIP en tant que service
sudo pcs resource create VIP ocf:heartbeat:IPaddr2 ip=172.16.0.50 cidr_netmask=24 op monitor interval=10s on-fail="standby"
#Enregistrer un exemple d'application en tant que service
sudo pcs resource create TCP-SERVER ocf:kamaboko:sample-tcp-server greet=Hi!
#Définissez des contraintes afin que les nœuds VIP et ACTIVE de l'exemple d'application soient identiques
sudo pcs constraint colocation add TCP-SERVER with VIP INFINITY
Connectez-vous à l'adresse IP virtuelle par telnet à partir d'un nœud externe.
salacia@Vega:~$ telnet 172.16.0.50 5678
Trying 172.16.0.50...
Connected to 172.16.0.50.
Escape character is '^]'.
Hi!, This is ha1!
Connection closed by foreign host.
Arrêtez le nœud connecté pour le basculer et vérifiez que le service est toujours disponible.
#Actuellement VIP et TCP-Nœud sur lequel la ressource SERVER s'exécute(ha1)Laissez tomber
salacia@ha1:~$ sudo pcs status
[sudo] password for salacia:
Cluster name: c1
Stack: corosync
Current DC: ha2 (version 1.1.18-2b07d5c5a9) - partition with quorum
Last updated: Tue Aug 11 14:31:30 2020
Last change: Tue Aug 11 14:17:26 2020 by root via cibadmin on ha1
2 nodes configured
2 resources configured
Online: [ ha1 ha2 ]
Full list of resources:
VIP (ocf::heartbeat:IPaddr2): Started ha1
TCP-SERVER (ocf::kamaboko:sample-tcp-server): Started ha1
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
salacia@ha1:~$ sudo shutdown -h now
Connection to 172.16.0.51 closed by remote host.
Connection to 172.16.0.51 closed.
#Vérifiez si le service continue à être fourni du nœud externe au VIP
salacia@Vega:~$ telnet 172.16.0.50 5678
Trying 172.16.0.50...
Connected to 172.16.0.50.
Escape character is '^]'.
Hi!, This is ha2!
Connection closed by foreign host.
#Nœud de destination de basculement(ha2)Vérifiez l'état avec
salacia@ha2:~$ sudo pcs status
[sudo] password for salacia:
Cluster name: c1
Stack: corosync
Current DC: ha2 (version 1.1.18-2b07d5c5a9) - partition with quorum
Last updated: Tue Aug 11 14:35:51 2020
Last change: Tue Aug 11 14:17:26 2020 by root via cibadmin on ha1
2 nodes configured
2 resources configured
Online: [ ha2 ]
OFFLINE: [ ha1 ]
Full list of resources:
VIP (ocf::heartbeat:IPaddr2): Started ha2
TCP-SERVER (ocf::kamaboko:sample-tcp-server): Started ha2
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
À propos, lors du test d'ocf-tester, c'est OK si vous spécifiez le chemin complet.
sudo ocf-tester -n sample-tcp-server /usr/lib/ocf/resource.d/kamaboko/sample-tcp-server
Comme expliqué précédemment, l'agent de ressources est écrit dans un script shell.
/usr/lib/ocf/resource.d/kamaboko/sample-tcp-server
#!/bin/sh
#Initialize
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
#default value
OCF_RESKEY_greet_default="Hello!"
: ${OCF_RESKEY_greet=${OCF_RESKEY_greet_default}}
#environment variables for systemd
DAEMON_PID_FILE=/var/run/sample-tcp-server/tcp-server.pid
sample_meta_data() {
cat << EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="sample-tcp-server" version="0.1">
<version>0.1</version>
<longdesc lang="en">sample tcp server</longdesc>
<shortdesc lang="en">sample tcp server</shortdesc>
<parameters>
<parameter name="greet" unique="0" required="0">
<longdesc lang="en">greet message</longdesc>
<shortdesc lang="en">greet message</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="meta-data" timeout="5" />
<action name="start" timeout="5" />
<action name="stop" timeout="5" />
<action name="monitor" timeout="5" />
<action name="validate-all" timeout="5" />
</actions>
</resource-agent>
EOF
return $OCF_SUCCESS
}
sample_validate(){
return $OCF_SUCCESS
}
sample_start(){
mkdir -p /var/run/sample-tcp-server
echo "GREET=${OCF_RESKEY_greet}" > /var/run/sample-tcp-server/env
systemctl start sample-tcp-server
sleep 1
return $OCF_SUCCESS
}
sample_stop(){
systemctl stop sample-tcp-server
return $OCF_SUCCESS
}
sample_monitor(){
if [ -f ${DAEMON_PID_FILE} ];
then
return $OCF_SUCCESS
fi
return $OCF_NOT_RUNNING
}
sample_usage(){
echo "Test Resource."
return $OCF_SUCCESS
}
# Translate each action into the appropriate function call
case $__OCF_ACTION in
meta-data) sample_meta_data
exit $OCF_SUCCESS
;;
start) sample_start;;
stop) sample_stop;;
monitor) sample_monitor;;
validate-all) sample_validate;;
*) sample_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
Dans les méta-données, les paramètres sont définis en plus des éléments requis.
Le paramètre est une valeur qui est définie lors de la création de la ressource, et peut être obtenue avec la variable ʻOCF_RESKEY_parameter namedans l'agent de ressource. Cette fois, le texte du message d'accueil est défini par le nom de paramètre «saluer». Dans le cas d'un paramètre obligatoire, l'attribut «required» est mis à 1, mais cette fois il vaut 0, il est donc traité comme une option. Par conséquent, il inclut également une définition de la valeur par défaut si elle n'est pas spécifiée. (Si elle n'est pas spécifiée, cette valeur par défaut
Hello!Sera dans
$ OCF_RESKEY_greet`.)
#default value
OCF_RESKEY_greet_default="Hello!"
: ${OCF_RESKEY_greet=${OCF_RESKEY_greet_default}}
sample_meta_data() {
cat << EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="sample-tcp-server" version="0.1">
<version>0.1</version>
<longdesc lang="en">sample tcp server</longdesc>
<shortdesc lang="en">sample tcp server</shortdesc>
<parameters>
<parameter name="greet" unique="0" required="0">
<longdesc lang="en">greet message</longdesc>
<shortdesc lang="en">greet message</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="meta-data" timeout="5" />
<action name="start" timeout="5" />
<action name="stop" timeout="5" />
<action name="monitor" timeout="5" />
<action name="validate-all" timeout="5" />
</actions>
</resource-agent>
EOF
return $OCF_SUCCESS
}
start
Je lance juste un service avec systemd.
Le fichier de service sera expliqué plus tard.
Puisque les paramètres d'OCF sont passés en tant que variables d'environnement au démarrage du service, $ {OCF_RESKEY_greet}
est écrit dans le fichier.
sample_start(){
mkdir -p /var/run/sample-tcp-server
echo "GREET=${OCF_RESKEY_greet}" > /var/run/sample-tcp-server/env
systemctl start sample-tcp-server
sleep 1
return $OCF_SUCCESS
}
stop Il n'y a pas d'explication particulière et le service est arrêté.
sample_stop(){
systemctl stop sample-tcp-server
return $OCF_SUCCESS
}
monitor Cette fois, je regarde le fichier PID.
sample_monitor(){
if [ -f ${DAEMON_PID_FILE} ];
then
return $OCF_SUCCESS
fi
return $OCF_NOT_RUNNING
}
J'ai fait cela pour simplifier, mais je ne pense pas que ce soit vraiment une bonne implémentation. Il est implémenté pour supprimer le fichier PID à la fin du processus, mais s'il est tué par SIGKILL, le fichier PID ne sera pas supprimé. En fonction de la création du fichier de service, l'action d'arrêt est considérée comme arrêtant la ressource par tous les moyens, si bien que SIGKILL peut être émis à la fin. Dans ce cas, le fichier PID continuera à rester même s'il est arrêté, et il est possible que l'état réel diffère de l'état confirmé par l'action du moniteur. (Puisque j'utilise systemd pour la gestion des services, j'aurais dû le faire via systemd)
validate-all Je ne fais rien de particulier.
sample_validate(){
return $OCF_SUCCESS
}
Rien de spécial n'est fait, il suffit de démarrer le démon tout en lisant les variables d'environnement à partir du fichier de variables d'environnement créé lors de la définition de la ressource.
/lib/systemd/system/sample-tcp-server.service
[Unit]
Description=Sample TCP Server
[Service]
Type=simple
ExecStartPre=/bin/touch /var/run/sample-tcp-server/env
EnvironmentFile=/var/run/sample-tcp-server/env
ExecStart=/usr/bin/tcp-server.py
ExecStop=/usr/bin/pkill -F /var/run/sample-tcp-server/tcp-server.pid
[Install]
WantedBy=multi-user.target
Les agents de ressources OCF sont étonnamment faciles à créer. Cette fois, en guise d'entrée, nous avons d'abord créé un agent de ressources qui ne fonctionne qu'avec les actions requises, mais il y a quelques points détaillés à noter lors de sa création. Il y a plusieurs astuces dans le Guide du développeur de l'agent de ressources OCF, donc je pense que ce sera utile.
LPIC304 Quand j'étudiais, je ne comprenais pas vraiment ce que faisait Pacemaker, et en recherchant diverses choses, j'ai réalisé que je pouvais créer mon propre agent de ressources, alors cet article est né.
Recommended Posts