カテゴリー
Linux

非 root ユーザーで Supervisor を動かす Docker Compose を作ったのでポイントなどをメモする

ポイント

  • debian:bullseye-slim イメージをベースにした。
  • Supervisor 4 が対象
  • ログ出力に関して権限を修正する必要があった。
  • ソケットに関する権限不足に対処する必要があった。

具体的な実際のエラーとその対処

Docker のビルドは成功するものの、コンテナに入って supervisord を実行するとエラーとなりました。その内容と対処方法を記します。

ログファイル出力権限に関するエラー内容

app@8adb871c70ca:/$ supervisord
Traceback (most recent call last):
  File "/usr/bin/supervisord", line 33, in <module>
    sys.exit(load_entry_point('supervisor==4.2.2', 'console_scripts', 'supervisord')())
  File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 359, in main
    go(options)
  File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 369, in go
    d.main()
  File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 72, in main
    self.options.make_logger()
  File "/usr/lib/python3/dist-packages/supervisor/options.py", line 1494, in make_logger
    loggers.handle_file(
  File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 419, in handle_file
    handler = RotatingFileHandler(filename, 'a', maxbytes, backups)
  File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 213, in __init__
    FileHandler.__init__(self, filename, mode)
  File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 160, in __init__
    self.stream = open(filename, mode)
PermissionError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
app@8adb871c70ca:/$ 

対処方法

Dockerfile でログ出力ディレクトリの所有者を non root ユーザーとすることで解消できました。

RUN chown -R ${USERNAME}:${USERNAME} /var/log/supervisor/

ソケットに関するエラー内容

app@7f2dd72b1d50:/$ supervisord 
Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)
For help, use /usr/bin/supervisord -h
app@7f2dd72b1d50:/$ 

対処方法

Dockerfile で Supervisor の設定ファイルである /etc/supervisor/supervisord.conf を編集し、ソケットファイルの場所を /var/run/supervisor.sock から /home/${USERNAME}/var/run/supervisor.sock へと変更してやることで、権限の問題がクリアされ解消できました。

ソケットファイルの場所はこれでふさわしいのかどうかは少し不安です。

RUN cp --archive /etc/supervisor/supervisord.conf /etc/supervisor/supervisord.conf.org \
  && sed -ri -e "s!/var/run/supervisor.sock!/home/${USERNAME}/var/run/supervisor.sock!g" /etc/supervisor/supervisord.conf \
  && mkdir -p /home/${USERNAME}/var/run/ \
  && chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/

最終的にこれでうまく動く Dockerfile の全容

FROM debian:bullseye-slim

ARG USERNAME=app
ARG USER_UID=1000
ARG USER_GID=$USER_UID

RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
    # デバッグ用に sudo をインストール
    && apt-get update && apt-get install -y  --no-install-recommends \
    sudo=1.9* \
    && apt-get clean && rm -rf /var/lib/apt/lists/* \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

# デバッグ用
RUN apt-get update && apt-get install -y --no-install-recommends \
  # ps コマンドを使いたい。
  procps \
  vim \
  && apt-get clean && rm -rf /var/lib/apt/lists/*

# Supervisor
RUN apt-get update && apt-get install -y --no-install-recommends \
  supervisor=4.* \
  && apt-get clean && rm -rf /var/lib/apt/lists/*
# ログファイル出力権限に関するエラーへの対処
# ```bash
# app@8adb871c70ca:/$ supervisord
# Traceback (most recent call last):
#   File "/usr/bin/supervisord", line 33, in <module>
#     sys.exit(load_entry_point('supervisor==4.2.2', 'console_scripts', 'supervisord')())
#   File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 359, in main
#     go(options)
#   File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 369, in go
#     d.main()
#   File "/usr/lib/python3/dist-packages/supervisor/supervisord.py", line 72, in main
#     self.options.make_logger()
#   File "/usr/lib/python3/dist-packages/supervisor/options.py", line 1494, in make_logger
#     loggers.handle_file(
#   File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 419, in handle_file
#     handler = RotatingFileHandler(filename, 'a', maxbytes, backups)
#   File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 213, in __init__
#     FileHandler.__init__(self, filename, mode)
#   File "/usr/lib/python3/dist-packages/supervisor/loggers.py", line 160, in __init__
#     self.stream = open(filename, mode)
# PermissionError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
# app@8adb871c70ca:/$ 
# ```
RUN chown -R ${USERNAME}:${USERNAME} /var/log/supervisor/
# ソケットに関するエラーへの対処
# ```bash
# app@7f2dd72b1d50:/$ supervisord 
# Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)
# For help, use /usr/bin/supervisord -h
# app@7f2dd72b1d50:/$ 
# ```
RUN cp --archive /etc/supervisor/supervisord.conf /etc/supervisor/supervisord.conf.org \
  && sed -ri -e "s!/var/run/supervisor.sock!/home/${USERNAME}/var/run/supervisor.sock!g" /etc/supervisor/supervisord.conf \
  && mkdir -p /home/${USERNAME}/var/run/ \
  && chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/
# Supervisor により管理するプログラム追加
COPY ./etc/supervisor/conf.d /etc/supervisor/conf.d

USER $USERNAME

おわりに

Laravel で Supervisor から Apache 、 Cron 、 などを管理するのですけれども、 root ユーザーでコンテナを動かしております。

これを non root ユーザーにしたかったのです。

  • そもそも Docker コンテナは root ではなく非 root ユーザーで動かすことがベストプラクティスとされている。
  • アプリのログ出力でファイルがない場合になぜか権限エラーとなることがあるが、これの原因は多分 root ユーザーで Supervisor を動かしているためではないか?

以上のことが解消できるのではと期待しています。

また、他のファイルも含めて、実際に動かすときに使ったファイルの全ては次のリポジトリにアップしておきました。

以上です。

コメントを残す