RabbitMQ

Пароль указан в переменных Гитлаба и хэшируется при сборке. В definitions.json указаны слова-маркеры, которые будут заменены sed-ом в зависимости от окружения, куда будет деплой Реббита.

.gitlab-ci.yml
stages:
  - build
  - deploy

variables:
  IMAGE_DEV: $CI_REGISTRY_IMAGE/rabbitmq_dev
  IMAGE_STAGE: $CI_REGISTRY_IMAGE/rabbitmq_stage
  IMAGE_PROD: $CI_REGISTRY_IMAGE/rabbitmq_prod
  VERSION: 1.0.$CI_PIPELINE_ID
  DOCKER_HOST: ssh://cicd@${DEPLOY_HOST} # Set default docker context in docker:cli container

before_script:
  - eval $(ssh-agent -s)
  - cat $SSH_PRIVATE_KEY | tr -d '\r' | ssh-add -
  - sed -i '/StrictHostKeyChecking /c StrictHostKeyChecking no' /etc/ssh/ssh_config || true
  - echo "$CI_REGISTRY_PASSWORD" |docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
 
# Task templates

.build:
  stage: build
  tags:
    - shell
  variables:
    IMAGE_NAME: ""
    DEPLOY_HOST: ""
    RABBITMQ_USER: ""
    RABBITMQ_PASS: ""
  script:
    - RABBITMQ_PASS_HASH=`docker run --rm --name rabbit-hash-gen rabbitmq:management-alpine rabbitmqctl hash_password $RABBITMQ_PASS |grep -v $RABBITMQ_PASS`
    - sed -i "s|RABBITMQ_USER|$RABBITMQ_USER|g" definitions.json
    - sed -i "s|RABBITMQ_PASS_HASH|$RABBITMQ_PASS_HASH|" definitions.json
    - docker build -t $IMAGE_NAME:$VERSION .
    - docker push $IMAGE_NAME:$VERSION
    - docker tag $IMAGE_NAME:$VERSION $IMAGE_NAME:latest
    - docker push $IMAGE_NAME:latest

.deploy:
  stage: deploy
  tags:
    - docker
  image: docker:cli
  variables:
    STACK: ""
    IMAGE_NAME: ""
    NETWORK: ""
    DEPLOY_HOST: ""
    RABBITMQ_STORAGE: ""
    RABBITMQ_PORT: ""
    RABBITMQ_ADMIN_PORT: ""
  script:
    - docker pull $IMAGE_NAME:$VERSION
    - docker stack rm $STACK
    - docker network create --driver=overlay --scope=swarm $NETWORK || true
    - docker stack deploy -c ./docker-compose.yml $STACK
 
# Build

build_dev:
  extends: .build
  rules:
    - if: $CI_COMMIT_BRANCH == "dev"
    - if: $BUILD == "yes"
  variables:
    IMAGE_NAME: $IMAGE_DEV
    DEPLOY_HOST: 10.1.0.138
    RABBITMQ_USER: $RABBITMQ_USER_DEV
    RABBITMQ_PASS: $RABBITMQ_PASS_DEV
 
# build_stage:
# build_prod:
 
# Deploy

deploy_dev:
  extends: .deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "dev"
    - if: $BUILD == "yes"
    - if: $DEPLOY == "dev"
      variables:
        VERSION: latest
  variables:
    STACK: rabbitmq_dev
    IMAGE_NAME: $IMAGE_DEV
    NETWORK: ${STACK}
    DEPLOY_HOST: 10.1.0.138
    RABBITMQ_STORAGE: /docker/rabbitmq/dev/rabbitmq_storage
    RABBITMQ_PORT: 8088
    RABBITMQ_ADMIN_PORT: 8089
  environment:
    name: dev
    url: https://${DEPLOY_HOST}:${RABBITMQ_ADMIN_PORT}
 
# deploy_stage:
# deploy_prod:

# Админка через TLS (порт 15671)

docker-compose.yml
version: "3.9"
services:
  rabbitmq:
    image: ${IMAGE_NAME}:${VERSION}
    hostname: rabbitmq
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
    ports:
      - ${RABBITMQ_PORT}:5672
      - ${RABBITMQ_ADMIN_PORT}:15671
    volumes:
      - ${RABBITMQ_STORAGE}:/var/lib/rabbitmq
    networks:
      - rabbitmq

networks:
  rabbitmq:
    external: true
    name: ${NETWORK}

В Докерфайле генерится сертификат для шифрования канала к админке

Dockerfile
FROM rabbitmq:management-alpine
 
COPY --chown=rabbitmq:rabbitmq rabbitmq.conf /etc/rabbitmq/
COPY --chown=rabbitmq:rabbitmq definitions.json /etc/rabbitmq/
 
RUN \
mkdir -p -m 700 /etc/ssl/rabbitmq && \
cd /etc/ssl/rabbitmq && \
openssl genrsa -out ca.key 2048 && \
openssl req -new -x509 -days 36500 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=rabbitmq/CN=rabbitmq Root CA" -out ca.crt && \
openssl req -newkey rsa:2048 -nodes -keyout rabbitmq.key -subj "/C=CN/ST=GD/L=SZ/O=rabbitmq/CN=rabbitmq" -out rabbitmq.csr && \
openssl x509 -req -extfile <(printf "subjectAltName=DNS:rabbitmq") -days 36500 -in rabbitmq.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out rabbitmq.crt && \
chown -R rabbitmq:rabbitmq /etc/ssl/rabbitmq
rabbitmq.conf
load_definitions            = /etc/rabbitmq/definitions.json
 
# https://www.rabbitmq.com/management.html#single-listener-https
management.ssl.port         = 15671
management.ssl.cacertfile   = /etc/ssl/rabbitmq/ca.crt
management.ssl.certfile     = /etc/ssl/rabbitmq/rabbitmq.crt
management.ssl.keyfile      = /etc/ssl/rabbitmq/rabbitmq.key

definitions.json (часть)

definitions.json
{
  "users": [
    {
      "name": "RABBITMQ_USER",
      "password_hash": "RABBITMQ_PASS_HASH",
      "hashing_algorithm": "rabbit_password_hashing_sha256",
      "tags": "administrator",
      "limits": {}
    }
  ],
  "vhosts": [
    {
      "name": "/"
    }
  ],
  "permissions": [
    {
      "user": "RABBITMQ_USER",
      "vhost": "/",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    }
  ],
  "topic_permissions": [],
  "parameters": [],
  "global_parameters": [],
  "policies": [],
  "queues": [
    {
      "name": "queue1",
      "vhost": "/",
      "durable": true,
      "auto_delete": false,
      "arguments": {
        "x-ha-policy": "all"
      }
    },

Очередь пустая после перезапуска RabbitMQ

In the class of your producer you should set delivery mode to “2” which is “persistent”.
You can do that using php-amqplib/rabbitmq-bundle by extending your producer class with OldSound\RabbitMqBundle\RabbitMq\Producer which, itself extends BaseAmqp.
Once you’ve extended your producer class with OldSound\RabbitMqBundle\RabbitMq\Producer it’s already by default setting the “persistent” delivery mode and you will see it stored both in “Persistent” and “In memory”.
Now even after a restart the messages are still int the queue, ready to be consumed.

https://devmeetsbiz.business.blog/2020/01/12/rabbitmq-queue-empty-after-a-restart-why-even-though-its-durable/