3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Docker内でsystemctlを使う with CentOS Stream 9

Posted at

コンテナ内でもcronとかをsystemctlを使って起動したい!
でも普通にコンテナイメージを作るとsystemctlがエラーが出て動かない!
(あとなんとなくCentOS Stream 9を使ってみたい!)
困った!

という人用の記事です。
※今回の内容には注意点もありますので、よく読んだ上でご利用は自己責任でお願いいたします。

結論

【注意点】
以下の手順のdocker run時に --privilegedオプションをつけていますが、
これは危険性のあるオプション です。
このオプションはドキュメントでは、 「潜在的な危険のある操作はデフォルトではできないようになっているが、--privilegedオプションによってそれが可能となる」 というようなことが書かれています。
したがってこの記事の内容を利用する際は、利用ケースをよく考えて使っていただければと思います。

【systemctlの使えるイメージの作り方、コンテナ起動の仕方】
1. 以下のDockerfileを用意して、

Dockerfile
FROM quay.io/centos/centos:stream9

ENV container docker
RUN dnf update && \
	dnf -y install cronie && \
	dnf -y install systemd && \
	dnf clean all && \
	systemctl enable crond.service

CMD ["/usr/sbin/init"]

2. コンテナイメージをビルドして

docker build -t local/cs9-systemd:0.5 .

3. コンテナをバックグラウンドで起動して

docker run --privileged --name cs9-systemd -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d local/cs9-systemd:0.5

4. あとはコンテナ内でbashを起動して手元のターミナルとつなげる

docker exec -it cs9-systemd /bin/bash

上記1~4の手順を実行すると、コンテナ内でsystemctlが使えます。
上記の例ではコンテナ起動時にcronのデーモンを動かす設定をしており、
crontab -eでジョブを設定してあげると自動実行されることが確認できると思います。
追加でなにかデーモンを起動したい場合は、通常のCentOSのようにコンテナ内でsystemctl startを使うことでできます。

試しにsystemctl list-unitsを使ったところ。ちゃんと動いている。
systemctl list-unitsを使ったところ。ちゃんと動いている。

解説

そもそもなぜsystemctlが動かないのか?

それはsystemdはPIDが1のときでないとエラーを返して起動しないようになっているから。
これはsystemdやsystemctlを実行したときのエラー
System has not been booted with systemd as init system (PID 1). Can't operate.にもそう書いてありますね。
PIDはプロセスのIDのことであり、PID1は一番最初に起動したプロセスに割り当てられるようです。
普通にlinuxを起動した際はsystemdが一番最初に起動するプロセスになるのですが、
dockerの場合はdocker runをした際に指定されたプログラムがPID1になります。
例えばdocker run [コンテナ識別子] /bin/bashとした際は、bashがPID1として起動します。
また、プログラムの指定を省略した際は少々動きが特殊で、
Dockerfileに書かれたCMDの内容があればその内容、
なければ/bin/bashがデフォルトとして指定されるようです。
ともかくこのdocker独特の挙動によってsystemdが動かないわけですね。

対策

今回の場合はdocker runを実行したときに/usr/sbin/initが実行されるようにする!
/usr/sbin/initの中でsystemdが起動され、systemdのPIDが1になるようです。
上記Dockerfile内のCMD ["/usr/sbin/init"]がそのための記述ですね。
上記の手順3docker runではコンテナ起動時に動かす(PID1になる)プログラムを指定していないので、
CMDに書いた/usr/sbin/initが実行されます。
なお、CMDに書くべきものはディストリビューションによって異なるようです。

その他Dockerfileの解説

dnf install -y cronie : cronieという名前のcronのパッケージをインストール
dnf -y install systemd : systemdのパッケージをインストール(実際には一緒にインストールされるsystemctlのコマンドを使います)
dnf clean all : パッケージインストール時にできたキャッシュ情報を削除
systemctl enable crond.service : systemctlの実行テストとして起動時にcronのデーモンを起動するようにお試しで設定

まとめ

(問題点がないわけではありませんが)コンテナ内でも一応systemctlを動かすことができました。
ここまで読んでいただきありがとうございました。

参考

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?