Misskeyを32bit環境(Debian i386)で動かしてみる
昨今のTwitterに関する騒動の影響で、「ポストTwitter」になりうるプラットフォームが俄に注目を集めているらしい。 その一つがセルフホスト型のプラットフォームのMisskeyであり、Twitterを踏襲したタイムラインをサポートしつつ、 Slackライクなリアクションを投稿につけることが出来たり、UIの高度なカスタマイズが出来たりするなどいくつかのユニークな特徴を有している。 また、ActivityPubによる他インスタンスとの連携に対応しており、 他のMisskeyインスタンスだけでなく、Mastodon等とも連携可能な非中央集権型のプラットフォームとなっている。
MisskeyはNode.jsで書かれているため、本来はLinux x86環境で動かすことはできないのだが、 Node.jsの非公式ビルドを用いる等、様々な工夫をすることで32bit環境でも動かすことが出来た。 今回はその記録として構築手順を書いていこうと思う。
概要
今回用いる環境はDebian 11.5 (bullseye) i386である。(ArchLinuxは公式にはx86_64しか対応していない為。) また、検証に際してはVirtualBox上のVMにて作業を行っている。
Misskeyの構築手順としてDockerを使ったインストールが推奨されているため、今回はこれに従う。
Dockerを使ったMisskey構築 | Misskey Hub
やる必要のあること
32bit環境で動かすにあたって、以下の障壁をクリアする必要がある。
- i386用のNode.js Dockerイメージの準備
- prebuiltバイナリを用いるパッケージへの対処
@tensorflow/tfjs-nodeを使わないようにするsharpの依存ライブラリの手動ビルド
以下ではこれらの解決方法を解説する。
※ 構築手順のみを知りたい場合、完全な構築手順を参照
i386用のNode.js Dockerイメージの準備
Node.jsは公式でLinux x86をサポートしないため、Docker Hubの公式イメージにもlinux/386版は存在しない。 ただ、Node.jsの非公式ビルドでx86版が存在するため、 x86版Node.jsイメージを作ることは技術的には可能である。
この方法で作られたと思われる非公式のNode.jsイメージがBalena社から提供されているので、 今回はありがたくこれを使わせてもらうことにする。
balenalib/i386-node - Docker Image | Docker Hub
Misskeyの公式で使われている16.15.1-bullseyeもバッチリ存在している。 (ただし、slim版は無い模様)
@tensorflow/tfjs-nodeを使わないようにする
Misskeyはオプション機能としてNSFW画像の自動判定機能が存在し、Tensorflowを用いて実装されている。
TensorflowのNode.js用ライブラリである@tensorflow/tfjs-nodeはネイティブのlibtensorflowに依存しているのだが、
このlibtensorflowはx86をサポートしていない。
このため、今回はNSFW機能の利用を諦めて@tensorflow/tfjs-nodeのインストールを回避するようにする。
なお、Misskey自体は既に@tensorflow/tfjs-nodeをoptionalDependenciesに移動しているため、
本来はパッケージのインストール時に--ignore-optionalを指定するのみで済む筈なのだが、
実際のnsfwjsのpeerDependenciesを正しく扱っていないためこのままだと依存関係エラーで起動しなくなってしまう。
nsfwjsのpeerDependenciesに含まれているのは@tensorflow/tfjsであり、
これ自体はlibtensorflowに依存していないため、単純にdependenciesに追加すれば解決する。
sharpの依存ライブラリの手動ビルド
sharpはNode.js用の画像処理パッケージで、Misskeyではアップロードされた画像のリサイズ等に用いていると思われる。
このパッケージはネイティブのライブラリであるlibvipsに依存しており、
通常のインストールであればprebuiltバイナリが自動でダウンロード展開されるようになっているのだが、
x86の場合は手動でビルドした上でホスト上に直接インストールする必要がある。
(ビルド手順: Building libvips from source)
なお、Debianのリポジトリにもlibvips42というパッケージが存在するのだが、
こちらはバージョンが古く(これは8.10.5だが、sharpには8.11以降が必要)、
sharpのインストール時に必要なcmake関係のファイルも不足しているため、これを用いることは出来ない。
今回は、Docker上でlibvipsをビルドし、ninja installで直接インストールして使ってしまうことにした。
この際、libvipsの依存ライブラリを色々とインストールする必要があるのだが、
これに関してはDebian公式のlibvips-devおよびlibvips42の依存パッケージを参考にすることとする。
完全な構築手順
以下では、Misskey Hubで説明されていることも含めて一通りの構築手順を説明する。
パッケージの更新
まず、サーバーのパッケージをすべて最新にしておく(念の為)。
1$ sudo apt -y update
2$ sudo apt -y upgrade
3$ reboot
必要なツールの準備
Git, Docker等のツールが必要になるのでインストールする。
1$ sudo apt -y install git docker.io docker-compose
Misskeyのクローン
Misskeyは常にソースからビルドする必要がある。 このため、まずはGitHubからソースコードをクローンする。
1$ git clone -b master https://github.com/misskey-dev/misskey.git
2$ cd misskey
設定
.config内に設定ファイルを作る必要があるため、まずはサンプルファイルをコピーする。
1$ cp .config/example.yml .config/default.yml
2$ cp .config/docker_example.env .config/docker.env
次に、.config/default.ymlを以下のように編集する。
urlをhttp://localhost:3000/に変更dbのhostをdbに変更redisのhostをredisに変更
(docker.envにはDBのパスワードしか書いていないので、今回はとりあえずそのままで良い)
Dockerfileの編集
次に、イメージビルドのスクリプトファイルであるDockerfileを編集していく。
32bitのNode.jsを使う
FROMから始まる行(2箇所)を以下のように変更する。
1-FROM node:16.15.1-bullseye AS builder
2+FROM balenalib/i386-node:16.15.1-bullseye AS builder
3
4ARG NODE_ENV=production
5
6WORKDIR /misskey
7
8COPY . ./
9
10RUN apt-get update
11-RUN apt-get install -y build-essential
12+RUN apt-get install -y build-essential git
13
14# (中略)
15
16-FROM node:16.15.1-bullseye-slim AS runner
17+# slim版はないのでbullseyeをそのまま用いる
18+FROM balenalib/i386-node:16.15.1-bullseye AS runner
19
20# (略)
gitを追加でインストールしているのは、balenalib版のbullseyeイメージにgitが含まれていないためである。 (本家では含まれている模様)
libvipsをビルド・インストールする
以下のようにDockerfileを編集する。
1FROM balenalib/i386-node:16.15.1-bullseye AS builder
2
3ARG NODE_ENV=production
4
5WORKDIR /misskey
6
7COPY . ./
8
9+# libvipsのバージョンは、sharpで指定されているバージョンと揃える
10+# 確認先: https://github.com/lovell/sharp/blob/main/package.json#L157
11+ARG VIPS_VER=8.13.3
12
13RUN apt-get update
14-RUN apt-get install -y build-essential git
15+RUN apt-get install -y build-essential git python3
16+RUN apt-get install -y libjpeg-dev libtiff-dev libpng-dev libgif-dev \
17+ librsvg2-dev libpoppler-glib-dev gobject-introspection zlib1g-dev libfftw3-dev \
18+ liblcms2-dev libmagickcore-dev libmagickwand-dev libfreetype6-dev libpango1.0-dev \
19+ libfontconfig1-dev libglib2.0-dev libice-dev libimagequant-dev liborc-0.4-dev \
20+ libheif-dev libmatio-dev libexpat1-dev libcfitsio-dev libopenslide-dev libwebp-dev \
21+ libgsf-1-dev libgirepository1.0-dev bc meson
22+RUN curl -O -L https://github.com/libvips/libvips/releases/download/v$VIPS_VER/vips-$VIPS_VER.tar.gz \
23+ && tar xf vips-$VIPS_VER.tar.gz \
24+ && cd vips-$VIPS_VER \
25+ && meson setup build --prefix=/vips \
26+ && cd build \
27+ && ninja \
28+ && ninja test \
29+ && ninja install
30+RUN cp -r /vips/. /usr/
31RUN git submodule update --init
32RUN yarn install
33RUN yarn build
34RUN rm -rf .git
35
36FROM balenalib/i386-node:16.15.1-bullseye AS runner
37
38WORKDIR /misskey
39
40RUN apt-get update
41RUN apt-get install -y ffmpeg tini
42
43+RUN apt-get install -y libcairo2 libcfitsio9 libexif12 libexpat1 libfftw3-double3 \
44+ libfontconfig1 libgcc-s1 libgif7 libglib2.0-0 libgsf-1-114 libheif1 libimagequant0 \
45+ libjpeg62-turbo liblcms2-2 libmagickcore-6.q16-6 libmatio11 libopenexr25 \
46+ libopenslide0 liborc-0.4-0 libpango-1.0-0 libpangoft2-1.0-0 libpng16-16 \
47+ libpoppler-glib8 librsvg2-2 libstdc++6 libtiff5 libwebp6 libwebpdemux2 \
48+ libwebpmux3 zlib1g
49+
50+COPY --from=builder /vips/ /usr/
51COPY --from=builder /misskey/node_modules ./node_modules
52COPY --from=builder /misskey/built ./built
53COPY --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
54COPY --from=builder /misskey/packages/backend/built ./packages/backend/built
55COPY --from=builder /misskey/packages/client/node_modules ./packages/client/node_modules
56COPY . ./
57
58ENV NODE_ENV=production
59ENTRYPOINT ["/usr/bin/tini", "--"]
60CMD ["npm", "run", "migrateandstart"]
行数が多いが、ほとんどがlibvipsの依存関係のインストールである。 libvipsのバージョンは必要に応じて変更すること。
また、今回のDockerfileはマルチステージビルドを利用しており、
builderとrunnerの2つのコンテナを用いている。
libvipsはビルド時と実行時の両方で必要であるため、両方のコンテナにインストールする必要がある。
これを実現するため、一旦/vips/以下にインストールし、
builderとrunnerの両方で/vips/の内容をシステムにコピーするようにしている。
(マルチステージングビルドではファイルコピー以外でコンテナ間の連携が出来ないため)
依存パッケージの編集
tensorflowを依存関係から外すため、以下の作業を行う。
scripts/install-packages.jsの編集
tensorflowに依存しているのはpackages/backend内のモジュールであり、
これのパッケージのインストールはscripts/install-packages.jsで行われている。
このため、以下のようにしてyarn installに--ignore-optionalオプションを追加する。
1const execa = require('execa');
2
3(async () => {
4 console.log('installing dependencies of packages/backend ...');
5
6- await execa('yarn', ['--force', 'install'], {
7+ await execa('yarn', ['--force', 'install', '--ignore-optional'], {
8 cwd: __dirname + '/../packages/backend',
9 stdout: process.stdout,
10 stderr: process.stderr,
11 });
これにより、@tensorflow/tfjs-nodeがインストールされなくなる。
packages/backend/package.jsonの編集
先述の理由により@tensorflow/tfjsを明示的にインストールする必要があるため、
以下のようにpackages/backend/package.jsonを編集する。
1{
2 // (中略)
3 "optionalDependencies": {
4 "@tensorflow/tfjs-node": "3.20.0"
5 },
6 "dependencies": {
7 "@bull-board/koa": "4.2.2",
8 "@discordapp/twemoji": "14.0.2",
9 "@elastic/elasticsearch": "7.11.0",
10 "@koa/cors": "3.1.0",
11 "@koa/multer": "3.0.0",
12 "@koa/router": "9.0.1",
13 "@peertube/http-signature": "1.7.0",
14 "@sinonjs/fake-timers": "9.1.2",
15 "@syuilo/aiscript": "0.11.1",
16+ "@tensorflow/tfjs": "3.20.0",
17 "ajv": "8.11.0",
18 "archiver": "5.3.1",
19 "autobind-decorator": "2.4.0",
20// (略)
このとき、@tensorflow/tfjs-nodeと@tensorflow/tfjsのバージョンが一致するようにする。
イメージのビルド
ここまでの手順が完了したら、以下のコマンドで一旦イメージをビルドする。
1$ docker-compose build
ビルドが成功すると以下のような出力が出るはずである。
1Successfully built ce6afa9c901c
2Successfully tagged misskey_web:latest
もしビルドに失敗してしまった場合、変更点に誤りがないかをよく確認すること。 (特に要求されるlibvipsのバージョンは頻繁に変わる可能性があるため、きちんと書き換えられているかよく確認する。)
なお、イメージ何回かビルドし直すと不要なキャッシュが溜まっていくので、 再ビルド前に以下のコマンドでキャッシュを削除すると良い。
1$ docker image prune
サーバーの立ち上げ
ビルドに成功したら、あとはサーバーを立ち上げるだけである。
1$ docker-compose up -d
初回起動はデータベースのマイグレーションが走るため時間がかかるが、
しばらくするとサーバーが立ち上がるので、
http://localhost:3000/にアクセスして正常に動作しているかどうか確認する。