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クライアントでの設定画面はこうなります。
dummy@example.com
と dummy2@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で書かれているようですね。
インストール
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
などして反映しておきます。