=====Oracle 21c Oracle Connection Manager - High Availability Clustering mit Pacemaker ===== **Aufgabe** Der Oracle Connection Manager soll hochverfügbar auf min. zwei System über eine zentrale IP Adresse als ein "active-passive 2-node (1:1) Cluster" betrieben werden. D.h. im Netz ist eine aktive IP Adresse konfiguriert über die der alle Clients und alle DB Registrierungen auf den CMAN zugreifen. Je nach Status des Clusters ist diese Adresse auf eine der beteiligten Maschinen gebunden. Muss nur diese Maschine zum Beispiel für ein OS Update neu gestartet werden, wird die IP Adresse im Cluster auf den zweiten Knoten umgezogen und dort wird der CMAN neu gestartet. {{ :dba:cman:pacemaker_cman_overview_v01.jpg?800 | Pacemaker Cluster mit zwei Knoten und virtueller IP für den Betrieb des CMAN }} Da wir im ersten Schritt nur ein zwei Knoten Cluster haben wird das Fencing und das Quorum Feature deaktiviert. Was mit diesem Konzept leider noch nicht funktioniert ist das Umziehen der aktive Session State des CMAN auf den zweiten Knoten. D.h. im Fehlerfall brechen die Verbindungen ab und müssen neu aufgebaut werden. Durch das TAF Feature von SQL*Net lässt sich das etwas optimieren, das muss aber im Einzelfall gut getestet werden ob das am Ende gut klappt. **Ablauf:** * Oracle Connection Manager System unter Oracle Linux 8 installiert und konfiguriert => [[dba:sqlnet_cman_connection_manager_21c|Oracle 21c - SQL*Net Proxy und Firewall mit dem Oracle Connection Manager CMAN implementieren - Einsatz als Standby DB Proxy für ältere Java Apps]] * Cluster Software installieren (nur Software!) * Maschine herunterfahren und clonen * Clon als eigenständige Umgebung für den CMAN einrichten (IP Adresse, Name etc.) * Pacemaker Cluster einrichten * Cluster IP vergeben * CMAN konfigurieren * Cluster Ressource Gruppe aus IP Adresse und CMAN anlegen * Trigger Skript erzeugen, das die Datenbanken neu am CMAN anmeldet falls als Remote Listener der CMAN eingetragen ist * Testen **Voraussetzung:** * Netzwerkinterface für die Cluster IP Adresse hat auf allen Servern den gleichen Name wie ens160 oder eth0 etc. * Maschinen Name / IP Adressen und neue Cluster IP im DNS eingerichtet * Zeiten auf allen Maschinen im Verbund auf die Sekunde genau synchron! ---- ---- ==== Pacemaker Cluster Software und Umgebung vorbereiten ==== Wie immer müssen die grundlegenden Vorausetzung für den Betrieb eines Clusters zu mehr als 100% geben sein! DNS Auflösung und Uhrzeiten auf den Maschinen muss 100% funktionieren und die Namen/IP Adressen der Maschinen dürfen nicht mehr ändern! === Software bestehender CMAN Umgebung installieren === Was für eine Maschine haben wir: hostnamectl Static hostname: cman21c.pipperr.local Icon name: computer-vm Chassis: vm Machine ID: xxxx Boot ID: xxxx Virtualization: vmware Operating System: Oracle Linux Server 8.9 CPE OS Name: cpe:/o:oracle:linux:8:9:server Kernel: Linux 5.4.17-2136.324.5.3.el8uek.x86_64 Architecture: x86-64 Passendes Repository hinzufügen: dnf config-manager --enable ol8_appstream ol8_baseos_latest ol8_addons System aktualisieren: dnf update reboot Basis Software installieren: dnf install pcs pacemaker resource-agents fence-agents-all Name der Maschine auf eine eindeutigen Namen für den Knoten 1 anpassen vi /etc/hostname cman21c-a.pipperr.local hostname cman21c-a.pipperr.local Maschine herunterfahren und Clonen init 0 Nur den Clone starten, IP Adresse und Server Name ändern, bestehende CMAN Maschine wieder starten, nun stehen uns zwei Maschinen zur Verfügung für die nächsten Schritte. == DNS Konfiguration== DNS Auflösung für beide Maschinen einrichten und prüfen! Die Namen und IP Adressen müssen sich problemlos in alle Richtungen auflösen lassen! In unsere Umgebung ist das dann: * cman21c-a 10.10.10.96 * cman21c-b 10.10.10.97 * OraCmanCluster 10.10.10.98 Mein DNS auf Oracle DB Basis siehe => [[linux:power_dns|PowerDNS 4.x - Die Alternative für BIND - Mit einer Oracle Datenbank im Backend einsetzen]] == Zeit Konfiguration == Sicherstellen das auf beiden Server die gleiche Uhrzeit auf die Sekunde genau eingerichtet ist! Dazu Crony aktiveren => https://docs.oracle.com/en/learn/ol-chrony/#introduction und https://docs.oracle.com/en/operating-systems/oracle-linux/8/network/network-ConfiguringNetworkTime.html#ol-nettime-chrony-config #prüfen timedatectl #Hardware Zeit übernehmen hwclock -w # Crony instalieren dnf list chrony dnf install chrony -y systemctl enable chronyd systemctl start chronyd systemctl status chronyd #prüfen chronyc -n tracking chronyc -n sources -v in der "/etc/chrony.conf" eine pool wie https://www.ntppool.org/en/zone/de "pool 0.de.pool.ntp.org" für die entsprechende Gegend eintragen und chrony Service neu starten. == FW einrichten / ausschalten == Pürfen ob die FW aktiv ist: firewall-cmd --state not running Falls Aktiv diese entsprechend konfigurieren oder deaktivieren falls das möglich ist. ---- ---- ==== Pacemaker Cluster einrichten ==== Beide Maschinen sind nun gestartet. ==Cluster Stack starten auf beiden Maschinen == Beide Knoten: systemctl start pcsd.service systemctl enable pcsd.service ==Passwort des Cluster Owners auf beiden Maschinen setzen== Beide Knoten: echo Clust0wnerPWD | passwd --stdin hacluster == Eigentliches Cluster erzeugen == Nur auf dem Knoten 1! Schlüsselaustaush [root@cman21c-a ~]# pcs host auth cman21c-a cman21c-b -u hacluster -p Clust0wnerPWD cman21c-b: Authorized cman21c-a: Authorized Cluster "OraCmanCluster" anlegen: [root@cman21c-a ~]# pcs cluster setup OraCmanCluster cman21c-a cman21c-b No addresses specified for host 'cman21c-a', using 'cman21c-a' No addresses specified for host 'cman21c-b', using 'cman21c-b' Destroying cluster on hosts: 'cman21c-a', 'cman21c-b'... cman21c-b: Successfully destroyed cluster cman21c-a: Successfully destroyed cluster Requesting remove 'pcsd settings' from 'cman21c-a', 'cman21c-b' cman21c-a: successful removal of the file 'pcsd settings' cman21c-b: successful removal of the file 'pcsd settings' Sending 'corosync authkey', 'pacemaker authkey' to 'cman21c-a', 'cman21c-b' cman21c-a: successful distribution of the file 'corosync authkey' cman21c-a: successful distribution of the file 'pacemaker authkey' cman21c-b: successful distribution of the file 'corosync authkey' cman21c-b: successful distribution of the file 'pacemaker authkey' Sending 'corosync.conf' to 'cman21c-a', 'cman21c-b' cman21c-a: successful distribution of the file 'corosync.conf' cman21c-b: successful distribution of the file 'corosync.conf' Cluster has been successfully set up. Cluster starten: [root@cman21c-a ~]# pcs cluster start --all cman21c-a: Starting Cluster... cman21c-b: Starting Cluster... Status überprüfen: [root@cman21c-a ~]# pcs status Cluster name: OraCmanCluster WARNINGS: No stonith devices and stonith-enabled is not false Cluster Summary: * Stack: unknown (Pacemaker is running) * Current DC: NONE * Last updated: Wed Jan 10 19:58:17 2024 on cman21c-a * Last change: Wed Jan 10 19:57:57 2024 by hacluster via crmd on cman21c-a * 2 nodes configured * 0 resource instances configured Node List: * Node cman21c-a: UNCLEAN (offline) * Node cman21c-b: UNCLEAN (offline) Full List of Resources: * No resources Daemon Status: corosync: active/disabled pacemaker: active/disabled pcsd: active/enabled [root@cman21c-a ~]# corosync-cfgtool -s Local node ID 1, transport knet LINK ID 0 udp addr = 10.10.10.96 status: nodeid: 1: localhost nodeid: 2: connected [root@cman21c-a ~]# corosync-cmapctl | grep members runtime.members.1.config_version (u64) = 0 runtime.members.1.ip (str) = r(0) ip(10.10.10.96) runtime.members.1.join_count (u32) = 1 runtime.members.1.status (str) = joined runtime.members.2.config_version (u64) = 0 runtime.members.2.ip (str) = r(0) ip(10.10.10.97) runtime.members.2.join_count (u32) = 1 runtime.members.2.status (str) = joined ==Service auf beiden Maschinen aktiveren beim Reboot== systemctl enable corosync.service systemctl enable pacemaker.service == Stonith deaktiveren== Da wir nur zwei Knoten haben kann diese Feature deaktiviert werden Nur auf Knoten 1 pcs property set stonith-enabled=false pcs status == reboot Test == Beide Knoten neu starten und testen ob das Cluster funktional ist: reboot pcs status ---- ==== Cluster IP Adresse vergeben ==== Pürfen ob diese ( oracmancluster.pipperr.local => 10.10.10.98 ) im DNS das auch richtig aufgelöst wird: nslookup > oracmancluster.pipperr.local Server: 10.10.10.100 Address: 10.10.10.100#53 Name: oracmancluster.pipperr.local Address: 10.10.10.98 Wie heißt unsere Interface(genauestens prüfen ob auf beiden Knoten das selbe Interface auch am gleichen Switch hängt und gleich heißt!): ip a .. 2: ens160: .. .. Virtuelle IP Adresse als Cluster Ressource zuordnen, der Name "cluster_ip" kann frei gewählt werden: pcs resource create cluster_ip ocf:heartbeat:IPaddr2 ip=10.10.10.98 cidr_netmask=24 op monitor interval=5s pcs status .. Full List of Resources: * cluster_ip (ocf::heartbeat:IPaddr2): Started cman21c-a .. Testen auf Knoten 1 ip a .. inet 10.10.10.98/24 brd 10.10.10.255 scope global secondary ens160 valid_lft forever preferred_lft forever .. Umziehen auf den anderen Knoten: [root@cman21c-a etc]# pcs resource move cluster_ip cman21c-b Warning: A move constraint has been created and the resource 'cluster_ip' may or may not move depending on other configuration [ pcs status .. Full List of Resources: * cluster_ip (ocf::heartbeat:IPaddr2): Started cman21c-b .. ---- ---- ==== CMAN ==== Da auf beiden Seite der CMAN läuft, muss nun auf beiden Seite dafür gesorgt werden, das der CMAN über die Cluster IP Adresse erreicht werden kann. Konzept: * Auf beiden Seiten läuft der CMAN (normal über Service gestartet) * CMAN hört auf alle Anfrage aus dem Netz mit der Cluster IP Adresse * CMan wird wie die "ocf:heartbeat:oralsnr - Manages an Oracle TNS listener" Resource gestartet * Mail wird versandt das umgeschaltete wurde (Resource ocf:heartbeat:MailTo - Notifies recipients by email in the event of resource takeover ) Was noch nicht funktioniert => Per Skript beim Switch Event der IP Adresse auch die Sessions des aktuellen CMAN auf den anderen umziehen; Skript wird über den Cluster Manager getriggert, in Arbeit ... Als Vorlage für einen eigene CMAN Resource kann diese Definition dienen "./usr/lib/ocf/resource.d/heartbeat/oralsnr" oder das Dummy Skript Beispiel unter "./usr/lib/ocf/resource.d/heartbeat/Dummy" Anleitung: siehe => https://github.com/ClusterLabs/resource-agents/blob/main/doc/dev-guides/ra-dev-guide.asc Danach das Skript testen mit: ocf-tester -v -n oracman /usr/lib/ocf/resource.d/heartbeat/oracman === Ein CMAN Konfiguration anlegen === Listener als Vorlage kopieren: cp ./usr/lib/ocf/resource.d/heartbeat/oralsnr ./usr/lib/ocf/resource.d/heartbeat/oracman Aus dieser "Ressource" müssen wir dann unser Startskript aufrufen siehe https://www.pipperr.de/dokuwiki/doku.php?id=dba:sqlnet_cman_connection_manager_21c#auto_start_als_linux_service_einrichten, eine generische Lösung ist mit wohl auch umsetzbar, mit den bestehenden Skripten wird es im ersten Schritt aber deutlich einfacher. Die wichtigsten Punkte beim Start mit Peacemaker Ressource Skripten: * Name der Ressource = Dateiname = Präfix für die Methoden der Ressource * Da hier die Listener Vorlage kopiert wurde, können die existierenden Hilfsskripte für die Oracle/Listener Ressource mit verwendet werden Anpassen auf; #!/bin/sh # # # oracman # # Description: Manages an Oracle Listener CMAN Konfiguration as a High-Availability # resource # # # Author: Gunther Pippèrr # Support: gunther@pipperr.de # License: GNU General Public License (GPL) # Copyright: (C) 2024 International Business Machines, Inc. # # This code inspired by the oralsnr resource script # written by Dejan Muhamedagic # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 oracman::home::user::cman_listener_name # # See oracman_usage() function below for more details... # # OCF instance parameters: # OCF_RESKEY_home (optional; else read it from /etc/oratab) # OCF_RESKEY_user (optional; user to run the listener) # OCF_RESKEY_cmanname (optional; defaults to LISTENER) # OCF_RESKEY_cmanport (mandatory; for the monitor op) # OCF_RESKEY_cmanclustername (mandatory; for the monitor op) # # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs . ${OCF_FUNCTIONS_DIR}/ora-common.sh # Parameter defaults OCF_RESKEY_home_default="/opt/oracle/product/21c/client_2" OCF_RESKEY_user_default="oracle" OCF_RESKEY_cmanname_default="CMAN_GPI" OCF_RESKEY_cmanport_default="1999" OCF_RESKEY_cmanclustername_default="oracmancluster.pipperr.local" : ${OCF_RESKEY_home=${OCF_RESKEY_home_default}} : ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} : ${OCF_RESKEY_cmanname=${OCF_RESKEY_cmanname_default}} : ${OCF_RESKEY_cmanport=${OCF_RESKEY_cmanport_default}} : ${OCF_RESKEY_cmanclustername=${OCF_RESKEY_cmanclustername_default}} ####################################################################### SH=/bin/sh oracman_usage() { methods=`oracman_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages an Oracle CMAN instance as an HA resource. The 'start' operation starts the oracle cman. The 'stop' operation stops the oracle cman. The 'status' operation reports whether the cman is running The 'monitor' operation reports whether the cman seems to be working The 'validate-all' operation reports whether the parameters are valid The 'methods' operation reports on the methods $0 supports ! } oracman_meta_data() { cat < 1.0 Resource script for Oracle CMAN. It manages an Oracle CMAN instance as an HA resource. Manages the Oracle CMAN The Oracle home directory (aka ORACLE_HOME). home Run the CMAN as this user. user Listener instance to be started (as defined in cman.ora). Defaults to CMAN_GPI. cmanname Listener instance Port to be started (as defined in cman.ora). Defaults to 1999. cmanport Listener instance start on this Cluster IP Adress cmanclustername END } # # methods: What methods/operations do we support? # oracman_methods() { cat <<-! start stop status monitor validate-all methods meta-data usage ! } # # Run commands as the Oracle owner... # runasdba() { if [ "$US" = "$ORACLE_OWNER" ]; then $SH else ( echo ". $ORA_ENVF" cat ) | su -s $SH - $ORACLE_OWNER fi } # # oracman_start: Start the Oracle Connection Manager instance # oracman_start() { if is_proc_running && test_tnsping; then : nothing to be done, we can leave right now ocf_log info "Connection manager $cmanname already running" return $OCF_SUCCESS fi output=`echo /opt/oracle/scripts/startcman.sh | runasdba` if test_tnsping; then : cool, we are up and running ocf_log info "Oracle Connection Manager $cmanname running: $output" return $OCF_SUCCESS else ocf_exit_reason "Oracle Connection Manager $cmanname appears to have started, but is not running properly: $output" ocf_log err "Probable Oracle configuration error" return $OCF_ERR_GENERIC fi } # # oracman_stop: Stop the Oracle instance # oracman_stop() { if is_proc_running; then output=`echo /opt/oracle/scripts/stopcman.sh | runasdba` else ocf_log info "Oracle Connection Manager $cmanname already stopped" return $OCF_SUCCESS fi ocf_stop_processes TERM $PROCS_CLEANUP_TIME `proc_pids` # kill the procs if they hanged if is_proc_running; then ocf_exit_reason "Oracle Connection Manager $cmanname not stopped: $output" return $OCF_ERR_GENERIC else ocf_log info "Oracle Connection Manager $cmanname stopped: $output" return $OCF_SUCCESS fi } # # is_proc_running: is the Oracle Connection Manager running? # is_proc_running() { show_procs | grep "." > /dev/null } # the following two should be run only if the process is running test_listener() { local output output=`/opt/oracle/scripts/statuscman.sh` if echo "$output" | grep -qs 'Uptime' then return $OCF_SUCCESS else ocf_exit_reason "$cmanname status failed: $output" return $OCF_ERR_GENERIC fi } # and does it work? test_tnsping() { local output output=`tnsping $cmanclustername:$cmanport/$cmanname` if echo "$output" | grep -qs '^OK'; then return $OCF_SUCCESS else ocf_exit_reason "tnsping $cmanclustername:$cmanport/$cmanname failed: $output" return $OCF_ERR_GENERIC fi } # # oracman_monitor: Can we connect to the listener? # oracman_monitor() { if is_proc_running; then test_listener && test_tnsping else return $OCF_NOT_RUNNING fi } oracman_status() { if is_proc_running then echo cman $cmanname is running exit $OCF_SUCCESS else echo cman $cmanname is stopped exit $OCF_NOT_RUNNING fi } # OCF_RESKEY_home="/opt/oracle/product/21c/client_2" # OCF_RESKEY_user="oracle" # OCF_RESKEY_cmanname="CMAN_GPI" # OCF_RESKEY_cmanport="1999" oracman_getconfig() { ora_common_getconfig "null" "$OCF_RESKEY_home" "$OCF_RESKEY_user" "$OCF_RESKEY_cmanname" "$OCF_RESKEY_cmanport" ${OCF_RESKEY_cmanclustername} cmanname=${OCF_RESKEY_cmanname} cmanport=${OCF_RESKEY_cmanport} cmanclustername=${OCF_RESKEY_cmanclustername} } oracman_validate_all() { ora_common_validate_all } # used in ora-common.sh show_procs() { ps -U "$ORACLE_OWNER" -o pid,user,args | grep '[t]nslsnr' | grep -i -w "$cmanname" } proc_pids() { show_procs | awk '{print $1}'; } PROCS_CLEANUP_TIME="10" OCF_REQUIRED_PARAMS="cmanname" OCF_REQUIRED_BINARIES="tnsping" ocf_rarun $* # # vim:tabstop=4:shiftwidth=4:textwidth=0:wrapmargin=0 ===Verteilen=== Diese Datei auf den zweiten Knoten kopieren nach "/usr/lib/ocf/resource.d/heartbeat/oracman" scp /usr/lib/ocf/resource.d/heartbeat/oracman cman21c-b:/usr/lib/ocf/resource.d/heartbeat/oracman ---- === CMAN Konfiguration === Auf beiden Knoten den Cman auf die Clusteradresse konfigurieren User Oracle: su - oracle cd $TNS_ADMIN #Kontrollieren das der CMAN auf den Namen der Maschine konfiguriert ist: #auf beiden Maschinen entsprechend anpassen #Nachteil bei Regeländerungen müssen zwei Dateien angepasst werden! # .. (address= (protocol=tcp)(host=oracmancluster.pipperr.local)(port=1999)) .. Testen das alles auch so funktioniert auf dem Knoten mit der aktiven Cluster IP. ---- ==== CMAN als Cluster Ressource aktiveren==== === Gruppe anlegen === Da die virtuelle IP und der CMAN zusammen gehören, werden beide in eine Gruppe gepackt: #was gibt es schon pcs resource group list # Gruppe anlegen pcs resource group add cmangrp cluster_ip gpicman pcs resource group list cmangrp: cluster_ip gpicman # da wir IP zur angelegt haben Constraint wieder freigeben pcs resource clear cluster_ip Removing constraint: cli-prefer-cluster_ip Auf beiden Seite die Ressource Hilfe Texte anzeigen lassen um zu prüfen ob die Ressource auch existiert: pcs resource describe oracman Anlegen im Cluster auf Knoten A mit: #als root pcs resource create gpicman oracman home="/opt/oracle/product/21c/client_2" user="oracle" cmanname="CMAN_GPI" cmanport="1999" cmanclustername="oracmancluster.pipperr.local" Assumed agent name 'ocf:heartbeat:oracman' (deduced from 'oracman') ---- ==== Testen ==== === Wartungsfall === Knoten herausnehmen: [root@cman21c-a ~]# pcs node standby cman21c-a # Zieht nach B um ... Node List: * Node cman21c-a: standby * Online: [ cman21c-b ] Full List of Resources: * Resource Group: cmangrp: * cluster_ip (ocf::heartbeat:IPaddr2): Started cman21c-b * gpicman (ocf::heartbeat:oracman): Starting cman21c-b .... #wieder aktivieren [root@cman21c-a ~]# pcs node unstandby cman21c-b === Störfall === Knoten B nun "abschießen" # auf Knoten B anmelden shutdown -h 0 Dienst wechseln sofort auf den aktiven Knoten ! ---- ==== Cluster in Betrieb nehmen ==== Nachdem das Cluster nun im Prinzip läuft, bleiben noch die Aufgaben das für den "echten" Betrieb zu optimieren. === CMAN.ora syncroniseren === Die cman.ora zwischen beiden Knoten sollte auf den selben Stand gehalten werden. In der CMAN.ora sind alle Regeln für A und für B hinterlegt, Datei funktioniert ohne Anpassung in beiden Umgebungen. Dazu bietet sich rsync als Job auf beiden Knoten an, rsync wird auf A immer um x:15 aufgerufen, auf B immer um x:45. === Alerting / Monitoring === Einbinden in die Überwachung, je nach dem was vorhanden ist. === Datenbank Registierung === Wird der CMAN umgeschaltet, muss sich die DB ja neu an dem CMAN anmelden falls als Remote Listener dieser registriert ist. Dazu muss der Event des Umschaltens "abgegriffen" werden und per Skript Kette dann in der DB die Registrierung mit "alter system register" neu aktviert werden. ---- ==== Web Oberfläche ==== Unter https://NodeName/2224 steht nach der Installation eine Oberfläche für das Cluster zur Verfügung. Der Default User ist "hacluster" und das Password das bei der Anlage des Clusters definiert wurde. Cluster beim ersten Aufruf mit "add" hinzufügen: {{ :dba:cman:peacemaker_cluster_ui_add_cluster.jpg?600 | Pacemaker Cluster hinzufügen }} Beispiel für eine Übersichtsmaske: {{ :dba:cman:pacemaker_ressource_overview.jpg?600 | Pacemaker Ressourcen Übersicht }} ---- ==== Quellen ==== Oracle Doku: * https://docs.oracle.com/en/operating-systems/oracle-linux/8/availability/index.html#Oracle-Linux-8 Pacemaker * https://clusterlabs.org/quickstart-redhat.html * https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/high_availability_add-on_reference/index Web * https://raymii.org/s/tutorials/Corosync_Pacemaker_-_Execute_a_script_on_failover.html