b-shock. Fortress

PostgreSQLのデータディレクトリに対し、ZFSのスナップショットを撮る

Mastodonの運用…に限らないけど、データベースのバックアップを取る必要がある。 pg_dump を行って rsync なりでリモートに送るのが簡単、実際その方法で1時間ごとに バックアップを取っていた。

Mastodonのデータベースを1年も運用すると、お一人様インスタンスでも1GB超のダンプファイルになる。
この大きさになると、1時間ごとに実行するのは困難。 1時間ごとに pg_dump を実行するお手軽バックアップ、1年にして破綻。
頻度を1日ごとに落とした。

個人的に、正規のバックアップは論理バックアップであるべきと考えており、この1日ごとの pg_dump は 辞められない。
一方で、今まで通りの1時間粒度のバックアップも、やはり続けたいと思っている。

それを実現するアイディアが、ZFSのスナップショット。
地雷運用と言われようとあえてFreeBSDを使い続けてきたが、その真価がついに。

以下の手順、全てroot権限にて。

マウントポイント

FreeBSDで通常のセットアップを行うと、PostgreSQLのデータディレクトリは /var/db/postgres の配下に 置かれるだろう。
ZFSのスナップショットはマウントポイントの単位で行われる為、このディレクトリを独立したマウントポイントに 分ける必要がある。

以下を実行すると、 /var/db/postgres既にあるファイルが削除される。
必要なら、それこそ pg_dump 等でバックアップしてから!

1
2
3
zfs create zroot/postgres
zfs set mountpoint=/var/db/postgres zroot/postgres
zfs set snapdir=visible zroot/postgres

zfstoolsを導入

スナップショットの保存、古いスナップショットの破棄、DBの一時停止等をひと通りやってくれる gemがある。
Mastodonインスタンスが置かれたサーバにRubyがインストールされてないはずはなく、 zfstoolsは以下の手順で導入可能。

1
2
gem install zfstools
zfs set com.sun:auto-snapshot=postgresql zroot/postgres

この手順で、 /usr/local/bin/zfs-auto-snapshot がインストールされる。

実行時ユーザーにsnapshot権限を付与

zfs-auto-snapshot は、OSのpostgresユーザーで実行するのが手っ取り早い。
このユーザーにはZFSのスナップショット作成の権限が与えられてない為、対応が必要。

1
zfs allow postgres snapshot zroot/postgres

wal_levelを設定

PostgreSQL側で、 wal_level を設定する必要がある。
/var/db/postgres/data96/postgresql.conf 等に以下追記。 (data96のところ、PostgreSQLのバージョンによって変わるから適用に読み替えて)

1
wal_level = replica

反映させる為には、恐らく再起動が必要。

1
service postgresql restart

スナップショットを撮る!

ここまでで準備終わり。以下のコマンドでスナップショットが撮れる。

1
sudo -u postgres /usr/local/bin/zfs-auto-snapshot hourly 24

実際の実行はcron等で。

おまけ

スナップショットの一覧を表示。

1
zfs list -t snapshot

誤って作りまくったスナップショットの破棄。

1
zfs destroy スナップショット名

Mastodon 2.5.0 @ FreeBSD

Mastodon 2.5.0がリリースされた。
FreeBSDで動作させるために必要な箇所、言い換えれば地雷が若干ある。

以下、FreeBSD 11.2での話ではあるけど、他のバージョンでも同様だと思います。

カスタムテーマ

いつものように、カスタムテーマが以前のものと互換性がない。
標準テーマから色を替えただけのものであるなら、作り直したほうが手っ取り早いです。

追記
これ、よく考えたらFreeBSDと関係ない話ですが。

ストリーミングAPIが動かない。

uwsが新しくなった為です。
これにFreeBSDのバイナリが含まれていない為、Mastodonでは動作しない模様。 2.4系で使われていた8.14.1ならば問題なし。

ためらうことなく、package.jsonを書き換え、 yarn upgrade しましょう!

貼れない画像がある。

「ある」などというレベルではなく、大半貼れない感じです。
日本語ファイル名が問題なのか、JPEGならよいのか。色々検証しましたが、全く切り分けできませんでした。

paperclipを6.1.0から 6.0.0に落とせば正常動作しますので、 ためらうことなくGemfileを書き換え、 bundle update ましょう。

所感

FreeBSDがハブにされてる感、はんぱないです!

パッケージのバージョンを落とす対応は有効と知りました。
これも修行なのです。自力解決しましょう!

mulukhiya-toot-proxy 1.2

しばらく間が空いたが、気にせず進行する流れw
一応、月ごとのアーカイブを途切れさせたくないとは思ってる。

書きたいネタはそれなりにあるのだけどね。
需要があるかはあんまり気にしてない。このブログの継続的な読者は多分いないのはわかってて、 たまたま同じことで困ってる人の問題解決を手伝えればよいという程度のもの。

本題。
拙作ツール mulukhiya-toot-proxyには ちょくちょく修正を加えており、先日1.2系という新バージョンをリリースした。

新バージョン事実上唯一の機能は、Mastodonでのトゥートにamazonの商品URLが含まれていた場合に、 商品画像を添付すること。
よって、Amazon Product APIへの対応を行う必要がある。

Amazon Product API

主にこちらを参考にした。

[Ruby] Amazon Product APIで商品検索してみた

特にトークンの取得等の手順が簡潔に説明されており、大いに助かった。感謝。

但し、今回必要なのは、事前にわかってるASINから商品画像のURLを引く機能。 記事の通りではなく若干アレンジが必要。

以下、要点のみ抜粋。

例外捕捉をしているのは、amazon側が割と頻繁に503を返すから。

この問題への対応は、単純にやり直すだけで問題なしと思ってる。 但し、このまんまじゃ無限ループになりかねないからw、回数の上限等を設ける必要は当然ある。
参考にしてる人がもしいたらw、各自対応よろしくです。

マルチパートなアップロード

Mastodonに画像をアップする際、マルチパート対応なHTTPクライアントが必要。 RubyではHTTPartyを好んで使ってましたが。 ひょっとして対応してないんじゃないですか?(調べが足りないだけかも)
HTTMultiPartyなるラッパーもあったが、最近メンテナンスされてないようだ。 普通に動きそうではあったけど、試してない。
メンテナンスされてないことを承知で使いたいひとはググってください。簡単に見つかるから。

結局、該当部分だけREST Clientなる クライアントで実装しました。
要点抜粋するとこんな感じ。

HTTPartyとREST Clientを意味もなく使い分けるのもアレだし、HTTPartyで実装された箇所をあとで REST Clientで書き直すかも。

以上、モロヘイヤにはこんな技術(というほど大層ではない)が使われているのでございます。

新しいMastodonの周辺ツール "mulukhiya-toot-proxy" の紹介

mulukhiya-toot-proxyという新しいツールを書いたので、そのご紹介。
縮めて「モロヘイヤ」とお呼び頂ければ。

mulukhiya-toot-proxy

通常はMastodonインスタンスと同じサーバにインストールし、Mastodon本体と並列に配置。 nginxのリバースプロキシを通して利用する。

Mastodonへのトゥート(/api/v1/statuses リクエスト)を横取りし、以下の改変を行って Mastodonに送り直す。


日本語を含むURLを適切にエンコードする。

ホスト名、パス、クエリー等に日本語を含むケースが該当。
この処理によって、各種クライアントでそのURLがクリックできるようになる可能性がある。 (人が作ったクライアントがどんな動作を動作するかまでは保証できない。だから「可能性」w)

各種短縮URLを元に戻す

この処理により、怪しい短縮URLのリンク先が明らかになる。
意図せず貼り付けてしまったt.coのリンク等も元通り。

アマゾンの商品URLから必要な部分だけを残し、他を全て削除

アマゾンの商品URLはSEO対策の為か、日本語の商品名を含んだ非常に長いものになるケースが多い。 ご存知の方も多いだろうが、シェアには不向き。
トゥートに無加工でコピペしてしまった場合にも、必要な部分だけを残して、他を全て削除する。


これらの処理は、nginxがトゥート要求を受け取ったあとに実行される。 Webクライアント以外のクライアント(BOT等)であっても、 /api/v1/statuses を利用する 全てのトゥートに適用される。

興味をお持ちの方は、リンク先をご覧頂ければ。
そして、もし使ってくれるなら★をつけてくれるとうれしいです。 よろしくお願いします!

XubuntuをOpenVPNクライアントに。(Xubuntu 18.04)

訳あって、GPD PocketをOSインストールから再構築した。
この話は近々するとして…。OpenVPNクライアントにする手順が若干変わっていた様だったので、 以前の記事と重複する内容も含め、改めてまとめておく。

パッケージの導入

1
sudo apt install openvpn

以前必要だったtunneldiggerは不要!
このツール、Ubuntu 18.04のリポジトリに含まれなくなったが、理由をやっと理解した。 そもそも要らなくなったのだ。

設定

1
2
cd /etc/openvpn
sudo cp ~/Dropbox/Documents/OpenVPN/bshock.ovpn ./client.conf

設定ファイルはDropboxに既に置いてあったので、そこから拝借してる。
内容は大体こんな感じ 。

接続・終了

  • VPN接続
1
sudo service openvpn start
  • VPN切断
1
sudo service openvpn stop
  • VPN再接続
1
sudo service openvpn restart

ふつうに apt install openvpn すると常時つなぎっぱの設定になり、通常用途ではそれ以上は することないのでは。
テザリング時やサスペンドからの復帰時等、起動後にネットワーク環境が変わった時は再接続を行う。

ログ設定

ここまでで一応終わりだけど、ログを見やすくするには、以下のような設定をすると いいんじゃないだろうか。

まず、/etc/rsyslog.d/openvpn.confをこんな感じで書く。

続いて、/etc/logrotate.d/openvpnをこんな感じで。

rsyslogやlogrotateについては、詳細は割愛。

トゥートをCWに変える

その後構築したものがいくつかあり。
これらの作業ログも記事にしたいのだけど、なかなか時間がない。
今月ぐらいに上げられるといいなぁ。

今日のやつはそんなに大層なものではなく、小ネタです。
想定する読者さんは、SQLがちょっとだけわかってpsqlコマンドも扱える、 Mastodonのインスタンスを持っている管理者さん。

ネタバレを含んだ含んだトゥートをCWにする。

プリキュアのテーマインスタンス「キュアスタ!」に、いつも お世話になっている。
このようなテーマインスタンスでは、概ね「ネタバレを含むトゥートにはCWを」という 推奨がある。先日唐突に「一度送信したトゥートをCWに変えることも可能なはず」と 思い立って、軽く調べてみた。

この時点では純粋な技術的な好奇心であり、「あとからCW」の是非については一旦保留 する。これについては後ほど。

PostgreSQLに接続

手っ取り早く、 psql コマンドを叩いて試す。
FreeBSD環境でデフォルト設定でセットアップがされているなら、以下のコマンドで Mastodonのデータベースに接続できる。

1
sudo -u postgres psql mastodon

直近のトゥートを探す

CWにする対象のトゥートを特定する。
連合のトゥートを排除してローカルのトゥートのみ残し、せいぜい10件も取得すればよいのでは ないか。

1
2
3
4
5
6
7
8
9
10
11
SELECT
id, -- トゥートID
created_at, -- 投稿日
text, -- トゥート本文
spoiler_text, -- CWタイトル
sensitive -- 本文を隠すか?
FROM statuses
WHERE
local='t'
ORDER BY updated_at DESC -- 更新日降順
LIMIT 10 OFFSET 0; -- 先頭10件

目的のトゥートを見つけたら、トゥートのIDを控えておく。

トランザクションを利用しつつ更新

1年運用しているが、Mastodonのデータベースを直接更新するなんて、経験のないこと。
理由がなければやるべきじゃないし、いつでもロールバック出来る様な備えをするに越したことは ない。
もしステージング的な環境を持っているなら、そちらで試してほしい。

早速、トランザクションを開始。

1
BEGIN;

次に、実際の書き換えを行う。

1
2
3
4
5
6
UPDATE statuses SET
spoiler_text='ネタバレ注意なのです!ストーップなのです!',
sensitive='t', -- 「隠す」フラグを立てる
updated_at=now() -- 更新日付を現在時刻に
WHERE
id='00000'; -- 先程控えた、トゥートのID。絶対忘れちゃダメw

結果反映を確認

トランザクション中の更新である為、この時点ではMastodonの画面に反映しない。
画面上で確認できないので、更新の結果を確認するには、この場でSELECTする必要あり。(以下)

1
2
3
4
5
6
7
8
9
SELECT
id, -- トゥートID
created_at, -- 投稿日
text, -- トゥート本文
spoiler_text, -- CWタイトル
sensitive -- 本文を隠すか?
FROM statuses
ORDER BY updated_at DESC -- 更新日降順
LIMIT 100 OFFSET 0; -- 先頭100件

先ほどとほぼ同じだが、意図しない書き換えが行われていないか確認するために、以下の修正を行った。

  • WHERE句を削除。
  • 件数を100軒に増やす。

トランザクションの終了、又は破棄

意図通りの更新であれば、

1
COMMIT;

を実行すれば、この時点でMastodonの画面に反映。
「キャッシュのクリア」的な処理が必要かと思ったが、そうでもなかった。 おれが普段作っているものより素直な作りだなw。わかりやすくてよい。
反映を確認できた?

万一、期待した結果と異なっていたら、

1
ROLLBACK;

を実行。

「あとからCW」の是非

先ほど、「一旦保留」と言った件。

まず、技術的な観点から、やむを得ない場合のみにするべき。間違っても、これを前提にした 運用はやめたほうがいい。
DBの詳細な説明、どこかにあった?もしあるなら(どこかにあるのをおれが知らないだけかも)、 それを熟読精査した上で実行するのは、まずは技術的にはOK。

コミュニティとしてどうなのか?という問題も。
発言を容易に書き換えたり出来ると、そもそも会話が成り立たない。 出来ることならするべきではないし、仮に行うのでも、この点を念頭に置くべき。
CWは…、まぁ微妙か。会話が成り立たなくなる種類の修正ではないし。

ネタバレ禁止というのも、「推奨事項」程度のものと思っていて。
本人から「これCWにしたいんですけど〜」的な申し出があったら初めて動くぐらいで、 大抵は十分なのではないか。と、個人的には思う。

以上。

Slack互換、トゥート用webhookを提供する小物ツール

拙作ツール tomato-toot を、バージョン2.0.0に アップグレードした。
Slack互換のAPIでトゥートが行えれば便利なのでは?というひらめきから、 急遽サーバモードを実装。 Slackだけでなく、webhookの仕様がSlackとそっくりなDiscord形式にも対応。

Slackにアラートを投げるツールは、きっと世にたくさんある。
手前味噌だが、拙作のものだとonionbot等も該当。 Chinachuでの録画開始・終了をトゥート出来る様になるという寸法。

BOTを設置してよいかはインスタンスの規約に従い、できれば管理人さんに許可ももらいましょう。
ご興味の向きはお試しの上、もしよかったら★つけてくださいw どうぞよろしく。

Xubuntu 18.04

Ubuntu 18.04 LTSがサーバ、デスクトップともリリースされ、順次更新していた。
愛用しているXubuntuも数日後にリリースされ、先ほど更新を適用した次第。

基本的な更新の手順

Ubuntu Server、Xubuntu共に、

1
sudo do-release-upgrade -d

で更新が可能。
-d をつけると、安定版だけでなく、開発中のものも更新先の対象になるらしい。
通常の用途で利用することは一見なさそうだが、何日経っても18.04へのアップグレードが 出来ず、やむを得ず -d をつけて実行した次第。 調べたが、 -d を使用するのは割と 一般的なセオリーではある様だ。

6環境試したうち1つだけ、更新が途中で止まったものがあった。
このようなことが稀にあるため do-release-upgrade をリモートで実行するのは慎み、 例えその必要がなくとも、極力実機の前で行う様にしようという話だと思う。

Ruby 2.5

sudo apt install ruby ってやったときに入るRubyのパッケージが、最新の2.5系になった。 ChefもSnesuも拙作のものも、相当数のツールがRubyで実装されており、影響は大きい。

通常であれば、

1
2
3
sudo apt-add-repository ppa:brightbox/ruby-ng
sudo apt update
sudo apt install ruby2.5

などとやる必要があったところ、今のところは最新の2.5がインストールできるため不要。
ただ、次のLTSが出るのは2年後。この頃まで2.5系のまま変わらない可能性は十分にあり、 brightbox/ruby-ngにお世話になる機会はまたいずれありそう。

CommandキーをCtrlキーにする

ここからは、MacBook Air 11に特化したXubuntuについての話題。

18.04にアップグレードすると、setxkbmapの設定が飛んでしまう。
過去記事に書いた通り の手順で復旧できる為、面倒だが再度実行。

トラックパッドの2本指スクロールの向きを上下逆に

これも過去記事と 同じ手順で再設定可能。

基本的な考え方は同じだが、今まで

1
xinput set-prop 12 287 -200 -200

だったところ、

1
xinput set-prop 12 288 -200 -200

に変更する必要はあった。

以上。

FreeBSD MySQL 5.7

FreeBSDでは訳あってMySQL 5.6を使っていたが、この度順次5.7への更新を始めた次第。

MySQLのアップグレード

以下実行。

1
2
3
4
5
6
su
service mysql-server stop
pkg install mysql57-server
service mysql-server start
gem install mysql2
mysql_upgrade -u root -p

mysql_upgradeのあとは、今までのrootパスワードを入力。
rootパスワードは変更はされていないので、安心していい。

ちなみに、インストール後にこんなメッセージが表示される。

1
2
3
4
5
6
7
Initial password for first time use of MySQL is saved in $HOME/.mysql_secret
ie. when you want to use "mysql -u root -p" first you should see password
in /root/.mysql_secret

MySQL57 has a default %%ETCDIR%%/my.cnf,
remember to replace it wit your own
or set `mysql_optfile="$YOUR_CNF_FILE` in rc.conf.

ふむなるほど。
新規導入の時は、 /root/.mysql_secret を読めという話ですな。

それにしても、以前5.6から5.7への更新を行った時は、InnoDBがそのままでは使えなかった。
どうやらSQLダンプからの再インポートが必要だった様だが、その後のバージョンアップで 改善されたのだろうか。

PowerDNSも使用している場合

PowerDNSをMySQLをストレージとして運用する場合、pkgコマンドからではなくportsから makeする必要がある為、MySQLをアップグレードした場合にはPowerDNSの再ビルドが必要。

また、portsからmakeする場合は、pkgコマンドから上書き出来ない様にロックするのが 普通と思う。
以下実行。

1
2
3
4
pkg unlock powerdns
portupgrade -f powerdns
pkg lock powerdns
service pdns restart

当方、portupgradeを使用している為に上記のような手順になってるけど、 他ツールをご利用の向きは読み替えて頂きたい。

PowerDNSの起動後、syslogに以下の様なログが出てればOK。

1
gmysql Connection successful. Connected to database 'pdns' on 'localhost'.

以上。

Dovecot 2.3への更新

FreeBSD Portsのdovecotパッケージが、2.3.1に更新された。

設定ファイルの書き換えが若干必要。
今どき、自分でPOP3/IMAPサーバを立てる需要がどれほどあるかは知らんけどw

ssl_protocolsディレクティブを削除

設定ファイルに以下の様な記述があったはずと思うけど。

1
ssl_protocols = !SSLv2 !SSLv3

ssl_protocols は非推奨になった。 加えて、 SSLv2 という値は廃止された。 (SSLv3 もついでに廃止して良かったはずと思うが)

同様の意味であれば、今後はこう書けとのこと。

1
ssl_min_protocol = TLSv1

この TLSv1 以上という指定は ssl_min_protocol の記述自体がないときのデフォルトだが、 書かれていないとWARNINGが出るので、明示的に記述するべき。

DHパラメータの設定

パッケージのインストール後に /var/db/dovecot/ssl-parameters.dat があることを確認し、 以下実行。

1
dd if=/var/db/dovecot/ssl-parameters.dat bs=1 skip=88 | openssl dhparam -inform der > /usr/local/etc/dovecot/dh.pem

実行後、設定ファイルに以下追記。

1
ssl_dh=</usr/local/etc/dovecot/dh.pem

これで ssl_dh に関するWARNINGは出なくなる。
service dovecot restart を実行。

設定ファイル全体

以上をふまえ、今個人的に使ってるのはこんなやつ。

plainやloginを許している以上、そろそろ非TLSの接続は廃止するべきだな。
(一応、認証の連続失敗で1週間のロックはしてる)