Open paunin opened 6 years ago
Just in case it helps, we do that with pgpool.
I've solved this for barman by adding script that adds label to pod with current role (primary or standby) and service that has a selector with role=primary
.
Here's the script:
#!/usr/bin/env python3
import json
import logging
import requests
import requests.exceptions
import os
import socket
import sys
import time
KUBE_SERVICE_DIR = '/var/run/secrets/kubernetes.io/serviceaccount/'
KUBE_NAMESPACE_FILENAME = KUBE_SERVICE_DIR + 'namespace'
KUBE_TOKEN_FILENAME = KUBE_SERVICE_DIR + 'token'
KUBE_CA_CERT = KUBE_SERVICE_DIR + 'ca.crt'
KUBE_API_URL = 'https://kubernetes.default.svc.cluster.local/api/v1/namespaces'
logger = logging.getLogger(__name__)
LABEL = os.environ.get("KUBERNETES_ROLE_LABEL", 'role')
def read_first_line(filename):
try:
with open(filename) as f:
return f.readline().rstrip()
except IOError:
return None
def read_token():
return read_first_line(KUBE_TOKEN_FILENAME)
def api_patch(namespace, kind, name, entity_name, body):
api_url = '/'.join([KUBE_API_URL, namespace, kind, name])
while True:
try:
token = read_token()
if token:
r = requests.patch(api_url, data=body, verify=KUBE_CA_CERT,
headers={'Content-Type': 'application/strategic-merge-patch+json',
'Authorization': 'Bearer {0}'.format(token)})
if r.status_code >= 300:
logger.warning('Unable to change %s: %s', entity_name, r.text)
else:
break
else:
logger.warning('Unable to read Kubernetes authorization token')
except requests.exceptions.RequestException as e:
logger.warning('Exception when executing PATCH on %s: %s', api_url, e)
time.sleep(1)
def change_pod_role_label(namespace, new_role):
body = json.dumps({'metadata': {'labels': {LABEL: new_role}}})
api_patch(namespace, 'pods', os.environ['HOSTNAME'], '{} label'.format(LABEL), body)
def record_role_change(new_role):
logger.debug("Changing the pod's role to %s", new_role)
pod_namespace = os.environ.get('POD_NAMESPACE', read_first_line(KUBE_NAMESPACE_FILENAME)) or 'default'
change_pod_role_label(pod_namespace, new_role)
def main():
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
if len(sys.argv) == 2 and sys.argv[1] in ('primary', 'standby'):
record_role_change(new_role=sys.argv[1])
else:
sys.exit('Usage: %s <primary/standby>', sys.argv[0])
return 0
if __name__ == '__main__':
main()
This script is then called by /usr/local/bin/cluster/repmgr/events/execs/includes/unlock_standby.sh
like python3 /usr/local/bin/label.py primary
.
And same for unlock_master.sh
with parameter standby
.
The only extra package needed is python3-requests
.
There are cases when it's required to have connection to master in any point of time. Need to introduce service which always would connect client to the master regardless of the current state of the cluster.
Service should proxy all of the used ports from postgres service including one for replication and pcp.
Some examples with HA proxy