将mastodon实例迁移至docker容器内

Author Avatar
st 2021年04月08日
  • 在其它设备中阅读本文章

2210年了,我怎么还在折腾长毛象。

最近计划把各种单独占着一个服务器的服务都容器化一下然后迁移到一个服务器上。不知不觉自己已经开了七八个服务器了,系统资源都没充分利用,放着久了也都是浪费钱。

备份原实例

首先按照官方迁移教程备份原实例,关闭服务后备份数据库、~/live/public/system以及~/live/.env.production。

用教程中的命令pg_dump -Fc mastodon_production -f backup.dump即可备份数据库,文件backup.dump会生成于当前文件夹。

安装mastodon

安装docker和docker-compose后,将mastodon代码复制到本地,并切换到最新的稳定版:

git clone https://github.com/tootsuite/mastodon.git /mastodon
cd ~/mastodon
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)

目前(2021年4月8日)稳定版3.3.0因为rails的一个依赖mimemagic 0.3.5被作者移除而无法正常build,暂时只能跳过git checkout,直接使用main branch,才可以正常build。

编辑docker-compose.yml,根据需要决定是否取消es的注释,在db下加入environment设置数据库名称及用户,并按照需求修改端口等:

version: '3'
services:

  db:
    restart: always
    image: postgres:9.6-alpine
    shm_size: 256mb
    networks:
      - internal_network
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
    volumes:
      - ./postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: mastodon
      POSTGRES_DB: mastodon_production
      POSTGRES_USER: mastodon

  redis:
    restart: always
    image: redis:6.0-alpine
    networks:
      - internal_network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
    volumes:
      - ./redis:/data

  es:
    restart: always
    image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.8.10
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - "cluster.name=es-mastodon"
      - "discovery.type=single-node"
      - "bootstrap.memory_lock=true"
    networks:
      - internal_network
    healthcheck:
      test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
    volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data
    ulimits:
      memlock:
        soft: -1
        hard: -1

  web:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
    networks:
      - external_network
      - internal_network
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:3000/health || exit 1"]
    ports:
      - "127.0.0.1:3000:3000"
    depends_on:
      - db
      - redis
      - es
    volumes:
      - ./public/system:/mastodon/public/system

  streaming:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: node ./streaming
    networks:
      - external_network
      - internal_network
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1"]
    ports:
      - "127.0.0.1:4000:4000"
    depends_on:
      - db
      - redis

  sidekiq:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: bundle exec sidekiq
    depends_on:
      - db
      - redis
    networks:
      - external_network
      - internal_network
    volumes:
      - ./public/system:/mastodon/public/system
## Uncomment to enable federation with tor instances along with adding the following ENV variables
## http_proxy=http://privoxy:8118
## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
#  tor:
#    image: sirboops/tor
#    networks:
#      - external_network
#      - internal_network
#
#  privoxy:
#    image: sirboops/privoxy
#    volumes:
#      - ./priv-config:/opt/config
#    networks:
#      - external_network
#      - internal_network

networks:
  external_network:
  internal_network:
    internal: true

随后将.env.production复制到目录下,修改DB_HOST、REDIS_HOST、ES_HOST以跟docker-compose.yml中的设置一致,命名为mastodon_db_1、mastodon_redis_1、mastodon_es_1,mastodon为git clone时设定的文件夹名。

修改完成后运行docker-compose build安装。

恢复备份

安装完成后运行docker-compose up -d db运行数据库,将backup.dump复制到目录中并运行cat backup.dump | docker exec -i mastodon_db_1 pg_restore -U mastodon -n public --no-owner --role=mastodon -d mastodon_production恢复数据库备份。

将备份的/public/system复制到目录下的/public/system。

随后运行docker-compose run --rm web rails db:migrate迁移数据库,运行docker-compose run --rm web rails assets:precompile重建assets,运行docker-compose run --rm web bin/tootctl feeds build重新生成首页,不重新生成首页的话用户登录后首页是空的。

全部完成后用docker-compose up -d运行所有服务。

配置反代

Apache的反代配置跟nginx有点不一样,网上也没现成的,主要是设置一下根目录,证书更新用的/.well-known/目录,以及反代规则,贴一下我的配置。

<VirtualHost *:443>
    SSLEngine on
    ServerName mastodon.stsecurity.moe
    DocumentRoot /mastodon/public/

    SSLCertificateFile /etc/apache2/ssl/mastodoncert.pem
    SSLCertificateKeyFile /etc/apache2/ssl/mastodonkey.pem
    SSLCertificateChainFile /etc/apache2/ssl/mastodonfullchain.pem

    <directory /mastodon/public/.well-known/>
      AllowOverride None
      Require all granted
    </directory>

    ErrorLog ${APACHE_LOG_DIR}/mastodon-error.log
    CustomLog ${APACHE_LOG_DIR}/mastodon-access.log combined

   ProxyPreserveHost On
   RequestHeader set X-Forwarded-Proto "https"
   ProxyPass /.well-known !
   ProxyPass /500.html !
   ProxyPass /oops.png !
   ProxyPass /api/v1/streaming/ ws://localhost:4000/
   ProxyPassReverse /api/v1/streaming/ ws://localhost:4000/
   ProxyPass / http://localhost:3000/
   ProxyPassReverse / http://localhost:3000/

   ErrorDocument 500 /500.html
   ErrorDocument 501 /500.html
   ErrorDocument 502 /500.html
   ErrorDocument 503 /500.html
   ErrorDocument 504 /500.html
</VirtualHost>

配置完反代再签一下证书,设置一下强制https,就可以正常访问了。

解决ElasticSearch反复重启的问题

服务正常运行后发现ElasticSearch一直在自动重启,本来以为是内存问题,但加了2Gswap后问题依然存在,用docker log mastodon_es_1查看log发现原因是:
"Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes"
查找了一下解决方案,修改ElasticSearch对应的文件存储地址/mastodon/elasticsearch的权限即可。
运行sudo chown -R 1000:1000 /mastodon/elasticsearch/或者sudo chmod -R 777 /mastodon/elasticsearch/即可。

备份数据库

运行docker exec -i mastodon_db_1 pg_dump -Fc mastodon_production -U mastodon -f /var/lib/postgresql/data/backup.dump即可,文件位于postgres文件夹。

相关链接

Migrate Mastodon from non Docker to Docker

Hosting your own mastodon instance via docker-compose

How to Install Mastodon Using Docker on Alibaba Cloud ECS

Mastodon Docker Setup

本文链接:https://blog.stsecurity.moe/archives/182/
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.