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

简介: 详细简述Docker下制作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下载本文涉及到的文件和源码,地址和链接信息如下表所示:
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本章所需的内容在rabbitmq_docker_files文件夹,如下图红框所示:

image.png

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

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:容器创建时执行的脚本

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

#安装erlang
RUN 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

#安装rabbitmq
RUN 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 5672
EXPOSE 15672
EXPOSE 25672
EXPOSE 4369
EXPOSE 9100
EXPOSE 9101
EXPOSE 9102
EXPOSE 9103
EXPOSE 9104
EXPOSE 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.log
else
        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
        fi
fi
  • 这个脚本有以下几点需要注意:
  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=888888
producer:
  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=888888
consumer:
  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

欢迎关注阿里云开发者社区博客:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...
相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
18天前
|
Docker 容器
将本地的应用程序打包成Docker镜像
将本地的应用程序打包成Docker镜像
|
3天前
|
NoSQL PHP MongoDB
docker push推送自己搭建的镜像
本文详细介绍了如何搭建和复盘两个Web安全挑战环境:人力资源管理系统和邮件管理系统。首先,通过Docker搭建MongoDB和PHP环境,模拟人力资源管理系统的漏洞,包括nosql注入和文件写入等。接着,复盘了如何利用这些漏洞获取flag。邮件管理系统部分,通过目录遍历、文件恢复和字符串比较等技术,逐步绕过验证并最终获取flag。文章提供了详细的步骤和代码示例,适合安全研究人员学习和实践。
19 3
docker push推送自己搭建的镜像
|
19天前
|
数据库 Docker 容器
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。Dockerfile定义了构建镜像所需的所有指令,包括基础镜像选择、软件安装、文件复制等,极大提高了开发和部署的灵活性与一致性。掌握Dockerfile的编写,对于提升软件开发效率和环境管理具有重要意义。
41 9
|
1月前
|
缓存 Linux 网络安全
docker的镜像无法下载如何解决?
【10月更文挑战第31天】docker的镜像无法下载如何解决?
1656 30
|
19天前
|
存储 缓存 运维
Docker镜像采用分层存储,每层代表镜像的一部分,如基础组件或应用依赖,多层叠加构成完整镜像
Docker镜像采用分层存储,每层代表镜像的一部分,如基础组件或应用依赖,多层叠加构成完整镜像。此机制减少存储占用,提高构建和传输效率。Docker还通过缓存机制提升构建和运行效率,减少重复工作。文章深入解析了Docker镜像分层存储与缓存机制,包括具体实现、管理优化及实际应用案例,帮助读者全面理解其优势与挑战。
41 4
|
2月前
|
缓存 监控 持续交付
|
1月前
|
存储 关系型数据库 Linux
【赵渝强老师】什么是Docker的镜像
Docker镜像是一个只读模板,包含应用程序及其运行所需的依赖环境。镜像采用分层文件系统,每次修改都会以读写层形式添加到原只读模板上。内核bootfs用于加载Linux内核,根镜像相当于操作系统,上方为应用层。镜像在物理存储上是一系列文件的集合,默认存储路径为“/var/lib/docker”。
|
2月前
|
消息中间件 编解码 Docker
【Docker项目实战】Docker部署RabbitMQ消息中间件
【10月更文挑战第8天】Docker部署RabbitMQ消息中间件
122 1
【Docker项目实战】Docker部署RabbitMQ消息中间件
|
1月前
|
存储 监控 Linux
docker构建镜像详解!!!
本文回顾了Docker的基本命令和管理技巧,包括容器和镜像的增删改查操作,容器的生命周期管理,以及如何通过端口映射和数据卷实现容器与宿主机之间的网络通信和数据持久化。文章还详细介绍了如何使用Docker部署一个简单的Web应用,并通过数据卷映射实现配置文件和日志的管理。最后,文章总结了如何制作自定义镜像,包括Nginx、Python3和CentOS镜像,以及如何制作私有云盘镜像。
150 2