本章是《Docker下RabbitMQ四部曲》系列的第二篇,将详细简述Docker下制作RabbitMQ镜像的技术细节,包括以下内容:
- 列举制作RabbitMQ镜像时用到的所有材料;
- 编写Dockerfile;
- 编写容器启动时执行的脚本startrabbit.sh;
- 单机版RabbtiMQ环境的docker-compose.yml说明;
- 集群版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文件夹,如下图红框所示:
接下来开始镜像制作吧;
RabbitMQ镜像要做的事情
先整理出我们需要一个什么样的镜像:
- 基础镜像为centos:7;
- 时区:Asia/Shanghai;
- 编码:zh_CN.UTF-8;
- 装好了Erlang;
- 装好了RabbitMQ;
- 集群时候各个RabbitMQ机器之间的访问权限是通过erlang.cookie来控制的,所以在镜像中提前准备好erlang.cookie,这样使用该镜像的所有容器由于erlang.cookie相同,就有了相互访问的权限;
- 创建容器时,可以通过参数来控制容器身份,例如集群版的主或者从,如果是身份是从,还要让从知道主的地址;
- 创建容器时,可以通过参数设置RabbitMQ,例如用户名和密码、是否是内存节点、是否是高可用的镜像队列;
以上就是RabbitMQ镜像所具备的功能,其中1-6都可以在Dockerfile中实现,7和8是在容器启动后要做的事情,所以要做个shell脚本来完成,容器创建时自动执行这个脚本;
准备镜像制作材料
根据前面列出的功能点,我们需要准备下面以下材料来制作镜像:
- Dockerfile:制作Docker镜像必须的脚本文件
- erlang.cookie:允许多个RabbitMQ容器相互访问的权限文件
- rabbitmq.config:RabbitMQ配置文件
- startrabbit.sh:容器创建时执行的脚本
这些材料在github上都能获取到,地址:https://github.com/zq2599/blog_demos/tree/master/rabbitmq_docker_files/image
erlang.cookie和rabbitmq.config很简单不需多说,我们细看Dockerfile和startrabbit.sh;
Dockerfile
Dockerfile是制作镜像时执行的脚本,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 1# Docker file for rabbitmq single or cluster from bolingcavalry
2# VERSION 0.0.3
3# Author: bolingcavalry
4
5#基础镜像
6FROM centos:7
7
8#作者
9MAINTAINER BolingCavalry <zq2599@gmail.com>
10
11#定义时区参数
12ENV TZ=Asia/Shanghai
13
14#设置时区
15RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
16
17#设置编码为中文
18RUN yum -y install kde-l10n-Chinese glibc-common
19
20RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
21
22ENV LC_ALL zh_CN.utf8
23
24#安装wget工具
25RUN yum install -y wget unzip tar
26
27#安装erlang
28RUN 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
29
30RUN yum install -y erlang
31
32#安装rabbitmq
33RUN rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
34
35RUN 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
36
37RUN /usr/sbin/rabbitmq-plugins list <<<'y'
38
39#安装常用插件
40RUN /usr/sbin/rabbitmq-plugins enable --offline rabbitmq_mqtt rabbitmq_stomp rabbitmq_management rabbitmq_management_agent rabbitmq_federation rabbitmq_federation_management <<<'y'
41
42#添加配置文件
43ADD rabbitmq.config /etc/rabbitmq/
44
45#添加cookie,使集群环境中的机器保持互通
46ADD erlang.cookie /var/lib/rabbitmq/.erlang.cookie
47
48#添加启动容器时执行的脚本,主要根据启动时的入参做集群设置
49ADD startrabbit.sh /opt/rabbit/
50
51#给相关资源赋予权限
52RUN chmod u+rw /etc/rabbitmq/rabbitmq.config \
53&& chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie \
54&& chmod 400 /var/lib/rabbitmq/.erlang.cookie \
55&& mkdir -p /opt/rabbit \
56&& chmod a+x /opt/rabbit/startrabbit.sh
57
58#暴露常用端口
59EXPOSE 5672
60EXPOSE 15672
61EXPOSE 25672
62EXPOSE 4369
63EXPOSE 9100
64EXPOSE 9101
65EXPOSE 9102
66EXPOSE 9103
67EXPOSE 9104
68EXPOSE 9105
69
70#设置容器创建时执行的脚本
71CMD /opt/rabbit/startrabbit.sh
72
73
如上所示,每个功能都有对应的注释,就不再赘述了;
容器启动后执行的脚本startrabbit.sh
startrabbit.sh内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 1#!/bin/bash
2
3change_default_user() {
4
5 if [ -z $RABBITMQ_DEFAULT_USER ] && [ -z $RABBITMQ_DEFAULT_PASS ]; then
6 echo "Maintaining default 'guest' user"
7 else
8 echo "Removing 'guest' user and adding ${RABBITMQ_DEFAULT_USER}"
9 rabbitmqctl delete_user guest
10 rabbitmqctl add_user $RABBITMQ_DEFAULT_USER $RABBITMQ_DEFAULT_PASS
11 rabbitmqctl set_user_tags $RABBITMQ_DEFAULT_USER administrator
12 rabbitmqctl set_permissions -p / $RABBITMQ_DEFAULT_USER ".*" ".*" ".*"
13 fi
14}
15
16HOSTNAME=`env hostname`
17
18if [ -z "$CLUSTERED" ]; then
19 # if not clustered then start it normally as if it is a single server
20 /usr/sbin/rabbitmq-server &
21 rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid
22 change_default_user
23 tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.log
24else
25 if [ -z "$CLUSTER_WITH" ]; then
26 # If clustered, but cluster with is not specified then again start normally, could be the first server in the
27 # cluster
28 /usr/sbin/rabbitmq-server&
29 rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid
30 tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.log
31 else
32 /usr/sbin/rabbitmq-server &
33 rabbitmqctl wait /var/lib/rabbitmq/mnesia/rabbit\@$HOSTNAME.pid
34 rabbitmqctl stop_app
35 if [ -z "$RAM_NODE" ]; then
36 rabbitmqctl join_cluster rabbit@$CLUSTER_WITH
37 else
38 rabbitmqctl join_cluster --ram rabbit@$CLUSTER_WITH
39 fi
40
41 rabbitmqctl start_app
42
43 # If set ha flag, enable here
44 if [ -z "$HA_ENABLE" ]; then
45 echo "Running with normal cluster mode"
46 else
47 rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode": "all"}'
48 echo "Running wiht HA cluster mode"
49 fi
50
51 # Tail to keep the a foreground process active..
52 tail -f /var/log/rabbitmq/rabbit\@$HOSTNAME.log
53 fi
54fi
55
56
这个脚本有以下几点需要注意:
- if [ -z “$CLUSTERED” ]表示如果环境变量中没有
CLUSTERED这个参数;
- 如果环境变量中没有
CLUSTERED这个参数,当前容器的身份就是主,会调用change_default_user方法,这个方法中检查是否输入了用户名和密码,如果有就创建用户,并赋予管理员权限,再把原有的guest账号删除;
- 如果环境变量中有
CLUSTERED这个参数,当前容器身份就是从,会执行
rabbitmqctl join_cluster命令加入到集群中去;
- 如果环境变量中有
RAM_NODE这个参数,会在rabbitmqctl join_cluster命令中带上ram参数,表示当前节点为内存节点;
- 如果环境变量中有
HA_ENABLE这个参数,就在启动RabbitMQ之后执行命令
rabbitmqctl set_policy,将集群中的队列变为镜像队列,实现集群高可用;
构建镜像
以上就是制作镜像前的准备工作,完成之后在Dockerfile文件所在目录下执行命令
docker build -t bolingcavalry/rabbitmq-server:0.0.3 .,即可构建镜像;
单机版的docker-compose.yml
这个docker-compose.yml在上一章我们用过,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 1rabbitmq:
2 image: bolingcavalry/rabbitmq-server:0.0.3
3 hostname: rabbitmq
4 ports:
5 - "15672:15672"
6 environment:
7 - RABBITMQ_DEFAULT_USER=admin
8 - RABBITMQ_DEFAULT_PASS=888888
9producer:
10 image: bolingcavalry/rabbitmqproducer:0.0.2-SNAPSHOT
11 hostname: producer
12 links:
13 - rabbitmq:rabbitmqhost
14 ports:
15 - "18080:8080"
16 environment:
17 - mq.rabbit.address=rabbitmqhost:5672
18 - mq.rabbit.username=admin
19 - mq.rabbit.password=888888
20consumer:
21 image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT
22 hostname: consumer
23 links:
24 - rabbitmq:rabbitmqhost
25 environment:
26 - mq.rabbit.address=rabbitmqhost:5672
27 - mq.rabbit.username=admin
28 - mq.rabbit.password=888888
29 - mq.rabbit.queue.name=consumer.queue
30
31
producer和consumer的配置我们下一章再看,现在重点关注rabbitmq的配置:
- 没有
CLUSTERED参数,表示该容器以主的身份运行;
- RABBITMQ_DEFAULT_USER、RABBITMQ_DEFAULT_PASS这两个参数设定了此RabbitMQ的管理员权限的账号和密码;
集群版的docker-compose.yml
内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 1version: '2'
2services:
3 rabbit1:
4 image: bolingcavalry/rabbitmq-server:0.0.3
5 hostname: rabbit1
6 ports:
7 - "15672:15672"
8 environment:
9 - RABBITMQ_DEFAULT_USER=admin
10 - RABBITMQ_DEFAULT_PASS=888888
11 rabbit2:
12 image: bolingcavalry/rabbitmq-server:0.0.3
13 hostname: rabbit2
14 depends_on:
15 - rabbit1
16 links:
17 - rabbit1
18 environment:
19 - CLUSTERED=true
20 - CLUSTER_WITH=rabbit1
21 - RAM_NODE=true
22 ports:
23 - "15673:15672"
24 rabbit3:
25 image: bolingcavalry/rabbitmq-server:0.0.3
26 hostname: rabbit3
27 depends_on:
28 - rabbit2
29 links:
30 - rabbit1
31 - rabbit2
32 environment:
33 - CLUSTERED=true
34 - CLUSTER_WITH=rabbit1
35 ports:
36 - "15675:15672"
37 producer:
38 image: bolingcavalry/rabbitmqproducer:0.0.2-SNAPSHOT
39 hostname: producer
40 depends_on:
41 - rabbit3
42 links:
43 - rabbit1:rabbitmqhost
44 ports:
45 - "18080:8080"
46 environment:
47 - mq.rabbit.address=rabbitmqhost:5672
48 - mq.rabbit.username=admin
49 - mq.rabbit.password=888888
50 consumer1:
51 image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT
52 hostname: consumer1
53 depends_on:
54 - producer
55 links:
56 - rabbit2:rabbitmqhost
57 environment:
58 - mq.rabbit.address=rabbitmqhost:5672
59 - mq.rabbit.username=admin
60 - mq.rabbit.password=888888
61 - mq.rabbit.queue.name=consumer1.queue
62 consumer2:
63 image: bolingcavalry/rabbitmqconsumer:0.0.3-SNAPSHOT
64 hostname: consumer2
65 depends_on:
66 - consumer1
67 links:
68 - rabbit3:rabbitmqhost
69 environment:
70 - mq.rabbit.address=rabbitmqhost:5672
71 - mq.rabbit.username=admin
72 - mq.rabbit.password=888888
73 - mq.rabbit.queue.name=consumer2.queue
74
75
这个脚本有以下几点需要注意:
- rabbit1是主节点;
- rabbit2和rabbit3由于设置了
CLUSTERED,身份成为从节点,在startrabbit.sh脚本中,会通过
rabbitmqctl join_cluster命令加入到主节点的集群中去,加入时如何找到主节点呢?用的是CLUSTER_WITH参数,而CLUSTER_WITH参数的值,在docker-compose.yml中通过link参数设置为rabbit1;
- rabbit2设置了RAM_NODE,所以是个内存节点;
至此,整个RabbitMQ镜像制作和使用的详细分析就结束了,您也可以自行实战,在Dockerfile和startrabbit.sh中增加一些命令来对RabbitMQ做更多个性化的设置,下一章,我们开发两个基于SpringBoot的工程,分别用来生产和消费消息;
参考并致敬:https://github.com/bijukunjummen/docker-rabbitmq-cluster