docker swarmでEC2スポットフリートにMastodonを載せる

Overview

経緯

前回:https://blog.asterism.xyz/posts/2019-07-31/

EC2インスタンスt3.smallとdocker-composeで動かしていた私のMastodonサーバ( https://mstdn.asterism.xyz/@aries )ですが、毎月のサーバ代がだいぶキツいというのがあり節約できないものかと色々やっております。

  • PostgreSQLをRDSからdocker上に移行
  • S3+CloudFrontからS3+Cloudflareへ
  • その後S3からwasabiへ

そんな事もありEC2の金額をだいぶ下げられるスポットフリートが気になりお試しという感じ。

ただ、フリートの挙動よくわかっておらず……。

フリートでもインスタンス強制削除がある?もしされたら同等のインスタンス再作成とかやってくれる?とかその辺ドキュメントちゃんと読まずやってます。週末には読むヨ。

構成

本当はALBで受けてコンテナに流すのが良いんだと思いますが、ALBはALBでお高いのでt3.nanoのnginxで受けたりとかケチってます。

構成図

自分でも見づらいと思うような構成図ですがうまいことやれず諦め。多分VPCとかサブネット描いたほうがよかったかも?

リバースプロキシとデータベースはオンデマンドインスタンスとして用意しておき、リバースプロキシをdocker swarmのマネージャーに。

スポットインスタンスへいちいちsshしてごにょごにょ操作するのも面倒なのでswarmへの参加はEC2のユーザーデータ(インスタンス作ったときに動くスクリプト)で対応しています。

#!/bin/bash
apt update
DEBIAN_FRONTEND=noninteractive apt upgrade -yq
apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt update
apt install docker-ce docker-ce-cli containerd.io -y
docker swarm join --token <token> <manager-IP:port>

スポットインスタンスは1vCPU, 1GB RAMを最低スペックとして、4インスタンス取るようにしています。

Mastodonの各コンテナを1つずつ動かすだけなら3つあるいは2つでも足りますが、(あるいはmanager上でも動かすならスポットは1つでも多分足りる)、折角docker swarmを初めて触るので無停止アップデートできないかなーというのも考えて各種コンテナを2つずつ用意できるようにしています。

stack deploy

クラスタが組めた後はこんなymlを書いてstack deploy

version: '3'
services:
  web:
    image: tootsuite/mastodon:latest
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.role == worker
    env_file: .env.production
    command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider --header 'x-forwarded-proto: https' --proxy=off localhost:3000/api/v1/instance || exit 1"]
    ports:
      - "3000:3000"
  streaming:
    image: tootsuite/mastodon:latest
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.role == worker
    env_file: .env.production
    command: node ./streaming
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider --header 'x-forwarded-proto: https' --proxy=off localhost:4000/api/v1/streaming/health || exit 1"]
    ports:
      - "4000:4000"
  sidekiq:
    image: tootsuite/mastodon
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.role == worker
    env_file: .env.production
    command: bundle exec sidekiq

docker swarmには初めて触るのでググりつつ試行錯誤しつつという感じだったのですがなんか思ってた以上に便利でした。

上のものをstack deployすると、workerだけにコンテナが配置されるのですがこの状態でもmanager兼リバースプロキシからは[http://localhost:3000]とかで繋げられます。

swarmは複数のdockerホストを単一のdockerホストのように動かせる、という認識で良いのかしら……。

運用

同じ名前のstackとしてdeployすればいいみたいですが、:latestだとちょっと心配ですね。

この辺変えるかなぁ……。

アップデートの手順としては

  • db:migrate用のコンテナを用意して実行
  • バージョンタグを書き換えた(あるいは:latestのまま?)stack deployをし直す

という感じ。

私の場合は https://github.com/mohemohe/mstdn.plusminus.io をパクってswarmマネージャーでmastodon_webだけ動かすようにしました。試運転はしましたがメモリ足りるかだけちょっと心配。

comments powered by Disqus