コンテナで定期実行（root ユーザー、一般ユーザー）

この記事では、コンテナ内でプログラムを定期実行する方法を紹介します。

root ユーザー実行の記事は見つかりますが、一般ユーザーで実行する方法は日本語サイトも英語サイトも見つからなかったため、この記事がお役に立てればと思います。

BusyBox の `crond` を採用しています。
通常の cron 、BusyBox の crond 両方試しましたが、通常の cron ではコンテナログ出力に苦戦したためです。

## root ユーザーの場合
`Dockerfile` 以外は root ユーザーの場合でも一般ユーザーの場合でも共通です。
```
# ディレクトリ構成（共通）
.
├── crontab
├── Dockerfile
└── supervisord.conf
```

```Dockerfile:Dockerfile
FROM debian:bullseye-slim

RUN apt-get update && apt-get install -y --no-install-recommends supervisor busybox-static \
    && rm -rf /var/lib/apt/lists/*
COPY crontab /var/spool/cron/crontabs/root
RUN chown root:root -R /var/spool/cron/crontabs/root
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
```

```:crontab
* * * * * whoami
```

```conf:supervisord.conf
[supervisord]
nodaemon=true
loglevel=info

[program:cron]
command=busybox crond -f -l 8 -L /dev/stderr
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
```

#### 実行結果
```shell
# ビルド
$ docker build -t root-cron . 
# 実行
$ docker run --rm --name cron-by-root root-cron
2023-04-07 12:31:59,396 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
2023-04-07 12:31:59,398 INFO supervisord started with pid 1
2023-04-07 12:32:00,401 INFO spawned: 'cron' with pid 6
crond: crond (busybox 1.30.1) started, log level 8
2023-04-07 12:32:01,417 INFO success: cron entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
crond: USER root pid   7 cmd whoami
root
crond: USER root pid   8 cmd whoami
root
```
`root` ユーザーで実行されている。

## 一般ユーザー（非 root ユーザー）の場合
`Dockerfile` のみ異なります。
今回は `testuser` ユーザーで定期実行します。（ユーザー名は適宜変えてください）

`/var/spool/cron/crontabs/` 配下、ユーザーごとのファイルの所有者は root にします。
これが自分的に意外でなかなか cron が動かず、正解にたどり着くのに苦労しました。

`supervisor` と `crond` は root ユーザーで実行します。でないと `/dev/stdout` と `/dev/stderr` に出力できず、コンテナログに出力できないためです。
crond が `/var/spool/cron/crontabs/` 配下のファイルを探し、各ユーザーで実行しています。
```
# ディレクトリ構成
.
├── crontab
├── Dockerfile
└── supervisord.conf
```

```Dockerfile:Dockerfile
FROM debian:bullseye-slim

RUN groupadd -r testuser && useradd -r -g testuser testuser \
    && mkdir -p /home/testuser \
    && chown -R testuser:testuser /home/testuser

RUN apt-get update && apt-get install -y --no-install-recommends supervisor busybox-static \
    && rm -rf /var/lib/apt/lists/*
COPY crontab /var/spool/cron/crontabs/testuser
RUN chown root:root -R /var/spool/cron/crontabs/testuser
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

USER root
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
```

```:crontab
* * * * * whoami
```

```conf:supervisord.conf
[supervisord]
nodaemon=true
loglevel=info

[program:cron]
command=busybox crond -f -l 8 -L /dev/stderr
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
```

#### 実行結果
```shell
# ビルド
$ docker build -t non-root-cron . 
# 実行
$ docker run --rm --name cron-by-non-root non-root-cron
2023-04-07 12:25:02,057 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
2023-04-07 12:25:02,059 INFO supervisord started with pid 1
2023-04-07 12:25:03,061 INFO spawned: 'cron' with pid 7
crond: crond (busybox 1.30.1) started, log level 8
2023-04-07 12:25:04,068 INFO success: cron entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
crond: USER testuser pid   8 cmd whoami
testuser
crond: USER testuser pid   9 cmd whoami
testuser
```
`testuser` ユーザーで実行されている。