dockerkubernetesrabbitmqrabbitmqctl

Init container to wait for rabbit-mq readiness


I saw the example for docker healthcheck of RabbitMQ at docker-library/healthcheck.

I would like to apply a similar mechanism to my Kubernetes deployment to await on Rabbit deployment readiness. I'm doing a similar thing with MongoDB, using a container that busy-waits mongo with some ping command.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-1
  template:
    metadata:
      labels:
        app: app-1
    spec:
      initContainers:
        - name: wait-for-mongo
          image: gcr.io/app-1/tools/mongo-ping
      containers:
        - name: app-1-service
          image: gcr.io/app-1/service
          ...

However when I tried to construct such an init container I couldn't find any solution on how to query the health of rabbit from outside its cluster.


Solution

  • Adapted from this example, as suggested by @Hanx:

    Dockerfile

    FROM python:3-alpine
    
    ENV RABBIT_HOST="my-rabbit"
    ENV RABBIT_VHOST="vhost"
    ENV RABBIT_USERNAME="root"
    
    RUN pip install pika
    
    COPY check_rabbitmq_connection.py /check_rabbitmq_connection.py
    RUN chmod +x /check_rabbitmq_connection.py
    
    CMD ["sh", "-c", "python /check_rabbitmq_connection.py --host $RABBIT_HOST --username $RABBIT_USERNAME --password $RABBIT_PASSWORD --virtual_host $RABBIT_VHOST"]
    

    check_rabbitmq_connection.py

    #!/usr/bin/env python3
    # Check connection to the RabbitMQ server
    # Source: https://blog.sleeplessbeastie.eu/2017/07/10/how-to-check-connection-to-the-rabbitmq-message-broker/
    
    import argparse
    import time
    import pika
    
    # define and parse command-line options
    parser = argparse.ArgumentParser(description='Check connection to RabbitMQ server')
    parser.add_argument('--host', required=True, help='Define RabbitMQ server hostname')
    parser.add_argument('--virtual_host', default='/', help='Define virtual host')
    parser.add_argument('--port', type=int, default=5672, help='Define port (default: %(default)s)')
    parser.add_argument('--username', default='guest', help='Define username (default: %(default)s)')
    parser.add_argument('--password', default='guest', help='Define password (default: %(default)s)')
    args = vars(parser.parse_args())
    
    print(args)
    
    # set amqp credentials
    credentials = pika.PlainCredentials(args['username'], args['password'])
    # set amqp connection parameters
    parameters = pika.ConnectionParameters(host=args['host'], port=args['port'], virtual_host=args['virtual_host'], credentials=credentials)
    
    # try to establish connection and check its status
    while True:
        try:
            connection = pika.BlockingConnection(parameters)
            if connection.is_open:
                print('OK')
                connection.close()
                exit(0)
        except Exception as error:
            raise
            print('No connection yet:', error.__class__.__name__)
            time.sleep(5)
    

    Build and run:

    docker build -t rabbit-ping .
    
    docker run --rm -it \
        --name rabbit-ping \
        --net=my-net \
        -e RABBIT_PASSWORD="<rabbit password>" \
        rabbit-ping
    

    and in deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    ...
    spec:
      ...
      template:
        ...
        spec:
          initContainers:
            - name: wait-for-rabbit
              image: gcr.io/my-org/rabbit-ping
              env:
                - name: RABBIT_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: rabbit
                      key: rabbit-password
          containers:
            ...