2020/11 SlackクローンなMattermostをAWSに構築してみた

日尾野秀樹
Mattermost

最近無料版Slackに限界を感じて別のチャットツールに乗り換える記事を見かけるようになりました。 無料版Slackだと5GBのファイルストレージ容量制限があったり、投稿した古いメッセージがlocked-inしてしまうため企業が証跡として使えないという理由が多いようです。

とはいえチャットツールの デファクトスタンダードになりつつあるSlackのU/Iは皆慣れ親しんでいるもので今更他のツールに移行は難しいですよね・・・

そこで今回はSlackクローンと言われるMattermost(マターモスト)を構築してどの程度Slack風かを見てみたいと思います。 なお、Mattermostはオンプレで構築できるOSSなチャットツールでGolangで作られています。
Slackと同様スマホやデスクトップ用の専用アプリがあるのもポイント高いです。 Mattermost Mobile and Desktop Apps ※公式リンクはこちら

構築するにあたって公式ドキュメントにAWSのBeanstalkに構築する手順がありましたので今回はそれを参考にコンテナベースで進めていきます。

タイミングいいことに今月(2020-11-13公表)Amazon Lightsailがコンテナサービスに対応したらしいです。
折角なのでそれで作ってみましょうー

ちなみに今回はマターモストのフィジビリが目的です。なので構築手順は大雑把に書いてます。特に説明もありません(汗) 実際は試行錯誤しながら進めていったのでハマった点なども紹介しようと思ったんですがちょっと趣旨がずれてしまう為やめました・・・

注意

主にAWSやDockerに関する横文字が一切の説明なしに登場します。
必要に応じてググるなりしてください<(_ _)>

1. 事前準備(自分のPCにセットアップしておくもの)

2. AWSの事前準備

  1. IAMで1つMattermostプログラム実行用のユーザーを作成します。
    権限はS3の読み書き権限とLightsailの読み書き権限をつけましょう。
    設定したらアクセスキーIDとシークレットアクセスキーをメモっておきます。
  2. AWS CLIをセットアップします。 自分のPCのAWS CLIを上記でメモったアクセスキーIDとシークレットアクセスキーでもってログインしておきます。詳細はこちらを参考にするとよいでしょう。
  3. S3にMattermost用のバケットを1つ作成します。
    バケット名はメモっておきましょう。
    今回はコンテナベースで構築する為、S3にMattermostの設定ファイルやデータファイルを保管するようにします。
  4. Lightsail上にデータベースを作成します。
    MattermostはデータベースとしてMySQLとPostgreSQLに対応します。
    今回はMySQLを選択します。
    構築したらデータベース名、ユーザ名、パスワードをメモりましょう。
    なおネットワーキングタブより「パブリックモード」を有効にしておきましょう。
    ※最終的には塞ぎますがDockerコンテナビルドがうまくいって安定するまではローカルから直接データベースにつなぎますので。
    lightsailデータベース構築画面lightsail データベース設定画面

3. Dockerfileの作成

こんな感じで・・・(説明手抜)

FROM python:3.6

# Install software
RUN apt-get update && apt-get install -y && \
    apt-get install -y vim && \
    pip install awscli && \
    ls

# Saving diskspace
RUN apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    ls

# Environment Settings (default)
ENV BUCKETNAME=<s3バケット名>
ENV MM_URL=https://releases.mattermost.com/5.29.0/mattermost-team-5.29.0-linux-amd64.tar.gz
ENV MM_FILE=mattermost-team-5.29.0-linux-amd64.tar.gz

# Mattermost Software installing
WORKDIR /mm
ADD $MM_URL .
RUN tar -zxvf ./$MM_FILE
ADD config.json ./mattermost/config/config.json
ADD entrypoint.sh .

# Copying aws config & credentials
# コンテナ内からaws-cliコマンドを実行するためconfigとcredentialsが格納された.awsフォルダを配置する
COPY ./.aws/ /root/.aws/

RUN chmod +x ./entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]

# Mattermost environment variables
ENV PATH="/mm/mattermost/bin:${PATH}"

# Create default storage directory (local)
RUN mkdir ./mattermost-data
VOLUME /mm/mattermost-data

# Ports
EXPOSE 8065

4. Mattermost設定ファイル準備

これをベースに作成します。変更箇所は以下のとおりです。細かい設定は立ち上がってきたらWeb画面上から治せますのでここでは必要最小限とします。
↓config.json(変更箇所抜粋。説明手抜)

{
    "SqlSettings": {
        "DriverName": "mysql",
        "DataSource": "<データベースユーザ名>:<データベースパスワード>@tcp(<データベースのエンドポイント>:3306)/<データベース名>?charset=utf8mb4,utf8",
    },
    "FileSettings": {
        "DriverName": "amazons3",
        "Directory": "/mm/mattermost-data",
        "AmazonS3AccessKeyId": "<アクセスキーID>",
        "AmazonS3SecretAccessKey": "<シークレットアクセスキー>",
        "AmazonS3Bucket": "<バケット名>",
        "AmazonS3Region": "<リージョン名>",
        "AmazonS3Endpoint": "s3.amazonaws.com",
        "AmazonS3SSL": true,
        "AmazonS3SignV2": false,
        "AmazonS3SSE": false,
        "AmazonS3Trace": false
    },
    "LocalizationSettings": {
        "DefaultServerLocale": "ja",
        "DefaultClientLocale": "ja",
        "AvailableLocales": ""
    },
}

5. entrypoint.shの作成

Dockerfileから呼ばれるentrypoint.shはこんな感じ。(説明手抜)

#!/bin/bash

term_handler() {
  echo "===== trap the SIGTERM/SIGINT signals ====="
  echo "(docker終了時処理)"
  echo "Stopping service with SIGTERM pid $1"

  echo "===== Copying config_docker.json To S3 ====="
  echo "(Mattermostの終了後に設定ファイルをS3にアップする)"
  aws s3 cp /mm/mattermost/config/config.json s3://$BUCKETNAME/config.json

  echo "===== Tearminating Mattermost ====="
  echo "(MattermostのプロセスにTERMシグナルを送って終了させる)"
  while kill -0 $1 > /dev/null 2>&1; do
    echo "Waiting for pid $1 to exit..."
    sleep 1
  done
}

echo "===== Copying config_docker.json From S3 ====="
echo "(Mattermostの起動前に設定ファイルをS3から取ってくる)"
aws s3 cp s3://$BUCKETNAME/config.json /mm/mattermost/config/config.json

echo "===== Starting Mattermost ====="
exec /mm/mattermost/bin/mattermost &
pid="$!"

echo "===== Trapping SIGTERM ====="
echo "(dockerからのSIGTERMやSIGINTを受信したら終了前処理をするためTrap設定)"
trap "term_handler $pid" SIGTERM
trap "term_handler $pid" SIGINT

echo "===== Wait terminating ====="
echo "(term_handlerが終了を検知するのを無限wait)"
while kill -0 $pid > /dev/null 2>&1; do
	sleep 1
	wait
done

# [debug] dockerシェルに入りたいときに有効化すること
#(Mattermostの終了後にそのままbash操作できるようにする)
#exec /bin/bash

※mattermost本体はexecで呼び出します。
これでSIGTERMをbashではなくmattermostが受け取るのでtrapできます。
trapしている理由はプログラム終了後にconfig.jsonをS3に保管するためです。 ちゃんとやるならMattermostのシステムコンソールから設定を変更したら都度S3にアップすべきですが今回はフィジビリティなので端折ります。

6. コンテナ作成とイメージ転送

さて準備できたのでDockerコンテナをビルドしてLightsail専用のDockerリポジトリに転送します。これはDocker Hubみたいなもんです。がdocker pushコマンドではなく専用のコマンドで転送するようです。そのためにプラグインを入れたわけです。

docker build -t mattermost-cv:1.0 .
docker buildコマンド
docker run --rm -it -p 3306:3306/tcp -p 80:8065/tcp mattermost-cv:1.0
docker runコマンド ⇒ログのデフォルトがjsonableですねwカッコイイ うまくいったらブラウザよりlocalhostにアクセスしてみましょう。

下のような画面がでれば概ね成功です。コンソールにログがでますのでエラーがないか念のため確認しましょう。

ローカル起動確認

Lightsail上のMySQLにアクセスしてテーブルが沢山できていたら成功です。

MySQLビューアの画面

とりあえず、Ctrl+Cで終了しましょう。
そうすることでMattermost設定ファイル(config.json)がS3バケット上の直下にアップロードされるはずなのでそれを確認しましょう。

Docker runコマンド終了 S3の画面 コンテナ作成 コンテナサービス作成
aws lightsail push-container-image --region <リージョン名> --service-name mattermost-test --label mattermost-test --image mattermost-cv:1.0
lightsailリポジトリにデプロイ Lightsailにデプロイ1 Lightsailにデプロイ2 コンテナ起動確認

7. Slackとの違い検証

Mattermostはデフォルトの見た目青基調なのでSlack風テーマに変更してみました。
Slack風Mattermost

デフォルトで所属する2つのチャンネルTown-squareとOff-topicの名前もそれぞれgeneralとrandomに変更しました。
ほぼSlackですねー

絵文字 ユーザー管理・メトリクス 統合管理機能 Markdown記法入力例

8. まとめ

Mattermostは想定以上にSlackでした。
Lightsail最小構成の割には動作モタツキはないようです。(ユーザが増えたらこの限りではない)
今のところユーザ数無限・メッセージ数無限・ディスク使用料無制限に使え、ランニングコストは(Lightsail最小構成だと)月額数千円程度から始められるので選択肢としては悪くないかもしれません。
ただ更新頻度がかなり高いらしいので、本当にこれで運用するならこんな突貫シェルじゃなく最低限自動アップデート・自動バックアップなどの実装は必要かと思われます。

余談

Lightsailのコンテナサービスのコスパはかなりよさそうです。
最小構成(1GBRAM,0.25vCPU)ならRDS相当のDBと固定IPとコンテナサービスと通信料ストレージ費用込で月額25USDとかです。
しかも最初の3か月無料とか安すぎでしょうw

以上です。

こんな記事も読まれています