Docker Container 内で systemd を使う方法
最初に
アノテーション メンテナンスチームの shinonome です。
今回は systemd を Docker Container 内でも使いたい場合の実現方法の記事になります。
この記事は、cgroup v2 下で稼働する前提で、Debian 11 / Ubuntu 22.04 Cloud Image で検証済みの内容になります。
※Docker の Rootless と Rootful mode に若干違いはありますが、どちらも稼働出来ます。
なお、通常の macOS の Docker 環境(Docker Desktop、Rancher Desktop など)では今回の内容はやりづらいと思います。
実践する際は下記の記事を参考に、自分が管理できる Linux (w/ Docker engine) 環境を先に立ててください。
準備作業 (Linux part)
まずは Docker systemd service unit ファイルの Service
配下に Slice=docker.slice
を追加後、docker service を再起動してください。
※こちらはこの後のコンテナー起動パラメーターの cgroup-parent
に使われます。
※変化が気になる方は事前に systemctl status
で変更前の状況を確認しましょう。
... [Service] ... Slice=docker.slice ...
# rootless vim ~/.config/systemd/user/docker.service # add slice systemctl --user daemon-reload systemctl --user restart docker systemctl --user status docker.slice systemctl --user status # optional # rootful vim /lib/systemd/system/docker.service # add slice systemctl daemon-reload systemctl restart docker systemctl status docker.slice systemctl status # optional
準備作業 (Dockerfile part)
次は Dockerfile を準備しましょう。
大まかな内容は:
- systemd 用の停止信号を指定
- systemd をインストールして、不要な一時ファイル等を削除
- Container 内に起動不要な systemd units を全て解除
- 必要な分は残す(もしくは再起用)、例えば journald
- Container 起動コマンドを systemd に指定
ARG TAG="latest" FROM debian:${TAG} ENV container docker ENV LC_ALL C ENV DEBIAN_FRONTEND noninteractive # match the stop signal to systemd's. STOPSIGNAL SIGRTMIN+3 USER root WORKDIR /root RUN apt-get update -y \ && apt-get install --no-install-recommends -y systemd \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ # allow login && rm -f /var/run/nologin # remove all unnecessary service. RUN rm -f \ /etc/systemd/system/*.wants/* \ /lib/systemd/system/*.wants/* # optional: enable journald. # known issus: audit won't work under rootless env due to permission. RUN cd /lib/systemd/system \ && ln -s ../systemd-journald.socket ./sockets.target.wants/systemd-journald.socket \ && ln -s ../systemd-journald-audit.socket ./sockets.target.wants/systemd-journald-audit.socket \ && ln -s ../systemd-journald-dev-log.socket ./sockets.target.wants/systemd-journald-dev-log.socket \ && ln -s ../systemd-journald.service ./sysinit.target.wants/systemd-journald.service \ && ln -s ../systemd-journal-flush.service ./sysinit.target.wants/systemd-journal-flush.service VOLUME [ "/tmp", "/run", "/run/lock" ] CMD [ "/lib/systemd/systemd" ]
起動
Dockerfile で Image を構築してから、記載したパラメーターでコンテナーを起動 (例は detach mode) してください。
※log 確認 / bash 呼び出し / 停止用の参考コマンドも記載しました。
※記載したコマンドでは、イメージ名をフォルダー名にしていますが、適宜変更してください。
docker build -t $(basename $PWD)-local . docker run -d -t \ --privileged \ --cap-add CAP_SYS_ADMIN --cap-add CAP_MKNOD \ --cgroup-parent=docker.slice --cgroupns private \ --tmpfs /tmp --tmpfs /run --tmpfs /run/lock \ --name systemd_container $(basename $PWD)-local:latest docker logs -f -t systemd_container docker exec -it systemd_container bash -c "systemctl status" docker container stop systemd_container
※rootless の場合、権限が足りないため、systemd-journald-audit.socket
の起動は失敗になり、systemd の状態は degraded
になりますが、コンテナーを使うには特に支障はないと思います。
※動作確認時点のコンテナー内の systemd バージョン: systemd 247.3-7+deb11u1
最後に
今回は、Docker Container 内で systemd を使う方法を紹介しました。
Container 内でも systemd でサービスを管理したい場合、是非試してみてください。
本ブログ、お役に立てると光栄です。
参考情報
- https://medium.com/swlh/docker-and-systemd-381dfd7e4628
- https://systemd.io/CONTAINER_INTERFACE/
- https://serverfault.com/questions/1053187/systemd-fails-to-run-in-a-docker-container-when-using-cgroupv2-cgroupns-priva
おまけに
cgroup v1 での実現もありますが、方法は若干違います。
v1 環境での方法はネット上にいっぱいありますので、必要でしたら検索してみてください。
例えば:https://developers.redhat.com/blog/2016/09/13/running-systemd-in-a-non-privileged-container
アノテーション株式会社について
アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。