ということで、
前回、デスクトップ環境での真っ新の状態からのdocker
のルートレス化をやってみたのだが、今回は、サーバー環境で、従来の dokcer グループにユーザ追加して、既に起動しているdocker
をルートレス化してみた。
そんな躓くこともないだろう?と高を括っていたが、盛大に躓いた。
ルートレス化できない
Ubuntu Server 22.04だったからか、前提条件は何もせずともクリアしていた。しかし、dockerd-rootless-setuptool.sh --force install
に失敗する。
[ERROR] Aborting because rootful Docker (/var/run/docker.sock) is running and accessible. Set --force to ignore.
arimasou16@ubuntu:~$ dockerd-rootless-setuptool.sh --force install
[INFO] Creating /home/arimasou16/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
+ systemctl --user start docker.service
+ sleep 3
+ systemctl --user --no-pager --full status docker.service
● docker.service - Docker Application Container Engine (Rootless)
Loaded: loaded (/home/arimasou16/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Fri 2024-02-09 18:13:30 JST; 777ms ago
Docs: https://docs.docker.com/go/rootless/
Process: 3879 ExecStart=/usr/bin/dockerd-rootless.sh (code=exited, status=1/FAILURE)
Main PID: 3879 (code=exited, status=1/FAILURE)
CPU: 7ms
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + mtu=
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + [ -z ]
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + command -v slirp4netns
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + [ -z ]
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + command -v vpnkit
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + echo Either slirp4netns (>= v0.4.0) or vpnkit needs to be installed
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: Either slirp4netns (>= v0.4.0) or vpnkit needs to be installed
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + exit 1
2月 09 18:13:30 ubuntu systemd[2411]: docker.service: Main process exited, code=exited, status=1/FAILURE
2月 09 18:13:30 ubuntu systemd[2411]: docker.service: Failed with result 'exit-code'.
+ set +x
[ERROR] Failed to start docker.service. Run `journalctl -n 20 --no-pager --user --unit docker.service` to show the error log.
[ERROR] Before retrying installation, you might need to uninstall the current setup: `/usr/bin/dockerd-rootless-setuptool.sh uninstall -f ; /usr/bin/rootlesskit rm -rf /home/arimasou16/.local/share/docker`
既に答えが書いてあるが、
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: + echo Either slirp4netns (>= v0.4.0) or vpnkit needs to be installed
2月 09 18:13:30 ubuntu dockerd-rootless.sh[3879]: Either slirp4netns (>= v0.4.0) or vpnkit needs to be installed
ということでsudo apt install slirp4netns
をする。そしたら、次は成功。前提条件にslirp4netns
はなかったぞ…vpnkit
だったりするんだろうが。
Dockerのコンテナーからhostに繋がらない
ルートレス化したので、そのままの設定で、Joplin Serverイメージを引っ張り直して起動してみる。しかし、ブラウザで見ると繋らない。
Joplin Serverのログをみると2024-02-09 09:48:50: [error] db: Timeout trying to connect to database: Error: connect ECONNREFUSED 127.0.0.1:5432
とホスト側で起動しているpostgres
に繋がらない。
既知の制限事項に書いてあったのだが、
ホストネットワーク ( docker run –net=host) も RootlessKit 内で名前空間化されます。
ということで繋げられない?
Dockerコンテナ内からホストのlocalhostにアクセスするという、まさにピンポイントな記事があった。
- Dockerコンテナと同じネットワーク内でサーバーを立てる
- UNIXソケットを使ってTCP通信を中継する
- Rootless Dockerでの–disable-host-loopbackの指定を解除する
- ngrokなどを使ってグローバルに公開する
とあったので、まず一番邪道そうな 3 の--disable-host-loopback
を外すをやったみたのだけど、やりかたが悪いのか?
- /usr/bin/dockerd-rootless.sh で
--disable-host-loopback
を削除 - docker.service再起動やらサーバ再起動
駄目だった…1
その次、 2 の linux - How to access localhost on rootless docker - Stack Overflowのアンサーでのシェルを試してみた。
#!/bin/bash
set -e
PORTS=($(echo "$1" | grep -oP '^\d+(:\d+)?$' | sed -e 's/:/ /g'))
if [ -z $PORTS ]; then
cat <<EOF
Usage:
$(basename "$0") SRC[:DEST]
SRC: will be the port accessible inside the container
DEST:
the connection will be redirected to this port on the host.
if not specified, the same port as SRC will be used
EOF
exit 1
fi
SOURCE=${PORTS[0]}
DEST=${PORTS[1]-${PORTS[0]}}
SOCKFILE="$XDG_RUNTIME_DIR/forward-docker2host-${SOURCE}_$DEST.sock"
socat UNIX-LISTEN:"$SOCKFILE",fork TCP:127.0.0.1:$DEST &
nsenter -U --preserve-credentials -n -t $(cat "$XDG_RUNTIME_DIR/docker.pid") -- socat TCP4-LISTEN:$SOURCE,reuseaddr,fork "$SOCKFILE" &
echo forwarding $SOURCE:$DEST... use ctrl+c to quit
sleep 365d
sudo apt install socat
をしてから、早速実行。Joplin Serverでのログを見ると、あっさり繋がるようになったのだけど…nginx
や他でも修正が必要なのか、ブラウザからJoplin Serverに繋がらない。そもそも理屈を良く分かってないので止めた。
ホストのPostgreSQLデータをDockerに移行
正直、もう今までのやり方でいいや、とか心挫かけたが今の流行に合わせておくということで、 1 の正攻法、postgres
もDockerで起動させてdocker compose
で接続させることにした。
postgres - Official Image | Docker Hubを眺めつつ思案した結果、どうせなら軽量の Alpine LinuxのPostgreSQLの最新版を使うことにした。
などを参考に、移行。
$ sudo -u postgres pg_dumpall -U postgres > postgres_dumpall.out
$ docker run --name postgresql_server -e POSTGRES_PASSWORD=パスワード -d postgres:16-alpine
$ docker cp postgres_dumpall.out コンテナID:/tmp/postgres_dumpall.out
$ docker exec -i -t コンテナID /bin/bash
# su postgres -c "psql -f /tmp/postgres_dumpall.out"
上記で移行できるが、
ボリュームを使ったコンテナの起動をしてないので、結局-v ./postgresql/db:/var/lib/postgresql/data
のようにボリュームを使ってからやり直すこととなった。
postgres
みたいなデータベースといった永続的なデータを扱うのにdocker
ってどうなの?って思ってたら、 /var/lib/postgresql/data をホストと共有することでコンテナ削除しても問題なく使えるんだねぇ。
適当に compose.yaml を作成してdocker compose up -d
すると、panic: interface conversion: interface {} is map[string]interface {}, not string
とのエラーが…
environment:
- APP_BASE_URL: https://example.com/joplin
環境変数の設定部分を=
とするのを:
としてしまったことが原因だった。
コンテナ同士で接続できない、コンテナ外部から接続できない
postgres
コンテナの後に、joplin server
を起動させるが、Joplin Serverからpostgres
コンテナに繋がらない。
他のDockerコンテナからコンテナ内のMySQLに接続する #Docker - Qiitaを参考に同じネットワーク空間で起動するようにして、POSTGRES_HOST=postgresql_server
と環境変数を設定すれば接続できるようになった。2
よっしゃ!と思ったら、今度はコンテナ外部からコンテナに繋がっていない…
Dockerのコンテナ外部から内部への接続 | FindxFineのとおり、postgres
コンテナに-p 5432:5432
を付け忘れていた。というか、同じポート番号だから要らんだろ、みたいな勘違いしていた。
とすったもんだあった挙句、下のような compose.yaml が完成した。
version: '3'
services:
db:
image: postgres:16-alpine
container_name: postgresql_server
restart: unless-stopped
volumes:
- ./postgresql/db:/var/lib/postgresql/data
- ./postgresql/log:/var/log
environment:
- POSTGRES_PASSWORD=postgresのパスワード
- PGDATA=/var/lib/postgresql/data/pgdata
networks:
- app-net
ports:
- "5432:5432"
app:
image: joplin/server:latest
container_name: joplin_server
depends_on:
- db
ports:
- "22300:22300"
restart: unless-stopped
environment:
- APP_BASE_URL=https://example.com/joplin
- APP_PORT=22300
- DB_CLIENT=pg
- POSTGRES_PASSWORD=joplinデータベースのパスワード
- POSTGRES_USER=joplinデータベースのユーザ名
- POSTGRES_DB=joplinデータベース名
- POSTGRES_PORT=5432
- POSTGRES_HOST=postgresql_server
networks:
- app-net
networks:
app-net:
driver: bridge
新たに覚えたdocker
コマンド
-
コンテナのログを見る
docker logs -f コンテナ名
-
compose
で実行中のコンテナに入るdocker compose exec サービス名 /bin/bash
コンテナ名では入れなくてサービス名services
なんですね。 -
ネットワーク情報の詳細を調べる
docker network inspect ネットワーク名
ホスト側やらルートDockerの後始末
最後、それまでルートで作成したdocker
のイメージ、コンテナは見えなくなっていたので、docker
コマンドでなく、普通にrm
3で削除した。良い子は真似しちゃ駄目。それと、ホスト側のpostgres
も削除した。
sudo gpasswd -d $USER docker
sudo rm -rf /var/lib/docker/overlay2/*
sudo rm -rf /var/lib/docker/containers/*
sudo systemctl stop postgresql.service
sudo systemctl disable postgresql.service
sudo apt autopurge postgresql*
sudo apt autopurge postgresql-*
sudo rm -rf /etc/postgresql-common /var/lib/postgresql /etc/postgresql
これ以上、問題が起きないことを願う。
-
/usr/bin/dockerd-rootless-setuptool.sh uninstall -f ; /usr/bin/rootlesskit rm -rf /home/arimasou16/.local/share/docker
してないから? ↩︎ -
Joplin Sync Server is Awesome - Install Joplin Server Using Docker Composeなど見ると
networks
の設定なしに db とやれば良いみたいに書いてあるから、単純にPOSTGRES_HOST=
の指定漏れ・ミスだけの可能性もある。 ↩︎ -
何か設定弄ったのか、ディレクトリ配下を
*
での一括削除が出来なかったので、本当は一つ一つ指定して削除した。 ↩︎