環境

Mastodon 2.3.3

やったこと

元々、mastodon.example.com で運用していた(アカウント名は hoge@example.com)

(要するに、.env.production で WEB_DOMAIN を指定してアカウント名と実際マストドンにアクセスする URL を変えていた)

いくつかのクライアントが、返信する際に、 hoge@mastodon.example.com と書いて返信して

しまうようだったので、マストドン自体の URL も example.com でアクセスできるように、

WEB_DOMAIN の指定を消したところ、トラブルに遭遇した。

現象

トゥートを行うと、SideKiq の push ジョブが失敗して、retry キューに溜まってしまう。

現象はこの Issue の通り

https://github.com/tootsuite/mastodon/issues/6667

対処

基本的には、対処方法はありません。元に戻すしかありません。。

しかも、URL 変更中に作成されたアカウント、かつ他インスタンスに登録されてしまうと、

戻したとしても新しいアカウントについて同じことが発生してしまいます。

しかし、Issue を見ると、他のインスタンスに既に登録されたアカウントと、URL の対応を変更する事ができず

アカウント名重複エラーとなっているようなので、自インスタンス側の全てのアカウントを作り直すことで

対応できます。(今回はほぼお一人様インスタンスだったので、こちらを選択しました)

蛇足

アカウントと URL の対応の変更、下手に出来ちゃうとアカウント乗っ取りが可能になりかねないので

なかなか難しいのでしょうね。

追記

2.8 くらいで、ユーザーを作り直す的なコマンドが toot-ctl に追加されているので、この記事の内容は古いかもしれません。

本稿のスコープ外

  • Kubernetes(以下 k8s)クラスタの構築方法
  • Mastodon の初期設定
  • kustomize のインストール

※ 多少読み替えて頂ければ、docker ではない Mastodon も移行できるはず

前提条件

  • kubectl が実行可能なこと
  • kustomize が使用可能なこと
  • 以降元 docker コンテナのファイルを持ってこれること

作業手順

実は移行自体はそれほど難しくありません。
移行が必要なのは、PostgreSQL の DB だけです。redis のデータも移行した方がよいですが、
移行しなくてもその時点の Sidekiq のジョブが失われる程度で、恐らく誰も気づきません。
※ 管理者的には、Sidekiq 画面のジョブ数がリセットされるのが残念かな?程度

kubernetes クラスタ上に Pod を生成

Deployment 定義を github に公開しています。

https://github.com/yakumo-saki/k8s-mastodon-deployment

私のインスタンスは、Glitch Edition なので Docker イメージ名が違いますが、基本的に
公開している Deployment をそのまま使用しています。
複数インスタンス持ちなので、myinstance をコピーして foundation としました。
myinstance/kustomize.yaml は以下のように書き換えました。

1
2
3
4
5
6
7
8
9
10
11
namePrefix: myinstance-       # Pod名の先頭にmyinstance- をつける
commonLabels:
app: myinstance

resources:
- ../base
configMapGenerator:
- name: config
env: env.production
files:
literals:

env.production ファイルは稼働中のインスタンスからそのまま持ってきます。

その上で、DB_HOST REDIS_HOST を変更します。

base/kustomization.yaml 変更

DB を戻し終わるまでは、Web, Streaming, Sidekiq には起動して欲しくありません。

そのため、一時的に ./base/kustomization.yaml を変更します。

1
2
3
4
5
6
7
8
9
10
11
12
13
resources:
- db-service.yaml
- db-pvc.yaml
- db-statefulset.yaml
- web-sidekiq-pvc.yaml
- redis-service.yaml
- redis-pvc.yaml
- redis-deployment.yaml
#- web-service.yaml ここから下をコメントアウト
#- web-deployment.yaml
#- streaming-service.yaml
#- streaming-deployment.yaml
#- sidekiq-deployment.yaml

ここまでできたら、

myinstance ディレクトリで

1
2
3
4
$ kustomize build | kubectl apply -f -

configmap/myinstance-config-4dm8g6h6gm created
(略)

移行元インスタンス停止

(リハーサルなら止めなくてよい)
DB と Redis コンテナ以外 を停止します。

DB, redis バックアップ取得

1
2
3
4
5
6
7
8
# 移行元インスタンスのdockerが動いてるところで
$ docker exec mastodon_db_1 pg_dumpall > pg_dumpall.sql

# このコマンドはredisへのアクセスが停止します。(短時間ですが)
$ docker exec mastodon_redis_1 redis-cli save
OK

$ docker cp mastodon_redis_1:/data/dump.rdb .

pg_dumpall.sql dump.rdb ファイルは、kubectl を使用可能な PC にコピーしておいて下さい。

DB バックアップを k8s 上の DB に戻す

1
2
3
4
5
6
7
8
9
10
$ kubectl cp pg_dumpall.sql myinstance-db-0:pg_dumpall.sql

$ kubectl exec -it myinstance-db-0 sh
$$ psql
root=# \i pg_dumpall.sql
(どばっと、DUMP取込のログが出る)
root=# quit

# SQLファイルを消しておかないとサーバーの容量を食うため(コンテナ再起動で消えますが)
$$ rm pg_dumpall.sql

Redis バックアップを k8s 上の DB に戻す

redis のバックアップは、 /data/dump.rdb を上書きするだけです。
しかし、一つ落とし穴があります。 それは、redis 稼働中に dump.rdb を上書きしても、
redis をシャットダウンする際に上書きされるという罠です。
なので、一旦 redis-server を起動しないようにします。

./base/redis-deployment.yaml を編集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class="language-yaml:./base/redis-deployment.yaml">(略)
containers:
- name: redis
image: redis:5.0-alpine
command: ["tail", "-f", "/dev/null"] # この行追加(またはコメントアウト解除)
resources:
requests:
memory: "16M"
livenessProbe:
# exec: # ここをコメントアウト
# command:
# - redis-cli
# - ping

(略)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ kubectl get pod して、 myinstance-redis-* のpod を探す。
$ kubectl cp dump.rdb myinstance-redis-xxxx:dump.rdb_new

$ kubectl exec -it myinstance-redis-xxxx sh

$$ ps aux
PID USER TIME COMMAND
1 root 0:00 tail -f /dev/null # redis-server が動いていないことを確認
52 root 0:00 sh
72 root 0:00 ps aux

$$ ls -lh
-rw-r--r-- 1 redis redis 92 Aug 16 05:06 dump.rdb
-rw-r--r-- 1 501 dialout 5.3M Aug 16 05:28 dump.rdb_new # 所有者が違う!

$$ cp dump.rdb_new dump.rdb
$$ chown redis.redis dump.rdb

一時的に変更した設定ファイルの復元

  • 編集した ./base/redis-deployment.yaml を元に戻します。
  • 編集した ./base/kustmization.yaml を元に戻します。

元に戻したら、いよいよ起動を行います。

1
kustomize build | kubectl apply -f -

動作確認

とりあえず、 curl [外向きのIP等]:3000 して何かが帰ってくれば OK とします。

リバースプロクシの設定変更

動作確認ができたら、リバースプロクシの設定を変更しましょう。

積み残し

favicon

マウントしないといけないのですが、本稿では色々と事情があり割愛しています。

蛇足

.env.production じゃなくて env.production にリネームしたのなんで?

.env.production だと ls したときに表示されないからです。 ls -a すれば見えますが。

個人的に見えないファイルが重要っていうのはあんまり好きではないので。。単純に好みですね

Qrunch さんがサービス終了されてしまうそうなので、自前で Ghost をホストすることにしました。データの移行はまだ終わっていませんが、ぼちぼちやっていきます。

ちなみに、オンプレミスの kubernetes クラスタ上で動作しています。

URL を本番用のものに変えた時にリダイレクトループになってしまってかなり焦りました。

https://ghost.org/faq/change-configured-site-url/

ぐぐったら思いっきり FAQ でした。リバースプロキシが入っているのでヘッダをセットする必要があったという凡ミス。

nginx の設定ファイルに以下を追記するとうまく行きます。

1
2
3
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

変更履歴

  • 2019/09/13 初稿。 kubernetes 1.15.3
  • 2019/09/26 storageclass.yaml の resturl についてを追記。

requirements

  • 3 台以上のノード(1 台でも 2 台でも動くのですが、1 台だとありがたみが薄い、2 台だとスプリットブレインの可能性)
  • それなりのディスク容量とディスクを GlusterFS のノードに割り当て済みであること。(パーティションでもいけそうに思えるが未検証)

準備

最後のデプロイスクリプトが、deploy ディレクトリの構造に依存している為、ディレクトリ名の変更等は

してはいけません。また、以下のファイル類は kubectl コマンドが使えればどのマシンに置いてあっても問題なさそうですが、

一応、kubernetes の master ノードで行いました。

各ノードの準備

/etc/modules-load.d/glusterfs.conf というファイル名で、GlusterFS の全ノードに以下の内容のファイルを配置します。

再起動ができれば再起動が一番良いですが、とりあえず modprobe でロードしてもよいと思います。

この作業は、GlusterFS のノード全てで必要です。(大事なので強調)

1
2
3
dm_snapshot
dm_mirror
dm_thin_pool

clone

まずは、以下のリポジトリを clone します。ZIP でダウンロードでも OK です。

https://github.com/gluster/gluster-kubernetes/

使用するのは、deploy ディレクトリ以下のみなので、以下 deploy ディレクトリを基準に説明します。

topology.json の準備

topology.json.sample をコピーして topology.json とします。

内容は sample を見て頂いた方が早いと思います。

gk-deploy スクリプトの修正

最近の kubernetes で変更になったオプションが使われている為、以下の issue の内容に従って gk-deploy を書き換えます。

具体的には、 --show-all を検索して、削除して下さい。

https://github.com/gluster/gluster-kubernetes/issues/582

1
2
3
4

#heketi_pod=$(${CLI} get pod --no-headers --show-all --selector="heketi" | awk '{print $1}')

heketi_pod=$(${CLI} get pod --no-headers --selector="heketi" | awk '{print $1}')

構築

gk-deploy スクリプトの実行

gk-deploy スクリプトを実行します。失敗に備えて、一度本記事を最後まで読んでからやることをおすすめします。

1
2
3
4
5
6
7
./gk-deploy -gv -w 600 --admin-key admkey --user-key usrkey

-g クラスタを新しく構築する
-v ログ出力を多めに
-w podが起動するまでの待ち時間。デフォルト300秒だが、当方の環境ではタイムアウトが発生した。
--admin-key 管理者用パスワード(と思われる)
--user-key ユーザー用パスワード(と思われる)

storageclass の apply

gk-deploy が成功すると、最後に、storageclass.yaml の内容が表示されます。

後で apply するので、 storageclass.yaml のような名前でファイルに保存して下さい。

表示される内容が誤っている場合があるので、 resturl: の指定が正しいことを確認して下さい。

resturl は、PV を確保する際に使用する heketi の API エンドポイントのアドレスです。

heketi はスクリプト内で自動的にデプロイされています。

エンドポイントは Service から取得することができます。具体的には以下です。

heketi_Endpoint 取得

1
2
3
4
$ kubectl get svc heketi
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
heketi ClusterIP 10.99.248.111 <none> 8080/TCP 15m
~~~~~~~~~~~~~ ~~~~

これで取得した IP アドレスとポートが、 storageclass.yaml 内に指定されているか確認して下さい。

当方が実行した際は、誤った値が表示されていました。

storageclass.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: glusterfs-storage
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://10.99.248.111:8080" <= heketi の serviceから取得可能
# restuser: "user" <= gk-deployはuserを指定しているのですが、
# restuserkey: "usrkey" <= adminに書き換えないと動きませんでした。
restuser: "admin"
restuserkey: "admkey"
reclaimPolicy: Retain <= 個人的好みです。PV削除時に物理削除されなくなります。
allowVolumeExpansion: true <= PV拡張を許可する

ここまで確認したら、 kubectl apply -f storageclass.yaml で StorageClass を生成して完了です。

(必要であれば) 作成した StorageClass をデフォルトに指定する

PVC を作成する際に、StorageClass 名を指定すれば良いのですが、省略された際にこの StorageClass が使用される

ようにする為には、default に指定する必要があります。

1
kubectl patch storageclass glusterfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

適用されたかどうかは以下のコマンドで確認できます。

1
2
3
4
> kubectl get sc
NAME PROVISIONER AGE
nfs nfs-client/nfs-ssd 42d
glusterfs-storage (default) kubernetes.io/glusterfs 37m <= (default) がついた

蛇足

失敗時のやりなおし

この記事はここが書きたいので書きました。

1
./gk-deploy -gv -w 600 --admin-key admkey --user-key usrkey --abort

末尾に --abort をつけるとやり直しができますが、途中でディスクに対して変更を行ってしまっている場合、abort しても

成功しません。 全ノードの topology.json で指定したディスクに対して wipefs --all /dev/sdb のように

各種シグネチャを削除する必要があります。

ありますが・・・ 恐らく、resource busy と言われて失敗するかもしれません。

その場合、一度ディスクをデタッチしてから再度行うと上手く行くと思います・・・が、恐らく、デバイス名が変わってしまいます。

最終的には再起動しかありません。(むしろご存じでしたら教えて下さい)

前書き

チェックリストは以下の通り。 上から順にチェックすると良いです。

なお、本文書は SpringBoot 1.2 ~ 1.4 の頃に書かれたものです。2.x になると少し事情が変わるかもしれません。

(2019/04/09 あまりにもそっけない文書だったので肉付け&改訂)

static 変数

@Autowired したいフィールドが static の場合、インジェクションされません。

static を外しましょう。

@Component の付け忘れ

@Autowired したいクラスに、 @Component がついていないと部品として認識されません。

ついてなければつけてみましょう。

ただし、これで直らなかった場合は別のアノテーションが @Component 相当の認識をされている

可能性が高いので元に戻しておきましょう。(害がない場合が多いと思いますが)

例えば、 @Service @Repository が既についているのであれば、部品として認識されるはずなので

@Component をつけても解決しません。

@Component されたクラスが @ComponentScan の範囲外

@SpringBootApplication がついたクラスのパッケージとその配下のパッケージは自動的にスキャンされます。

しかし、それ以外のパッケージに存在するクラスは部品探索範囲外なので、部品として認識されません。

解決方法としては、

  • 問題のクラスを、 @SpringBootApplication のパッケージ(配下含む)に移動する
  • @SpringBootApplication のついたクラスに、 @ComponentScan("パッケージ") を追加する

@Autowired したいクラスは、 @Component ではない

@Component ではないクラスは Spring の管轄外なので @Autowired は効きません。

@Component されたクラスの名前が他と重複している

Springboot 等の依存ライブラリ内の部品と名前が重複している場合、無視される場合があります。

試しにクラス名を変えると上手くいくかもしれません。(正確には無視というより優先順位問題)

特に一般的な名前をクラスにつけたクラスのみが当てはまる場合、試してみる価値はあります。

ダメだった名前の例) Environment

ご参考情報

@ComponentScan の書き方例

1
2
3
4
@ComponentScan(“org.example.somepackage”)
@SpringBootApplication
public class SpringBootApplication implements CommandLineRunner {
// (略)
1
2
// この書き方は古いかもしれない
@ComponentScan(basePackages = {"com.example.pkg1","com.example.pkg2"})

debian 10

boot from debian 10 ISO

<Installer GUI>

  • Lang English
  • location other - Asia - Japan
  • locale en_US.UTF-8
  • keymap Japanese
  • network conf eth0
  • hostname kubeworker3
  • root password
  • user account

disk partition

  • use entire disk (NO LVM)
  • delete swap and expand ext4
  • without swap , go back ? -> No
  • write changes ? -> Yes
  • mirror -> Japan deb.debian.org
  • proxy -> none
  • popularity-contest -> yes

Software

  • uncheck ALL
  • check ssh server
  • check standard system utilities

installation complete

after boot

from console

login as user

  • su -
  • apt install sudo vim
  • gpasswd -a username sudo
  • vi /etc/network/interfaces
1
2
3
4
5
iface eth0 inet static
address 192.168.10.x
netmask 255.255.255.0
gateway 192.168.10.1
dns-nameservers 192.168.10.1
  • reboot

ssh

  • ssh-copy-id 192.168.10.x
  • ssh 192.168.10.x
  • sudo apt install nfs-common

backport kernel

  • echo “deb http://deb.debian.org/debian buster-backports main contrib non-free” | sudo tee /etc/apt/sources.list.d/backports.list
  • sudo apt -t buster-backports install linux-image-amd64
  • sudo reboot

install containerd

https://kubernetes.io/ja/docs/setup/production-environment/container-runtimes/

  • sudo su -
  • apt install gnupg2
  • apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common
  • curl -fsSL https://download.docker.com/linux/debian/gpg“ | apt-key add -
  • add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable”
  • apt-get update && apt-get install -y containerd.io
  • cat > /etc/modules-load.d/containerd.conf <EOF
    overlay
    br_netfilter
    EOF
  • cat > /etc/sysctl.d/99-kubernetes-cri.conf <EOF
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    EOF
  • sysctl –system
  • mkdir -p /etc/containerd
  • containerd config default > /etc/containerd/config.toml
  • systemctl restart containerd

install kubeadm

  • sudo su -

  • cat < /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF

  • sudo apt-get install -y iptables arptables ebtables

  • sudo update-alternatives –set iptables /usr/sbin/iptables-legacy

  • sudo update-alternatives –set ip6tables /usr/sbin/ip6tables-legacy

  • sudo update-alternatives –set arptables /usr/sbin/arptables-legacy

  • sudo update-alternatives –set ebtables /usr/sbin/ebtables-legacy

  • sudo apt-get update && sudo apt-get install -y apt-transport-https curl

  • curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

  • cat <EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
    deb https://apt.kubernetes.io/ kubernetes-xenial main
    EOF

  • sudo apt-get update

  • sudo apt-get install -y kubelet kubeadm kubectl

  • sudo apt-mark hold kubelet kubeadm kubectl

  • reboot

join

  • kubeadm token create –print-join-command
  • kubeadm join 192.168.10.x:6443 –token aaaaa.2on657o4347ka7lp –discovery-token-ca-cert-hash sha256:efe45c57b63e7d19b41f6262e0bd2fb1bae5f0f80b002d9d9448adc8725a8cc1

はじめに

Knockout.js 3.3.0 を使い始めて数週間ですが、
とりあえずハマった事をメモします。

Mapping

JSON から Knockout の Observable を作ってくれる便利なプラグインですが…

ko.toJSON するといらないものが付く

ko_mappings みたいなのが付いてしまう。

→ ko.mapping.toJSON を使う必要がある。

Editables

編集のロールバックや、変更されたか否かを自動で判定してくれる便利なもの。

ko.editable(hoge) すると hasChanges が追加されてしまう

ko.mapping.toJSON したときに余計なプロパティが

付いてしまう。(で、例えば Java とか型の固い言語に JSON 化して引き渡すと hasChanges を

解釈できずにコケる)

→ どうにもならないので、ko.mapping 側の ignore に追加する。hasChanges という名前をフィールドに使えなくなるが仕方が無い(editable 使う時点で使えないし)

http://knockoutjs.com/documentation/plugins-mapping.html

1
ko.mapping.defaultOptions().ignore = ["hasChanges"];

observableArray に subscribe したは良いけど、変更が通知されない

→FAQ らしい。observableArray は中身について一切関知しない。

なので、追加/削除の時しか通知は来ない。

see: http://kojs.sukobuto.com/docs/observableArrays

・・・でもこれ、直感的な動作とは言いがたいような気がする。

じゃあ中身の変更を知りたい時は?

ObservableArray の中身のプロパティを、ko.observable で定義して(ko.mappings 使えば自動)

Array 内の全てのオブジェクトの、必要なプロパティに Subscribe すれば良い。

Subscribe するときは、次の項目の通り、 this に束縛する値に都合のよいものを指定する。

Subscribe したは良いけど、変更されたオブジェクトがハンドラに渡ってこない!

Subscribe するときの第二引数で、ハンドラの this に束縛する値をセットする必要がある。

Subscribe をやめたい

Subscribe した時に返ってくるオブジェクト.dispose() すれば OK。

1
2
3
4
5
6
7
ko.utils.arrayForEach(array.items(), function (item) {
var subscribe = item.value.subscribe(function (newValue) {
// 変更されたときのハンドラ
}, item); // 第二引数にちゃんと対象オブジェクトを指定しておく

subscribe.dispose(); // subscribeやめる
});

observableDictionary が Subscribe できない

実装されてないのでどうにもならない模様。私は諦めた。

ただし、中身は普通に Observable なはずなので、subscribe できるはず。

$root は出来るだけ使わない

ViewModel 一個で画面を作っている場合、$root = $parent となるのが大半でしょう。

この時、できるだけ $parent で指定しておいた方が良いです。

後々、画面が複雑化してきて、複数 ViewModel に分割した場合(以下例参照)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 例えばこんな感じです
var viewModel = new MainViewModel();
var subModel = new SubViewModel();
ko.applyBindings({
main: viewModel
, sub: subModel
});

// HTML内
<div id="main" data-bind="with: main">

</div>
<div id="sub" data-bind="with:sub">
略略
</div>

元々$root で取得していたものは $root.main で参照するようになります。

$rootを使っている箇所、全て書き直しになってしまうので、$parent を

できるだけ使う事をおすすめします。というより、$root を使わないといけないことは

滅多にないはずです。

→2015/08/30 追記

そもそも、大きく囲んだ要素に data-bind=”with: main” と書いてあるのであれば

main の viewModel の中の要素を指定する際、プレフィックス的なものは不要。

とりあえず data-bind=”with:hoge” を書いておいた方が収まりがいいと感じた。

バインディングコンテキストは理解しておいた方がよさそう。

-> 2015/09/30 追記

viewModel が一つしかない場合でも、ko.applyBindings(viewModel); は使わずに

上のコードのように連想配列を渡しておけば、後からVM分割したくなっても安心。

可能であれば if より visible を使う

if は、条件が false な時に、その中の要素を本当に消してしまいます。

条件が成立すると、中の要素を追加します。何が問題かというとバインドした

イベントが消えるということです。

visible であれば隠れるだけなのでこういった問題は発生しません。

環境

  • Ubuntu 18.04LTS
  • Mackerel

手順

Mackerel エージェントを入れる

https://mackerel.io/ja/docs/entry/howto/install-agent

Ubuntu16 以降なので以下のコマンド。と言っても、Mackerel の Web にログイン状態で、Hosts→ 右上のエージェントをインストール を選択すると OS の選択肢が表示されて、そこから選ぶとコマンドが完璧な形で表示されるのでそこをコピペすることをおすすめします。

1
wget -q -O - https://mackerel.io/file/script/setup-all-apt-v2.sh | MACKEREL_APIKEY='<YOUR_API_KEY>' sh

Mackerel Agent Plugin を入れる

全部のプラグインがセットになっています。

1
apt-get install mackerel-agent-plugins

Postgres Plugin 設定

Mackerel のプラグインは CLI からテストできる。楽。

1
2
mackerel-plugin-postgres -user=postgres -password=postgres_pwd [-database=<databasename>]
# -database 以降省略可能

出力例

なお、最初は同じコマンドを二度実行しないと警告が表示されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
postgres.tempfile.temp_bytes    0.000000        1534094514
postgres.connections.active 1.000000 1534094514
postgres.connections.active_waiting 0.000000 1534094514
postgres.connections.idle 0.000000 1534094514
postgres.connections.idle_in_transaction 0.000000 1534094514
postgres.commits.xact_commit 77.899761 1534094514
postgres.commits.xact_rollback 0.000000 1534094514
postgres.blocks.blks_read 2.291169 1534094514
postgres.blocks.blks_hit 1660.954654 1534094514
postgres.size.total_size 984558979.000000 1534094514
postgres.iotime.blk_read_time 0.000000 1534094514
postgres.iotime.blk_write_time 0.000000 1534094514
postgres.rows.tup_returned 7974.272076 1534094514
postgres.rows.tup_fetched 739.761337 1534094514
postgres.rows.tup_inserted 1.861575 1534094514
postgres.rows.tup_updated 2.004773 1534094514
postgres.rows.tup_deleted 0.000000 1534094514
postgres.deadlocks.deadlocks 0.000000 1534094514
postgres.xlog_location.xlog_location_bytes 37238.377088 1534094514

Mackerel Agent に plugin 実行を指示する

設定ファイルに実行する内容を記述する必要があります。

/etc/mackerel-agent/mackerel-agent.conf を編集します。

すでに plugin の設定サンプルが書かれているので、コメントアウトするだけ…

ではありません 設定例は以下のような形になります。

1
2
[plugin.metrics.postgres]
command = "mackerel-plugin-postgres -user=postgres -password=postgres_pwd"

蛇足

ようするに command = "先程テストしたコマンドラインそのまま"

です。これに気づかず、少しハマりました。

他のプラグインでパラメタがないものについては、設定ファイルのコメントアウトを外すだけで有効になります。

各プラグインの説明は・・・ https://github.com/mackerelio/mackerel-agent-plugins

これなんですかねぇ… 割と淡白な説明ですがなんとかなると思います。

Why Arch Linux?

Docker を動かす為のできるだけ小さい構成の OS を捜していた。
Arch は全部自分でパッケージ入れて好きに構成するという考え方らしいので
できるだけ最小にできるはず!ということでやってみた記事です。(なお初めてです)
手順は以下を参照しながらやっています

https://dzone.com/articles/install-arch-linux-on-windows-10-hyper-v

環境

  • Hyper-V 第二世代 VM
  • ディスク容量 20GB
  • archlinux-2019.06.01-x86_64.iso

手順

VM の作成

  • セキュアブート無効

起動

Arch の ISO をマウントして起動する。
すると、自動的に root のプロンプトが起動してくる。
コンソールではコピペもできず不便なので、ssh が使えるようにする。

1
2
3
4
5
6
localectl set-keymap jp106
passwd # rootにパスワードがないとssh繋げられない
systemctl start sshd

# なお、IPアドレスは
ip a なり ifconfig で調べられる

パーティション作成

EFI で起動させたいので、GPT でパーティションを切っていく。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ gdisk /dev/sda
# EFIブート
command?: n #新規作成
number: [入力せずにENTER]
First sector: [入力せずにENTER]
End Sector: +512M
type: EF00 # EFIブートパーティション

# データ
command?: n #新規作成
number: [入力せずにENTER]
First sector: [入力せずにENTER]
End Sector: [入力せずにENTER]
type: [入力せずにENTER] # Linux

command?: w # 書込
Do you want to proceed? (Y/N): Y

フォーマット

1
2
mkfs.fat -F32 /dev/sda1
mkfs.ext4 /dev/sda2

とりあえずマウント

1
2
3
mount /dev/sda2 /mnt
mkdir /mnt/boot # EFIブートパーティションをマウントするため
mount /dev/sda1 /mnt/boot

ファイルコピー

1
2
3
4
5
6
7
8
pacstrap /mnt base base-devel openssh vim
genfstab -U /mnt >> /mnt/etc/fstab
arch-chroot /mnt

# ここから、ディスク上に書き込まれる

# ブートローダー入れる
bootctl install

ブートローダー設定

vim /boot/loader/loader.conf

1
2
3
default arch
timeout 3
editor 0

ブートローダー設定 2

1
cp /usr/share/systemd/bootctl/arch.conf /boot/loader/entries/

blkid -s PARTUUID -o value /dev/sda2

で UUID を取得しておく。

vim /boot/loader/entries/arch.conf

1
options root=PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx rootfstype=ext4 add_efi_memmap

ブートローダー設定を反映

1
2
bootctl update
bootctl

これで再起動できます。おつかれさまでした。

ネットワーク設定

固定 IP を指定する。DHCP 使わない。Network-manager もナシ

1
vim /etc/systemd/network/20-wired.network
1
2
3
4
5
6
7
8
[Match]
Name=eth0

[Network]
Address=10.1.0.230/24
Gateway=10.1.0.1
DNS=8.8.8.8
DNS=8.8.4.4
1
2
systemctl enable systemd-networkd
systemctl enable systemd-resolved

locale まわり

1
2
3
4
5
vim /etc/locale.gen

en_US.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
の二行のコメントアウトを外した。
1
sudo locale-gen
1
sudo localectl set-locale LANG=en_US.UTF-8

ここで一度 SSH を切断して、再接続しないと表示乱れが発生した。

timezone

1
sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
1
2
$ date
Thu 20 Jun 2019 05:06:48 PM JST JSTになっていることを確認

ホスト名

1
hostnamectl set-hostname ほすとめい