写点什么

Docker 下 RabbitMQ 四部曲之二:细说 RabbitMQ 镜像制作

作者:程序员欣宸
  • 2022 年 5 月 27 日
  • 本文字数:5064 字

    阅读完需:约 17 分钟

Docker下RabbitMQ四部曲之二:细说RabbitMQ镜像制作

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本章是《Docker 下 RabbitMQ 四部曲》系列的第二篇,将详细简述 Docker 下制作 RabbitMQ 镜像的技术细节,包括以下内容:


  1. 列举制作 RabbitMQ 镜像时用到的所有材料;

  2. 编写 Dockerfile;

  3. 编写容器启动时执行的脚本 startrabbit.sh;

  4. 单机版 RabbtiMQ 环境的 docker-compose.yml 说明;

  5. 集群版 RabbitMQ 环境的 docker-compose.yml 说明;

文件和源码下载

  • 您可以在 GitHub 下载本文涉及到的文件和源码,地址和链接信息如下表所示:



  • 这个 git 项目中有多个文件夹,本章所需的内容在 rabbitmq_docker_files 文件夹,如下图红框所示:


  • 接下来开始镜像制作吧;

RabbitMQ 镜像要做的事情

  • 先整理出我们需要一个什么样的镜像:


  1. 基础镜像为 centos:7;

  2. 时区:Asia/Shanghai;

  3. 编码:zh_CN.UTF-8;

  4. 装好了 Erlang;

  5. 装好了 RabbitMQ;

  6. 集群时候各个 RabbitMQ 机器之间的访问权限是通过 erlang.cookie 来控制的,所以在镜像中提前准备好 erlang.cookie,这样使用该镜像的所有容器由于 erlang.cookie 相同,就有了相互访问的权限;

  7. 创建容器时,可以通过参数来控制容器身份,例如集群版的主或者从,如果是身份是从,还要让从知道主的地址;

  8. 创建容器时,可以通过参数设置 RabbitMQ,例如用户名和密码、是否是内存节点、是否是高可用的镜像队列;


  • 以上就是 RabbitMQ 镜像所具备的功能,其中 1-6 都可以在 Dockerfile 中实现,7 和 8 是在容器启动后要做的事情,所以要做个 shell 脚本来完成,容器创建时自动执行这个脚本;

准备镜像制作材料

  • 根据前面列出的功能点,我们需要准备下面以下材料来制作镜像:


  1. Dockerfile:制作 Docker 镜像必须的脚本文件

  2. erlang.cookie:允许多个 RabbitMQ 容器相互访问的权限文件

  3. rabbitmq.config:RabbitMQ 配置文件

  4. startrabbit.sh:容器创建时执行的脚本


  • 这些材料在 github 上都能获取到,地址:https://github.com/zq2599/blog_demos/tree/master/rabbitmq_docker_files/image

  • erlang.cookie 和 rabbitmq.config 很简单不需多说,我们细看 Dockerfile 和 startrabbit.sh;

Dockerfile

  • Dockerfile 是制作镜像时执行的脚本,内容如下:


# Docker file for rabbitmq single or cluster from bolingcavalry # VERSION 0.0.3# Author: bolingcavalry
#基础镜像FROM centos:7
#作者MAINTAINER BolingCavalry <zq2599@gmail.com>
#定义时区参数ENV TZ=Asia/Shanghai
#设置时区RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
#设置编码为中文RUN yum -y install kde-l10n-Chinese glibc-common
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ENV LC_ALL zh_CN.utf8
#安装wget工具RUN yum install -y wget unzip tar
#安装erlangRUN rpm -Uvh https://github.com/rabbitmq/erlang-rpm/releases/download/v19.3.6.5/erlang-19.3.6.5-1.el7.centos.x86_64.rpm
RUN yum install -y erlang
#安装rabbitmqRUN rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
RUN yum install -y https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.5-rc.1/rabbitmq-server-3.7.5.rc.1-1.el7.noarch.rpm
RUN /usr/sbin/rabbitmq-plugins list <<<'y'
#安装常用插件RUN /usr/sbin/rabbitmq-plugins enable --offline rabbitmq_mqtt rabbitmq_stomp rabbitmq_management rabbitmq_management_agent rabbitmq_federation rabbitmq_federation_management <<<'y'
#添加配置文件ADD rabbitmq.config /etc/rabbitmq/
#添加cookie,使集群环境中的机器保持互通ADD erlang.cookie /var/lib/rabbitmq/.erlang.cookie
#添加启动容器时执行的脚本,主要根据启动时的入参做集群设置ADD startrabbit.sh /opt/rabbit/
#给相关资源赋予权限RUN chmod u+rw /etc/rabbitmq/rabbitmq.config \&& chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie \&& chmod 400 /var/lib/rabbitmq/.erlang.cookie \&& mkdir -p /opt/rabbit \&& chmod a+x /opt/rabbit/startrabbit.sh
#暴露常用端口EXPOSE 5672EXPOSE 15672EXPOSE 25672EXPOSE 4369EXPOSE 9100EXPOSE 9101EXPOSE 9102EXPOSE 9103EXPOSE 9104EXPOSE 9105
#设置容器创建时执行的脚本CMD /opt/rabbit/startrabbit.sh
复制代码


  • 如上所示,每个功能都有对应的注释,就不再赘述了;

容器启动后执行的脚本 startrabbit.sh

  • startrabbit.sh 内容如下:


#!/bin/bash
change_default_user() {
if [ -z $RABBITMQ_DEFAULT_USER ] && [ -z $RABBITMQ_DEFAULT_PASS ]; then echo "Maintaining default 'guest' user" else echo "Removing 'guest' user and adding ${RABBITMQ_DEFAULT_USER}" rabbitmqctl delete_user guest rabbitmqctl add_user $RABBITMQ_DEFAULT_USER $RABBITMQ_DEFAULT_PASS rabbitmqctl set_user_tags $RABBITMQ_DEFAULT_USER administrator rabbitmqctl set_permissions -p / $RABBITMQ_DEFAULT_USER ".*" ".*" ".*" fi}
HOSTNAME=`env hostname`
if [ -z "$CLUSTERED" ]; then # if not clustered then start it normally as if it is a single server /usr/sbin/rabbitmq-server & rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid change_default_user tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.logelse if [ -z "$CLUSTER_WITH" ]; then # If clustered, but cluster with is not specified then again start normally, could be the first server in the # cluster /usr/sbin/rabbitmq-server& rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.log else /usr/sbin/rabbitmq-server & rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid rabbitmqctl stop_app if [ -z "$RAM_NODE" ]; then rabbitmqctl join_cluster rabbit@$CLUSTER_WITH else rabbitmqctl join_cluster --ram rabbit@$CLUSTER_WITH fi
rabbitmqctl start_app
# If set ha flag, enable here if [ -z "$HA_ENABLE" ]; then echo "Running with normal cluster mode" else rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode": "all"}' echo "Running wiht HA cluster mode" fi # Tail to keep the a foreground process active.. tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.log fifi
复制代码


  • 这个脚本有以下几点需要注意:


  1. if [ -z "$CLUSTERED" ]表示如果环境变量中没有 CLUSTERED 这个参数;

  2. 如果环境变量中没有 CLUSTERED 这个参数,当前容器的身份就是主,会调用 change_default_user 方法,这个方法中检查是否输入了用户名和密码,如果有就创建用户,并赋予管理员权限,再把原有的 guest 账号删除;

  3. 如果环境变量中有 CLUSTERED 这个参数,当前容器身份就是从,会执行 rabbitmqctl join_cluster 命令加入到集群中去;

  4. 如果环境变量中有 RAM_NODE 这个参数,会在 rabbitmqctl join_cluster 命令中带上 ram 参数,表示当前节点为内存节点;

  5. 如果环境变量中有 HA_ENABLE 这个参数,就在启动 RabbitMQ 之后执行命令 rabbitmqctl set_policy,将集群中的队列变为镜像队列,实现集群高可用;

构建镜像

  • 以上就是制作镜像前的准备工作,完成之后在 Dockerfile 文件所在目录下执行命令 docker build -t bolingcavalry/rabbitmq-server:0.0.3 .,即可构建镜像;

单机版的 docker-compose.yml

  • 这个 docker-compose.yml 在上一章我们用过,内容如下:


rabbitmq:  image: bolingcavalry/rabbitmq-server:0.0.3  hostname: rabbitmq  ports:    - "15672:15672"  environment:    - RABBITMQ_DEFAULT_USER=admin    - RABBITMQ_DEFAULT_PASS=888888producer:  image: bolingcavalry/rabbitmqproducer:0.0.2-SNAPSHOT  hostname: producer  links:    - rabbitmq:rabbitmqhost  ports:      - "18080:8080"  environment:   - mq.rabbit.address=rabbitmqhost:5672   - mq.rabbit.username=admin   - mq.rabbit.password=888888consumer:  image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT  hostname: consumer  links:    - rabbitmq:rabbitmqhost  environment:   - mq.rabbit.address=rabbitmqhost:5672   - mq.rabbit.username=admin   - mq.rabbit.password=888888   - mq.rabbit.queue.name=consumer.queue
复制代码


  • producer 和 consumer 的配置我们下一章再看,现在重点关注 rabbitmq 的配置:


  1. 没有 CLUSTERED 参数,表示该容器以主的身份运行;

  2. RABBITMQ_DEFAULT_USER、RABBITMQ_DEFAULT_PASS 这两个参数设定了此 RabbitMQ 的管理员权限的账号和密码;

集群版的 docker-compose.yml

  • 内容如下:


version: '2'services:  rabbit1:    image: bolingcavalry/rabbitmq-server:0.0.3    hostname: rabbit1    ports:      - "15672:15672"    environment:      - RABBITMQ_DEFAULT_USER=admin      - RABBITMQ_DEFAULT_PASS=888888  rabbit2:    image: bolingcavalry/rabbitmq-server:0.0.3    hostname: rabbit2    depends_on:      - rabbit1    links:      - rabbit1    environment:     - CLUSTERED=true     - CLUSTER_WITH=rabbit1     - RAM_NODE=true    ports:      - "15673:15672"  rabbit3:    image: bolingcavalry/rabbitmq-server:0.0.3    hostname: rabbit3    depends_on:      - rabbit2    links:      - rabbit1      - rabbit2    environment:      - CLUSTERED=true      - CLUSTER_WITH=rabbit1    ports:      - "15675:15672"  producer:    image: bolingcavalry/rabbitmqproducer:0.0.2-SNAPSHOT    hostname: producer    depends_on:      - rabbit3    links:      - rabbit1:rabbitmqhost    ports:      - "18080:8080"    environment:      - mq.rabbit.address=rabbitmqhost:5672      - mq.rabbit.username=admin      - mq.rabbit.password=888888  consumer1:    image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT    hostname: consumer1    depends_on:      - producer    links:      - rabbit2:rabbitmqhost    environment:     - mq.rabbit.address=rabbitmqhost:5672     - mq.rabbit.username=admin     - mq.rabbit.password=888888     - mq.rabbit.queue.name=consumer1.queue  consumer2:    image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT    hostname: consumer2    depends_on:      - consumer1    links:      - rabbit3:rabbitmqhost    environment:      - mq.rabbit.address=rabbitmqhost:5672      - mq.rabbit.username=admin      - mq.rabbit.password=888888      - mq.rabbit.queue.name=consumer2.queue
复制代码


  • 这个脚本有以下几点需要注意:


  1. rabbit1 是主节点;

  2. rabbit2 和 rabbit3 由于设置了 CLUSTERED,身份成为从节点,在 startrabbit.sh 脚本中,会通过 rabbitmqctl join_cluster 命令加入到主节点的集群中去,加入时如何找到主节点呢?用的是 CLUSTER_WITH 参数,而 CLUSTER_WITH 参数的值,在 docker-compose.yml 中通过 link 参数设置为 rabbit1;

  3. rabbit2 设置了 RAM_NODE,所以是个内存节点;


  • 至此,整个 RabbitMQ 镜像制作和使用的详细分析就结束了,您也可以自行实战,在 Dockerfile 和 startrabbit.sh 中增加一些命令来对 RabbitMQ 做更多个性化的设置,下一章,我们开发两个基于 SpringBoot 的工程,分别用来生产和消费消息;

  • 参考并致敬:https://github.com/bijukunjummen/docker-rabbitmq-cluster

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 05 月 27 日阅读数: 22
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
Docker下RabbitMQ四部曲之二:细说RabbitMQ镜像制作_Java_程序员欣宸_InfoQ写作社区