ejabberd 19.09.1をインストールしてクラスタリングする

「いまさらXMPP」と言われそうですが、オープンであることはそれだけで価値があることだと思います。

今回、XMPPサーバーのErlang実装である ejabberd をインストールしてクラスタリングしようと思います。 ejabberdはXMPPの他にMQTTとSIPも喋れるので我が家の萬のことに使えそうです。

とりあえず皆さんお手持ちのサーバーがあると思いますが、私は2台のサーバーにUbuntu Server 18.04 LTSをインストールして最新の状態にアップデートしておきました。 CentOSでもArch Linuxでも何でも大丈夫だと思います。 dpkgとrpmはバイナリパッケージが有りましたが、私はSource packageでインストールしていきます。

DNSサーバーもあると便利なのですが、ここでは省きます(私は設定しますが)。

Erlang/OTP 22のインストール

導入方法は何でもいいと思います。私はソースから入れてみます。 必要なパッケージは README.md を確認してほしいのですが、私はこんな感じに入れています。書き漏らしているものがあったらスミマセン。

sudo apt install -y build-essential libssl-dev zlib1g-dev libncurses5-dev autoconf curl git
cd ~/
curl -L https://github.com/erlang/otp/archive/OTP-22.1.3.tar.gz | tar -zx
cd otp-OTP-22.1.3
./otp_build autoconf
./configure --prefix=/usr/local/erlang/22.1 \
            --enable-smp-support \
            --enable-m64-build \
            --disable-sctp \
            --enable-threads \
            --enable-kernel-poll \
            --enable-hipe \
            --without-javac \
            --without-wx \
            --without-docs \
            --without-odbc \
            --disable-debug
make -j2
sudo make install

インストール

cd ~/
curl -L https://github.com/processone/ejabberd/archive/19.09.1.tar.gz | tar -zx
cd ejabberd-19.09.1
sudo apt install -y libexpat1-dev 

さて ejabberd のビルドを始めます。

./autogen.sh
./configure --prefix=/usr/local/ejabberd \
            --with-erlang=/usr/local/erlang/22.1 \
            --enable-user=ejabberd \
            --enable-group=ejabberd \
            --enable-tools \
            --enable-elixir \
            --enable-zlib \
            --enable-hipe \
            --enable-sip \
            --enable-stun
make -j2
sudo make install
sudo useradd -M -d /usr/local/ejabberd/ -s /usr/sbin/nologin ejabberd
sudo chown ejabberd:ejabberd -R /usr/local/ejabberd
sudo cp ejabberd.service /etc/systemd/system/ejabberd.service

設定

/usr/local/ejabberd/etc/ejabberd/ejabberd.yml を適当に変更します。基本的に特殊な話はないですが、最初の hosts のところはejabberdクラスタ全体としての(XMPPサーバーの)ホスト名です。 ここでは example.com としていますので、jid@example.com というJIDを使うことになります。

--- /usr/local/ejabberd/etc/ejabberd/ejabberd.yml.orig  2019-10-19 07:01:43.351109724 +0900
+++ /usr/local/ejabberd/etc/ejabberd/ejabberd.yml       2019-10-19 07:01:47.711079485 +0900
@@ -15,7 +15,7 @@
 ###

 hosts:
-  - localhost
+  - "example.com"

 loglevel: 4
 log_rotate_size: 10485760
@@ -36,7 +36,7 @@
     max_stanza_size: 262144
     shaper: c2s_shaper
     access: c2s
-    starttls_required: true
+    starttls_required: false
   -
     port: 5269
     ip: "::"
@@ -46,7 +46,7 @@
     port: 5443
     ip: "::"
     module: ejabberd_http
-    tls: true
+    tls: false
     request_handlers:
       /admin: ejabberd_web_admin
       /api: mod_http_api
@@ -153,7 +153,7 @@
   mod_fail2ban: {}
   mod_http_api: {}
   mod_http_upload:
-    put_url: https://@HOST@:5443/upload
+    put_url: http://@HOST@:5443/upload
   mod_last: {}
   mod_mam:
     ## Mnesia is limited to 2GB, better to use an SQL backend

続いて /usr/local/ejabberd/etc/ejabberd/ejabberdctl.cfg を編集します。Erlangのノード名を指定します。 私は1号機のホスト名は xmpp1, 2号機は xmpp2 としています。

--- /usr/local/ejabberd/etc/ejabberd/ejabberdctl.cfg.orig       2019-10-19 07:07:51.002048355 +0900
+++ /usr/local/ejabberd/etc/ejabberd/ejabberdctl.cfg    2019-10-19 07:07:54.230022994 +0900
@@ -134,7 +134,7 @@
 #
 # Default: ejabberd@localhost
 #
-#ERLANG_NODE=ejabberd@localhost
+ERLANG_NODE=ejabberd@xmpp1

 #.
 #' EJABBERD_PID_PATH: ejabberd PID file

xmpp1, xmpp2 ともにお互いがお互いのホスト名を解決できるように、/etc/hosts も設定しておきます。ここはDNSが自由に設定できるならそれでも構わないです。 例は省きます。

起動してみる

とりあえず xmpp1 だけ起動してみます。

sudo systemctl start ejabberd

ejabberdctl を使ってステータスを見てみます。

sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl status

こんな結果が戻ればOKです。

The node ejabberd@xmpp1 is started with status: started
ejabberd 0.0 is running in that node

XMPPのホスト名も確認します。example.com が戻ればOKです。

sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl registered_vhosts

ユーザー登録してみる

dummy ユーザーと dummy2 ユーザーを登録してみます。パスワードは pass123 にしました。

sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl register dummy example.com pass123
sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl register dummy2 example.com pass123

User dummy@example.com successfully registered などと表示されれば登録できています。

試しにクライアントから接続してみます。接続先のサーバーはxmpp1のIPアドレスを直接指定します。

PidginというXMPPクライアントでの設定画面はこうなります。 f:id:dreamizm:20191019083200p:plain f:id:dreamizm:20191019082912p:plain

dummy@example.comdummy2@example.com を設定してどちらもオンラインにします。 お互いにユーザー追加をしてメッセージを送れれば大丈夫です。

2号機(xmpp2) もユーザー登録以外は同様の設定をして動かしておきます。

クラスタリング

/usr/local/ejabberd/.erlang.cookie をxmpp1からxmpp2にコピーします。 一応 sha1sum /usr/local/ejabberd/.erlang.cookieハッシュ値を確認して、同一であることを確認します。 ファイルのオーナーも調整しておきます。

sudo chown ejabberd. /usr/local/ejabberd/.erlang.cookie

一旦ejabberdを再起動して

sudo systemctl restart ejabberd

クラスタに参加します。

sudo -u ejabberd /usr/local/ejabberd/sbin/ejabberdctl --no-timeout join_cluster 'ejabberd@xmpp1'

うまくいっていることを確認します。

$ sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl list_cluster
ejabberd@xmpp1
ejabberd@xmpp2

xmpp1とxmpp2で情報が同期されているはずなので、確認します。xmpp2でコマンドを叩いてみます。

$ sudo -u ejabberd -H /usr/local/ejabberd/sbin/ejabberdctl registered_users example.com
dummy
dummy2

dummy@example.com でxmpp1に、 dummy2@example.com でxmpp2に接続してメッセージがやり取りできることを確認しておきましょう。

おわり

以前はejabberdのクラスタリングはmnesiaの同期操作を手作業でしないといけなかったのですが、最近のリリースではコマンドひとつでできるようになりました。 ぜひみなさんも高機能なXMPPで遊んでみてください。

rktでAlpine Linuxのイメージを作る

こんな感じのスクリプトを作ってみました。 build-alpine.sh などとして保存しておきます。

#!/bin/bash
set -e

[ "x$ALPINE_VERSION" == "x" ] && ALPINE_VERSION="edge"

if [ "$EUID" -ne 0 ]; then
    echo "This script uses functionality which requires root privileges"
    exit 1
fi

acbuild --debug begin

acbuildEnd() {
    export EXIT=$?
    acbuild --debug end && exit $EXIT
}

trap acbuildEnd EXIT

acbuild --debug set-name alpine
acbuild --debug set-tag "${ALPINE_VERSION}"
acbuild --debug dep add quay.io/coreos/alpine-sh
acbuild --debug run -- sed -i 's/v[[:digit:]]\.[[:digit:]]/'"${ALPINE_VERSION}"'/' /etc/apk/repositories
acbuild --debug run apk update
acbuild --debug run -- apk add --upgrade apk-tools
acbuild --debug run -- apk upgrade --latest --available
acbuild --debug run -- rm -rf /var/cache/apk/*
acbuild --debug set-exec -- /bin/sh
acbuild --debug write --overwrite "alpine-${ALPINE_VERSION}-amd64.aci"

やっていることは見たまんまで、サンプルをほぼそのままです。 アレンジしているのはAlpine Linuxのバージョンを指定できるようにしているところで、デフォルトで edge を使います。

# edgeのイメージを作ります
sudo ./build-alpine.sh
# v3.7でイメージを作ります
sudo ALPINE_IMAGE=v3.7 ./build-alpine.sh

カレントディレクトリに alpine-v3.7-amd64.aci とかできていると思うので走らせてみます。シェルが動けばOKです。 exit でコンテナ(Pod) を抜けましょう。

sudo rkt run --insecure-options=image --interactive=true alpine-v3.7-amd64.aci

rktを操作してみる

Podの一覧を見るには rkt list を使います。

$ sudo rkt list
UUID        APP IMAGE NAME  STATE   CREATED     STARTED     NETWORKS
0cd9f129    alpine  alpine:v3.7 exited  7 seconds ago   7 seconds ago   

イメージの一覧を見てみます。 rkt image list をつかいます。

$ sudo rkt image list
ID          NAME                    SIZE    IMPORT TIME LAST USED
sha512-2222d0a86708 quay.io/coreos/alpine-sh:latest     5.4MiB  42 minutes ago  4 minutes ago
sha512-e50b77423452 coreos.com/rkt/stage1-coreos:1.29.0 211MiB  36 minutes ago  36 minutes ago
sha512-7f3037d4a34c alpine:v3.7             6.6MiB  15 seconds ago  15 seconds ago

Podとイメージを削除してみます。

# Podを消すときはUUIDを指定します。前方一致で絞り込めればいいようです。
$ sudo rkt rm 0cd9
"0cd9f129-69d1-42be-9663-4668a4895cdc"

$ sudo rkt list
UUID    APP IMAGE NAME  STATE   CREATED STARTED NETWORKS

# イメージを消すときは ID か NAME を指定します。 IDは前方一致で絞り込めればいいようです
$ sudo rkt image rm sha512-7f
successfully removed aci for image: "sha512-7f3037d4a34c66a0929595a8a46afa5b3364cf84e218aa0305bcfdfe8b95d863"
rm: 1 image(s) successfully removed

$ sudo rkt image list
ID          NAME                    SIZE    IMPORT TIME LAST USED
sha512-2222d0a86708 quay.io/coreos/alpine-sh:latest     5.4MiB  49 minutes ago  12 minutes ago
sha512-e50b77423452 coreos.com/rkt/stage1-coreos:1.29.0 211MiB  43 minutes ago  43 minutes ago

さきほど作ったACIを、走らせずに取り込んでみます。

$ sudo rkt fetch --insecure-options=image alpine-v3.7-amd64.aci 
sha512-7f3037d4a34c66a0929595a8a46afa5b

$ sudo rkt image list
ID          NAME                    SIZE    IMPORT TIME LAST USED
sha512-2222d0a86708 quay.io/coreos/alpine-sh:latest     5.4MiB  51 minutes ago  14 minutes ago
sha512-e50b77423452 coreos.com/rkt/stage1-coreos:1.29.0 211MiB  45 minutes ago  45 minutes ago
sha512-7f3037d4a34c alpine:v3.7             6.6MiB  5 seconds ago   5 seconds ago

取り込んだACI alpine:v3.7 をつかって色々やってみます。ちなみに、ctrl + ] を 3回叩くとコンテナをKILLできます。

$ sudo rkt run --interactive=true alpine:v3.7 --name=alpine-sh
/ # Container rkt-108f0bef-5d73-4458-85ec-b2407ad8acd3 terminated by signal KILL.
$ sudo rkt list
UUID        APP     IMAGE NAME  STATE   CREATED     STARTED     NETWORKS
108f0bef    alpine-sh   alpine:v3.7 exited  51 seconds ago  51 seconds ago  

$ # 実行するコマンドを変えてみます
$ sudo rkt run --interactive=true alpine:v3.7 --name=alpine-ls --exec="ls"
bin      dev      etc      home     lib      linuxrc  media    mnt      proc     root     run      sbin     srv      sys      tmp      usr      var
$ sudo rkt list
UUID        APP     IMAGE NAME  STATE   CREATED     STARTED     NETWORKS
108f0bef    alpine-sh   alpine:v3.7 exited  1 minute ago    1 minute ago    
9e3ed729    alpine-ls   alpine:v3.7 exited  29 seconds ago  29 seconds ago  

$ # デフォルトのコマンド /bin/sh にオプションを渡すときは `--` を前置きしてあげます
$ sudo rkt run --interactive=true alpine:v3.7 --name=alpine-ls2 -- -c 'ls'
bin      dev      etc      home     lib      linuxrc  media    mnt      proc     root     run      sbin     srv      sys      tmp      usr      var
$ sudo rkt list
UUID        APP     IMAGE NAME  STATE   CREATED     STARTED     NETWORKS
108f0bef    alpine-sh   alpine:v3.7 exited  2 minutes ago   2 minutes ago   
9e3ed729    alpine-ls   alpine:v3.7 exited  1 minute ago    1 minute ago    
efe730a1    alpine-ls2  alpine:v3.7 exited  5 seconds ago   5 seconds ago   

rkt (Rocket) on Ubuntu 17.10

rktをUbuntu(Ubuntu Server) 17.10にインストールして動かしてみようと思います。

rktのGitHubをご覧いただくのがはやいのですが、ざっくりいうとDockerのようなコンテナを動かすやつです。Dockerよりも後発(たぶん)なぶん、しっかりスッキリした作りです。 多くがGoで書かれているようですね。

github.com

インストール

Ubuntuリポジトリにも rkt がありますが、私は(意味もなく)最新版を使いたかったので、公式の dpkg を入れてみようと思います。

https://github.com/rkt/rkt/blob/master/Documentation/distributions.md#deb-based

ここに書いてあるとおりですが、私が試した時点では以下のとおりです。バージョンは変わるので、上の公式のドキュメントに従ってやってください。

gpg --recv-key 18AD5014C99EF7E3BA5F6CE950BDD3E0FC8A365E
wget https://github.com/rkt/rkt/releases/download/v1.29.0/rkt_1.29.0-1_amd64.deb
wget https://github.com/rkt/rkt/releases/download/v1.29.0/rkt_1.29.0-1_amd64.deb.asc
gpg --verify rkt_1.29.0-1_amd64.deb.asc
sudo dpkg -i rkt_1.29.0-1_amd64.deb

このタイミングで、ついでに systemd-container とか、git を入れておきます。

sudo apt install systemd-container git

さて acbuild を入れます。

git clone https://github.com/containers/build.git acbuild
cd acbuild
./build-rkt

bin にビルドされた実行ファイルができるので、 PATH に追加しておきます。 ~/.profile にでも書いておきます。

PATH="$HOME/acbuild/bin:$PATH"

exec $SHELL -l などして反映しておきます。