postgresql 中的 Cron:alpine docker 容器

问题描述 投票:0回答:3

我正在使用“普通”postgresql:alpine docker 映像,但必须每天安排数据库备份。我认为这是一个非常常见的任务。

我创建了一个脚本

backup
并将其存储在
/etc/periodic/15min
中的容器中,并使其可执行:

bash-4.4# ls -l /etc/periodic/15min/
total 4
-rwxr-xr-x    1 root     root            95 Mar  2 15:44 backup

我尝试手动执行它,效果很好。

我的问题是让

crond
自动运行。

如果我执行

docker exec my-postgresql-container crond
,守护进程将启动并且 cron 工作,但是 我想将其嵌入到我的 Dockerfile 中

FROM postgres:alpine

# my backup script, MUST NOT have .sh extension
COPY backup.sh /etc/periodic/15min/backup 
RUN chmod a+x /etc/periodic/15min/backup

RUN crond # <- doesn't work

我不知道如何重写或覆盖官方镜像中的命令。出于更新原因,如果可能的话,我也想保留这些图像。

postgresql docker cron docker-container
3个回答
9
投票

注意:如果您想将同一个容器与多个服务

一起使用,请选择此选项

安装Supervisord,这将使您能够运行

crond
postgresql
Dockerfile
将如下所示:

FROM postgres:alpine
RUN apk add --no-cache supervisor
RUN mkdir /etc/supervisor.d
COPY postgres_cron.ini /etc/supervisor.d/postgres_cron.ini
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

并且

postgres_cron.ini
将如下所示:

[supervisord]
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
loglevel=info                ; (log level;default info; others: debug,warn,trace)
nodaemon=true              ; (start in foreground if true;default false)

[program:postgres]
command=/usr/local/bin/docker-entrypoint.sh postgres
autostart=true
autorestart=true

[program:cron]
command =/usr/sbin/crond -f
autostart=true
autorestart=true

然后您可以启动 docker 构建过程并从新映像运行容器。请根据需要随意修改

Dockerfile
postgres_cron.ini


1
投票

几个月前我遇到了完全相同的问题。关键在于,一个容器只能有一个由

ENTRYPOINT
中的
CMD
和/或
Dockerfile
定义的主进程。

您不能仅将

postgres
替换为
crond
,否则您的数据库将无法运行。通常建议每个容器使用一项服务来分隔关注区域。


考虑到这一点,要么使用一个单独的容器,除了

crond
之外什么都不运行,因此
Docker
都可以跟踪其生命周期,并在失败时重新启动它,机器重新启动等。

或者使用

cron
在主机上通过
docker exec
运行作业。

第三个也是我认为最好(但也是先进)的解决方案是

pg_cron
。它是一个
postgres
扩展,因此在同一数据库容器中运行作业。您的挑战是调整它的配置和安装。

最简单的部分应该是

postgresql.conf

# add to postgresql.conf:
shared_preload_libraries = 'pg_cron'
cron.database_name = 'postgres'

接下来,您需要通过调整

pg_cron
(可以从官方
Dockerfile
图像中获得)来将
alpine postgres
扩展添加到图像中。 这里描述了它的安装。


0
投票

好吧,现在是 2024 年了,在悄悄咒骂 postgres docker 的维护者几个小时后,他们剥夺了我的 root 权限,转而使用“稍微安全一点”但“过于复杂”的 postgres 用户,让我的生活变得一团糟。是我的解决方案:

在我的场景中,我想每天左右运行 certbot 来更新我的证书。

在 docker 镜像内的 /usr/local/bin/docker-entrypoint.sh 中获取 docker-entrypoint.sh 的副本

i.e. docker cp <container>:/usr/local/bin/docker-entrypoint.sh

像这样更新 docker 文件:

FROM postgres:latest

#do your installs etc (i'm installing certbot and cron here)

# ---below is important---  
USER root
COPY ./crontab /etc/cron.d/certbot-renew
RUN chmod 0644 /etc/cron.d/certbot-renew
RUN crontab /etc/cron.d/certbot-renew
USER postgres
COPY ./docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh

说明:进入 root 模式,将 crontab 文件复制到容器中,设置其权限并向 cron 注册,然后返回到 postgres 用户。

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
0 5 * * * certbot renew -n >> /var/log/cron.log 2>&1

现在,使用 docker compose 启动容器,但在 docker-compose.yml 文件中包含 user:0:0 选项,如下所示:

services:

  postgres:
    container_name: ${CONTAINER_NAME}
    image: ${IMAGE_NAME}
    build:
      dockerfile: Dockerfile
      context: .
    restart: unless-stopped
    user: 0:0

这里有一个技巧 - 通过使用 root 用户执行 docker compose,它将进入“docker-entrypoint.sh”中定义的 if 语句,大约第 314 行,将您降级为 postgres 用户 - 这部分在这里:


_main() {

...
        if [ "$(id -u)" = '0' ]; then
            # then restart script as postgres user
            # !!! -HERE IS YOUR ONLY CHANCE BEFORE LOSING ROOT PRIVILEGES
            # insert this line below:
            service cron start
            # now you lose your root privileges
            exec gosu postgres "$BASH_SOURCE" "$@"
        fi

因此逻辑如下 - 您以 root 身份启动容器,入口点在将您放入 postgres 之前启动 cron,然后容器正常启动。

你会注意到我没有将输出(在 crontab 中)记录到 /proc/1/fd/1 - 因为再一次 - 偏执的维护者甚至不允许 root 发布到 /proc/1/fd/ 1 - 所以要验证你的 cronjob 正在运行,请跟踪容器内的 /var/log/cron.log - 这是另一个非常烦人的事情,因此如果不以 root 身份登录到容器,你实际上无法看到 cron 正在做什么。尝试将作业的输出记录到 /proc/1/fd/1 将导致“权限被拒绝”错误,并且看起来好像 cron 不起作用,因为实际上,作业将失败并出现错误且没有输出。

© www.soinside.com 2019 - 2024. All rights reserved.