This page looks best with JavaScript enabled

Misskey | 在Docker中大版本升级Misskey

兼谈Postgres容器从12.2-alpine升级至15-alpine

 ·  ☕ 10 min read

借此机会记录Misskey v12.119跨v13大版本升级至2023年终版本全过程。

本文直接参考了lala的升级过程,由于有巨坑因此仅作备忘使用,鞠躬。
原文地址:(https://lala.im/8578.html)

简要介绍

由于学(躺)业(平)原因,上次打开服务器已经是一年多了,在此期间Misskey历经两次大版本升级。本着不动就不会坏的原则就拖着一直没升,因为印象里我所在的v12.119版本当时有修复好一个危及Fediverse的重要的安全性bug。而且据友所说新版本有一些花里胡哨用不上的功能,在旧版本躺平习惯了又没有安全性后顾之忧也就没什么升级的必要。但是前些天看到身边原本用Misskey v12的友友们纷纷升级到v13,我终于开始不淡定了。毕竟本来就跟社会脱节再不升级的话会不会因为低版本兼容性的问题而被Fedi抛弃啊…

在本人沉迷于日制校供和美妆区的过去一年间,Misskey项目又新增了好多分支,甚至有一些分支的功能颠覆了本Fedi老人的认知,比如迁移到新账号后导入过去的贴文之类的,在以前想都不敢想。Fedi宇宙日渐活跃,又经历一波微博迁移潮,Misskey项目及其分支开发工作也稳定输出,真的有一种百花齐放的感觉。但是作为建站不想维护的我有难了,最后还是选择在DDL(农历新年开始前)面前放弃一切尊严。

本人搭建Misskey的全步骤在这篇博客:Misskey | 利用Docker-compose搭建Fedi开源社交平台,搭建好之后升级过一次小版本(从v12.118升至v12.119)修复了上文提到的安全性bug,除此之外再无升级维护操作。正好借此机会记录Misskey v12.119跨一整个v13大版本升级至2023年终版本全过程。

环境介绍

先说一下,我搭建使用的是docker-compose,并且使用的是dockerhub中的官方现有镜像,并不是把项目源码拉到本地后自己构建。当然如果是在服务器里构建镜像的话步骤几乎是一样的。用docker-compose方式搭建Misskey是最小化、自定义程度不错且新手友好的方式。我的项目目录是/opt/misskey,不使用s3对象存储而是将文件储存在本地的files目录下。docker-compose.yml.config/docker.env.config/default.yml这三个文件使用的是官方项目一年前的版本,现在均已经经过了巨大改动。

服务器系统是Debian 10,Misskey的重要依赖Node.js版本号是16。docker和docker-compose应该是哪个版本都可以,但最好不要用过于旧的。Misskey v12.119使用的docker-compose.yml文件内声明postgres版本号是12.2-alpine,redis用的是4.0-alpine

打开官方项目的更新历史,可以看到在13.0.0 (2023/01/16)这个大版本升级的时候要进行的改动:

For server admins

Node.js 18.x or later is required
PostgreSQL 15.x is required
Misskey not using 15 specific features at 13.0.0, but may do so in the future.
Docker環境でPostgreSQLのアップデートを行う際のガイドはこちら: #9641 (comment)
Elasticsearchのサポートが削除されました
代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
Yarnからpnpmに移行されました corepackの有効化を推奨します: sudo corepack enable
……

也就是说,在Misskey v13 以及更高版本中,Node.js要从16.x升到18.x,postgres要升到15-alpine,redis作为缓存也可以从4.0-alpine升到7-alpine但不是必须。同时ES搜索已经不提供支持了。

升级操作

如果不幸因为各种各样的原因升级失败需要备份一下旧的文件与环境。登入服务器,进入到Misskey的项目目录,先停掉web容器,防止有新的数据写到数据库:

cd /opt/misskey
docker compose stop web

然后掏出VPS的服务提供商,全盘做一个系统快照。这样如果不幸失败了也有很大机会找回数据。注意一下系统快照不是万能的,虽然能很方便地将服务器一键回滚到之前的状态,但也是有极极极小概率回滚失败。祝大家武运昌隆。

然后先查看一下数据库的用户密码和数据库名是什么,这些都设置在.config/docker.env里面。运行nano .config/docker.env就可以看到。然后运行pg_dump命令来备份数据库。

docker compose exec db pg_dump -Fc misskey -U misskey-user > db.dump

上面的命令将misskey换成数据库名,misskey-user换成数据库用户。等待一会在/opt/misskey目录下就会有一个db.dump文件啦,这个就是备份出来的二进制数据。数据备份完成后停止并删除所有容器:

docker-compose down

这样Misskey的所有服务就全部停掉了。为了避免翻车再备份一下数据库的持久化数据:运行mv db db1,把db目录重命名成db1,如果升失败了可以直接恢复,等之后确认升级成功了可以删除。

接下来编辑docker-compose.yml文件。因为docker-compose.yml做了很大改动,所以也备份一下旧的:

mv docker-compose.yml docker-compose.yml.save   #将docker-compose.yml文件重命名,等之后确认升级成功了可以删除
nano docker-compose.yml   #创建新的docker-compose.yml文件

文件内容如下:

version: "3"

services:
  web:
#    build: .
    restart: always
    image: misskey/misskey:2023      #我准备将Misskey升级到2023年终版本,改成latest也可以
    links:
      - db
      - redis
#     - mcaptcha
#     - meilisearch
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports:
      - "3000:3000"              #如果服务器端口3000已被使用,可改为其他端口,例如127.0.0.1:5210:3000
    networks:
      - internal_network
      - external_network
    volumes:
      - ./files:/misskey/files      #用户上传到本地的文件,如果您一开始就接入外部存储(如wasabi或是AWS S3)您可以忽略这块配置
      - ./.config:/misskey/.config:ro        #.config目录下有两个配置文件,设置成让Misskey只读

  redis:
    restart: always
    image: redis:7-alpine
    networks:
      - internal_network
    volumes:
      - ./redis:/data
    healthcheck:
      test: "redis-cli ping"
      interval: 5s
      retries: 20

  db:
    restart: always
    image: postgres:15-alpine
    networks:
      - internal_network
    env_file:
      - .config/docker.env
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
      interval: 5s
      retries: 20

#  mcaptcha:
#    restart: always
#    image: mcaptcha/mcaptcha:latest
#    networks:
#      internal_network:
#      external_network:
#        aliases:
#          - localhost
#    ports:
#      - 7493:7493
#    env_file:
#      - .config/docker.env
#    environment:
#      PORT: 7493
#      MCAPTCHA_redis_URL: "redis://mcaptcha_redis/"
#    depends_on:
#      db:
#        condition: service_healthy
#      mcaptcha_redis:
#        condition: service_healthy
#
#  mcaptcha_redis:
#    image: mcaptcha/cache:latest
#    networks:
#      - internal_network
#    healthcheck:
#      test: "redis-cli ping"
#      interval: 5s
#      retries: 20

#  meilisearch:
#    restart: always
#    image: getmeili/meilisearch:v1.3.4
#    environment:
#      - MEILI_NO_ANALYTICS=true
#      - MEILI_ENV=production
#    env_file:
#      - .config/meilisearch.env
#    networks:
#      - internal_network
#    volumes:
#      - ./meili_data:/meili_data

networks:
  internal_network:
    internal: true
  external_network:

然后Ctrl+X,按Y保存。上述文件将postgres升到15,redis升到7。但是.config/docker.env.config/default.yml这两个配置文件还没有修改,要修改一下:

mv .config/default.yml default.yml.save  #重命名default.yml文件并且放到/opt/misskey目录下,也就是.config目录的外面。等之后确认升级成功了可以删除
nano .config/default.yml  #新建文件

文件内容在这里:default.yml。注意改动:

  • url项改为你的域名。重要,由于分布式属性,一旦开启站点则不可更改。所以要和之前的设置保持一致
  • 将db项的user和pass改为数据库用户和数据库密码。和docker.env文件保持相同

其他配置都可以保持默认。然后Ctrl+X,按Y保存。接下来修改docker.env文件:运行nano .config/docker.env,直接再后面加一行:

DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}"

Ctrl+X,按Y保存退出就好。还有一个Node.js没有升级,将它升到18.x

sudo curl -fsSL https://deb.nodesource.com/setup_16.x | sudo bash -
sudo apt install nodejs

如果报错提示sudo命令不存在,把这两行里面的三个sudo都删掉就好了。到此为止环境的部分就配好了。把刚刚导出来的12.2-alpine版本的db数据库备份文件再导入进15-alpine版本的db数据库里,这个步骤就是数据库的升级。

docker compose up -d db

启动15-alpine版本的db数据库容器,会在/opt/misskey目录下面新增一个db文件夹。

docker compose exec -T db pg_restore -U misskey-user -d misskey < db.dump

上面的命令将misskey换成数据库名,misskey-user换成数据库用户。这样就会把db.dump这个二进制文件里的数据导入进15-alpine版本的db数据库容器,完成数据库从12.2到15的升级操作。

docker compose logs db

查看db容器的日志,确保没有报错信息,就可以将Misskey服务全部启动:

docker-compose up -d

至此Misskey的大版本升级就完成了。不过lala又提供了另一种数据库的升级方法,使用pg_dumpall备份数据。虽然说是要记录下来做参考,但是我实际运行的时候是导出不了全局备份文件的,而且第一种方法真的很简单为什么不用第一种。顺便说一下官方给的数据库升级步骤就是第二种,有大坑。

第二种数据库升级方法(不推荐)

下面来说第二种方法,使用pg_dumpall备份数据,使用psql恢复数据。(不推荐这种方法)

这种方法和上面的区别在于pg_dumpall备份出来的数据是纯文本的,pg_dumpall也只支持这一种格式。

纯文本格式的数据不能使用pg_restore恢复,只能使用psql恢复。并且pg_dumpall会导出Roles,这里就是大坑所在。

还是先停止web容器:

docker compose stop web

使用pg_dumpall备份数据:

docker compose exec db pg_dumpall -U misskey-user > db.sql     #misskey-user换成你的数据库用户

停止并删除其他所有容器:

docker compose down

重命名挂载目录:

mv db/ db.backup

由于postgresql15将默认的host验证方式从md5改成了scram-sha-256(在postgresql14之前都是md5,14之后就是scram-sha-256

又因为pg_dumpall备份出来的数据是包含roles的,所以这里需要把postgresql15容器的host验证方式改回和之前一样的都使用md5,否则会导致misskey程序无法连接数据库。

编辑docker-compose.yml文件里面指定的envfile:

nano ./config/docker.env

加入如下配置:

POSTGRES_HOST_AUTH_METHOD=md5

修改image的tag:

image: postgres:12.2-alpine

将12.2改为15:

image: postgres:15-alpine

(可选)redis的tag也可以改一下:

image: redis:4.0-alpine

目前官方的docker-compose.yml文件里面已经是7了:

image: redis:7-alpine

拉新的image:

docker compose pull

启动db容器:

docker compose up -d db

导入数据:

docker compose exec -T db psql -U misskey-user < db.sql   #misskey-user换成你自己的数据库用户

导入完成后查看日志,看看有没有报错:

docker compose logs db

如果遇到下面的这些错误可以忽略,这是因为容器在启动的时候已经创建了同名的role和数据库:

ERROR:  role "misskey" already exists
ERROR:  database "misskey" already exists

最后将全部容器都启动:

docker compose up -d

数据库升级小记

使用这种方法需要注意的是POSTGRES_HOST_AUTH_METHOD变量仅在容器初始化的时候生效,也就是说如果容器已经启动过一次了,再设置这个变量是不起作用的:

https://github.com/docker-library/postgres/issues/981

如果要修改已经启动过的容器,可以编辑pg_hba.conf

nano db/pg_hba.conf

文件的末尾有一行这样的配置:

host all all all scram-sha-256

修改为:

host all all all md5

重启容器使其生效:

docker compose restart db

至此两种postgresql数据库备份、恢复方法都介绍完了。剩下的是与misskey相关的操作。

Misskey赋权

根据这个新的更改:

https://github.com/misskey-dev/misskey/pull/9560

以及如果你遇到了这些问题:

https://github.com/misskey-dev/misskey/issues/9564

https://github.com/misskey-dev/misskey/issues/9608

那么你还需要修改misskey文件目录所有者,然后重启:

cd /opt/misskey
chown -hR 991.991 files
docker compose restart

最后清理下无用的docker image

docker images // 找到镜像的id,然后用rmi命令删除
docker rmi 755f15b2f8cd
docker rmi ae192c4d3ada
docker rmi -f  `docker images | grep `<none>` | awk `{print $3}`` 

总结遇到的问题,一开始我是使用的pg_dumpall备份的数据库,这个工具备份出来的数据包含了数据库共有的全局对象,即数据库角色、表空间、配置参数等数据。这就是pg_dumpallpg_dump最大的区别所在,pg_dump备份出来的数据是不含这些内容的。这是我后来仔细看了官方文档才发现的:

https://www.postgresql.org/docs/current/app-pg-dumpall.html#Description

又由于postgresql14之后的版本将默认的host验证方式从md5改为了scram-sha-256,这是我翻了半天在官方docker镜像页面发现的:

https://hub.docker.com/_/postgres

里面有这样一段话:

This optional variable can be used to control the auth-method for host connections for all databases, all users, and all addresses. If unspecified then scram-sha-256 password authentication is used (in 14+; md5 in older releases).

这样就导致恢复后的数据库还用的是旧的md5验证方式,与现有postgresql15默认的配置不兼容。最后就导致程序连接不上数据库。

最后我看了下通过pg_dumpall备份出来的纯文本数据,里面确实有这样的内容:

CREATE ROLE misskey;
ALTER ROLE misskey WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION BYPASSRLS PASSWORD `md5xxxxx`;

所以,以后备份数据最好用pg_dump。。。


Roelxy
WRITTEN BY
Roelxy
新世紀摸魚戰士