1. 程式人生 > >Docker下RabbitMQ四部曲之二:細說RabbitMQ映象製作

Docker下RabbitMQ四部曲之二:細說RabbitMQ映象製作

本章是《Docker下RabbitMQ四部曲》系列的第二篇,將詳細簡述Docker下製作RabbitMQ映象的技術細節,包括以下內容:
1. 列舉製作RabbitMQ映象時用到的所有材料;
2. 編寫Dockerfile;
3. 編寫容器啟動時執行的指令碼startrabbit.sh;
4. 單機版RabbtiMQ環境的docker-compose.yml說明;
5. 叢集版RabbitMQ環境的docker-compose.yml說明;

檔案和原始碼下載

您可以在GitHub下載本文涉及到的檔案和原始碼,地址和連結資訊如下表所示:

名稱 連結 備註
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該專案原始碼的倉庫地址,ssh協議

這個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:容器建立時執行的指令碼

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 <[email protected]>

#定義時區引數
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 [email protected]$CLUSTER_WITH
                else
                        rabbitmqctl join_cluster --ram [email protected]$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的工程,分別用來生產和消費訊息;