我需要在执行某些计划任务,由于一些不可名状的原因,我不想在宿主机上写 cron,不然全天下都知道我在干什么了,那么我就脱裤子放个屁 —— 在 docker 容器内部悄咪咪的执行
具体场景是我启动了一个 nginx 的 docker 容器,我需要每2个小时执行一次授权检测,授权检测实际上就是在 nginx 容器内部执行一个检测脚本,脚本具体工作事项就不具体介绍了
原本这个事情直接在宿主虚拟机上搞定是最直接的,但是直接在宿主上跑一个计划任务那不是谁都知道了(就是防止一下甲方问东问西),那这里我们就需要用到 ofelia,让 ofelia 来帮我干这个活
摘抄一份 deepseek 查到的 ofelia 介绍
Ofelia 非常灵活,提供了四种不同的任务(Job)类型以适应不同场景:job-exec:在 指定的、正在运行 的容器中执行命令。例如,定期在已有的 nginx 容器里执行日志清理脚本。job-run:每次任务触发时,都会基于指定的镜像创建一个新容器来执行命令,执行完毕后销毁该容器。这对于运行一次性的、隔离性要求高的任务非常有用。job-local:在 运行 Ofelia 本身的主机(或容器)上 直接执行命令。job-service-run:用于 Docker Swarm 模式,在 Swarm 集群中创建一个一次性服务来执行任务。
下面上代码
docker-compose.yml
services:nginx:image: owasp/modsecurity-crs:nginxcontainer_name: nginxhostname: nginxvolumes:- ./server.conf:/etc/nginx/conf.d/server.conf- ./html:/usr/share/nginx/html- ./rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:roenvironment:- TZ=Asia/Shanghai- BLOCKING_PARANOIA=2 # 阻断模式的严格等级- ANOMALY_INBOUND=4 # 入站异常分数阈值,低于 9 GetCapabilities 就会被拦截- ANOMALY_OUTBOUND=4 # 出站异常分数阈值ports:- "80:80" # modsecurity-nginx 内部由8080端口反向代理到80端口,我们自己的配置文件以80端口启动即可user: rootrestart: alwaysofelia:image: mcuadros/ofelia:0.3container_name: ofeliahostname: ofeliavolumes:- /var/run/docker.sock:/var/run/docker.sock:roenvironment:- TZ=Asia/Shanghaiuser: rootrestart: always
ofelia/config.ini
[job-exec "auth_check"]# 每秒执行 # schedule = * * * * * *# 每两个小时执行 schedule = 0 0 */2 * * *container = nginx command = sh /script/auth_check.sh# 可选参数 user = root # 指定执行用户 no-overlap = true # 防止任务重叠执行
script/auth_check.sh
#!/bin/bashexport PATH=$PATH:/usr/local/binDEADLINE="2026-03-03 00:00:00" LOG_FILE="/var/log/auth_check.log"if [ $(date +%s) -gt $(date -d "$DEADLINE" +%s) ]; thenecho "$(date '+%Y-%m-%d %H:%M:%S') - 授权已过期" >> $LOG_FILEtouch /etc/nginx/auth_expired.lock 2>/dev/null elseecho "$(date '+%Y-%m-%d %H:%M:%S') - 授权正常" >> $LOG_FILErm /etc/nginx/auth_expired.lock -rf 2>/dev/null fi
三个文件准备好后执行下面的启动命令(不在启动 compose 时挂载文件,使用 docker cp 则是为了不留痕迹, docker cp 完毕后记得删除 script 和 ofelia 两个目录,深藏功与名)
docker compose up -d docker cp script nginx:/ docker cp ofelia ofelia:/etc# ofelia 启动后没有配置文件,拷贝配置文件进去后停止2秒等待下一次重启 sleep 2 docker logs -f ofelia# 删除 script 和 ofelia 深藏功与名 # rm script ofelia -rf
ofelia 的容器日志应该类似下面这样
open /etc/ofelia/config.ini: no such file or directory open /etc/ofelia/config.ini: no such file or directory 2026-03-01T19:20:00.793+08:00 scheduler.go:44 ▶ NOTICE New job registered "auth_check" - "sh /script/auth_check.sh" - "0 0 */2 * * *" 2026-03-01T19:20:00.793+08:00 scheduler.go:55 ▶ DEBUG Starting scheduler with 1 jobs
说明任务已经注册成功了,等待下一次任务执行后再查看最新日志即可
针对我的这个任务查看是否执行成功则很简单,运行下面的 docker 命令验证即可
[root@host-10-1-146-42 srv]# docker exec -it nginx cat /var/log/auth_check.log 2026-03-01 20:00:00 - 授权正常
说到底上面这个流程近似于脱裤子放屁,要更隐蔽一点就不要直接使用 ofelia,from ofelia,自己 build 一个镜像,把配置文件换一个路径,把镜像换一个名字掩盖一下
如果还嫌不够彻底,那就自己用 go 或 c++ 写一个程序,硬编码要执行的计划任务
