Blog

Dockerでsystemctlを使いたい!(Docker初心者向け)

はじめに

はじめまして、ニフティ新卒2年目の菅谷です。
社内勉強会や普段の業務でコンテナ型仮想化に触れる機会があり、dockerコンテナを利用していて詰まったsystemctlの利用についてお話したいと思います。

この記事の対象者

対象者

  • linux初心者
    • linuxの仮想環境を用意したい
    • initプロセスに依存するコマンドを実行したい

前提

dockerコンテナでは、initプロセスに依存せずにサービスの起動や停止等が行えます。
また、コンテナ立ち上げ時や利用時にサービスが停止すると、コンテナも停止するため、systemdを利用せずコンテナのログだけでサービスの状態を確認することが可能です。
しかし、今回の記事では「linuxサーバ(コンテナ)内で手を動かしたい」という方が対象となっているため、linuxサーバ内でsystemdを利用することを前提として話を進めていきます。

systemctlを使いたい

docker desktopを利用してプロキシサーバとして稼働するコンテナを構築中、squidサービスを稼働させるためにsystemctlコマンドを実行しようとしました。
ところが、systemctlコマンドを実行しようとしたところ次のようなエラーが…。

Failed to get D-Bus connection: Operation not permitted

このエラーでは「このコマンドを実行する権限がないよ」といわれています。systemctlコマンドを実行する権限がないようです。そもそもsystemctlとはどういったコマンドなのでしょうか?

systemctlとは

systemdと呼ばれるlinuxの起動処理、各サービスの管理を行うデーモンプロセスのコマンドです。
このコマンドでは以下の処理を実行できます。
  • start: サービスを起動する
  • stop: サービスを停止する
  • restart: サービスを再起動する
  • reload: サービスの設定を再読み込みする
  • is-active: サービスが稼働しているか確認する
  • enable: サービスの自動起動設定
  • disable: サービスの自動起動設定無効
  • reboot: システムを再起動する
  • poweroff: システムをシャットダウンする
例えば、squidサービスが稼働しているかどうか確認したい場合は次のようにコマンドを実行します。実行後は稼働していれば「active」、稼働していなければ「inactive」という表示が確認できます。 次の例ではsquidサービスの自動起動を設定しています。 このようにsystemctlコマンドを利用することでサービスの起動、停止、システムのシャットダウンまでが容易に行うことができます。
systemctlコマンドがサービス、システムにおいて重要なコマンドであることが分かりました。では、Dockerコンテナにおいてsystemdが使えない原因はどのようなものがあるでしょうか。

Dockerではなぜsystemdが使えないのか?

サービス、システムの管理に欠かせないsystemdですがdockerで利用できないのはLinuxの起動処理に関係があるようです。
linux(OS)の起動処理は次の順で行われます。
  1. 電源投入後、BIOSが起動する。
  2. BIOSからブートローダが呼び出される。
  3. ブートローダがlinuxカーネルを起動する。
  4. linuxカーネルがinitプロセス(pid:1)を起動する。
ここで言われているinitプロセスはsystemdにあたります。
そのため、dockerではコンテナを立ち上げる前にあらかじめinitプロセスが稼働状態でないとsystemdサービスが動作しないというわけです。(と書きましたが、単純にdocker hubで提供されているcentosのイメージページには、「systemdはデフォルトでactiveではない」と書かれています。また、その状態をunprivilegedと呼び、この状態ではDockerコンテナ内でデーモンの起動を行うことができません。)

使えるようにするには

systemdをdockerコンテナ上で利用できるようにするためには、あらかじめinitプロセスを稼働させる必要があるということがわかりました。
では、事前にinitプロセスを起動するために必要なことを書き出してみましょう。
  1. initプロセスを稼働した状態のコンテナがあること
  2. デフォルトで設定されているunprivileged(コンテナから全デバイスへアクセスする許可が無効)がprivileged(許可状態)に切り替わっていること
1ではinitプロセスが起動したコンテナを用意します。initプロセスの実行にはコンテナ起動時のコマンドに/sbin/initを指定する必要があります。
2ではデフォルトで無効化されているコンテナのデーモン起動サービス(systemd)を有効化しています。有効化には1で述べたコンテナを立ち上げる際にprivilegedオプションを指定する必要があります。

やってみましょう!

systemdを利用するために必要なことが分かったところで、実際にコンテナを立ち上げてみてsystemctlコマンドが利用可能になったことを確認してみましょう。

環境

  • ホスト: Windows 10
  • Docker Desktop: 4.2
  • イメージ: centos:7

確認手順

バックグラウンドでinitプロセス稼働させたコンテナを起動

Docker Desktopが起動された状態でターミナルを開き、次のコマンドを実行します。 実行するとコンテナIDが表示されます。
docker container psコマンドで起動中のコンテナのプロセスを確認します。
systemd-containerという名前のコンテナが/sbin/initを実行していることが確認できます。
docker container runを実行する際に付けたdオプションはバックグラウンドでコンテナを生成、コマンドを実行しており、さらにprivilegedオプションでコンテナにデーモンの管理を許可しています。

コンテナにログイン

initプロセスが稼働しているか確認するため、先ほど生成したコンテナにログインします(正確にはbashを実行します)。
ログインするには次のコマンドを実行します。 ログインが完了するとプロンプトが表示されます。
psコマンドを実行し、バックグラウンドでinitプロセスが稼働しているか確認してみましょう。
pid:1に/sbin/initが実行されていることが分かります。
この状態でsystemdが使えるようになっているはずです。

systemctlコマンドでsquidサービスの状態を確認

systemctlコマンドが利用できるか確認します。
今回はsystemd関連のサービス稼働状態を確認してみます。 実行してみたところ、サービスの稼働状態を確認することができるようになっていました。

注意しなければならないこと

コンテナにおけるサービスの管理はsystemctlで行わねばならない、というわけではないということに注意してください。
docker本来の機能は「特定のプロセスを1つだけ起動する」というものであり、1コンテナで複数のプロセスを動作させることは推奨されていません。つまり、コンテナ型仮想化は仮想環境を提供しますが、通常のLinuxサーバとは異なり1プログラムを動かすために、1台のコンテナを用いる運用が推奨されているということです。
よって、Dockerを利用する際は「1コンテナ1プロセス」を意識してサービスのパフォーマンスに重点を置いた運用をしていきましょう。

おわりに

今回はDockerコンテナの利用においてsystemctlコマンドを実行する方法について紹介してみました。
自身においても、この記事を執筆中にdockerの運用で心がけるべき「1コンテナ1プロセス」について学びがあり、知識向上につながったと思います。
dockerを利用し始めた方や、興味を持った方の役に立てれば幸いです。
今後もdockerやlinuxサーバの技術を学び、詰まったことや、便利な部分を紹介できればと思います。

参考

We are hiring!

ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です!
ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! Tech TalkやMeetUpも開催しております!
こちらもお気軽にご応募ください!