Background jobs: Cron does not run
Tag: latest (2022/02/04) When trying to setup Cron as the background job, it seems it cannot work without a lot of work on top of the image Missing: Packages: Cron (and dependencies) Service: Something to run Crontab jobs Settings to Reproduce:
- Install docker image from tag: latest
- Setup dependencies (SQL DB) and config to get NextCloud started
- Enable Cron background Job
- Settings -> Basic Settings -> Select " Cron" Radio Button under "Background jobs" section
- Wait 5 minutes and reload page
- observe that the last job was run over 5 minutes ago (PROBLEM)
- Log into docker container terminal as Root
- Install Cron package and dependencies
- Install editor and configure EDITOR env var (I used nano)
- edit crontab (crontab -u www-data -e) to add recommended line per documentation (https://docs.nextcloud.com/server/23/admin_manual/configuration_server/background_jobs_configuration.html)
- Wait 5 minutes and reload page
- observe that the last job was run over 5 minutes ago (PROBLEM)
- Further investigation you can see that there are no Cron logs at expected locations, which indicates Cron is not even running. I was unable to figure out how to start the Cron service since the docker image is stripped down version of Debian. SystemD does not seem to be installed.
Mitigation: Mitigation is to setup Cron on Host and run "docker exec -u 33 -t nextcloud-app php -f /var/www/html/cron.php" (www-data UID = 33)
- Note: on Fedora Server, Cron is not enabled/running after Cron is installed. the service has to be enabled for Cron jobs to run (systemctl enable crond.service). I assume something similar needs to be done within the docker image/container.
Proposed Solution:
- Create Docker Image with cron installed and setup such that selecting Cron as a background job is enough to setup the cron job. OR
- Update Documentation to note that official docker image[s] do not support Cron Jobs in a Docker Container and list links to solutions or mitigations.
Here is some info from docker image inspect
"Id": "sha256:df82fda354851c092a2e95bb49189231931c357c36ab03a4ec3c19fdd64c4925",
"RepoTags": [
"nextcloud:latest"
],
"RepoDigests": [
"nextcloud@sha256:867d3f34d5a7baa1fb48b18b86e36486e406832881219c5bcd7f9952bc947366"
],
The background cron should be run in a separate container If you provide the docker-compose.yml you using I can help you with how to set up the cron container. Or the docker compose examples right here can help you. https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/insecure/mariadb/apache/docker-compose.yml It should be like that
app:
image: nextcloud:apache
restart: always
ports:
- 127.0.0.1:8080:80
volumes:
- nextcloud:/var/www/html
environment:
- MYSQL_HOST=db
- REDIS_HOST=redis
env_file:
- db.env
depends_on:
- db
- redis
cron:
image: nextcloud:apache
restart: always
volumes:
- nextcloud:/var/www/html
entrypoint: /cron.sh
depends_on:
- db
- redis
That could work but if it is starting a while new container, that sounds like a bit more RAM just to run Cron.php. also seeing two containers sharing the volume seems odd. Since you could have file IO errors. If this is the recommended way, there was no mention of this method in any of the documentation (docs.nextcloud.com).
so few ways to use the cron is,
- use separate compose like above
- use host cron and docker exec command
- custom image to run cron apa apache in parallel
That could work but if it is starting a while new container, that sounds like a bit more RAM just to run Cron.php. also seeing two containers sharing the volume seems odd. Since you could have file IO errors. If this is the recommended way, there was no mention of this method in any of the documentation (docs.nextcloud.com).
That's the recommended way in the examples and no proplem with sharing the same volume because it's only calls the cron file and about ram it uses 38mb of ram so not really a problem so don't worry and spin that extra cron container
Edit.. You don't need to add all volumes only the /var/www/html
@martadinata666 , I use the host to push a docker exec, and it works, and cron initiates sending the command to the container. With regards to all options, I did not find any documentation stating the docker image crontab does not work and steps to take to fix it. I think it would be easiest to add notes to the documentation to state such and list solutions and links. Documentation locations I am referring to: https://github.com/nextcloud/docker/wiki https://docs.nextcloud.com/server/23/admin_manual/configuration_server/background_jobs_configuration.html
@martadinata666 , I use the host to push a docker exec, and it works, and cron initiates sending the command to the container. With regards to all options, I did not find any documentation stating the docker image crontab does not work and steps to take to fix it. I think it would be easiest to add notes to the documentation to state such and list solutions and links. Documentation locations I am referring to: https://github.com/nextcloud/docker/wiki https://docs.nextcloud.com/server/23/admin_manual/configuration_server/background_jobs_configuration.html
But it's documented in the official examples here https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/insecure/mariadb/apache/docker-compose.yml
@kemoantemo , I am not saying what you linked is bad. I am saying me as a user never found that in all the searching I did. What good is "documentation" if a user cannot find the "documentation" to find the answer? What I am asking is if we can help users (like me) find the information we need by putting the documentation or links to documentation where a [new] user would look.
I get you but any new user should follow the examples of the official docker so where is the problem? Maybe it's not in the documentation of nextcloud because next cloud have a lot of deploy methods so you should check the examples of the method you going to use and don't worry from the cron container it's not fully nextcloud container it doesn't run nextcloud instance it just run a cron process that calls cron.php every 5 minutes so it's pretty good and easy to applicate solution. you can use the supervisored to run nextcloud and cron from same container but it's really almost the same because after all it's the same PID so just use the official examples and don't worry
everyone got personal preferences, in my case i rather not modify host so i create custom image with added supervisor to run cron and apache in parallel. Because i also need additional job like full text search, and preview generator, and pretty messed up on upgrade as it get overwritten cmiiw
The NC docker docs just mention cron briefly, pointing to the examples:
The examples folder gives a few examples on how to add certain functionalities, like including the cron job, smb-support or imap-authentication.
Here is where cron is defined in the examples
This would be the correct way to do it with docker-compose*. Containers should be a single process to allow logs and error handling to make sense.
Since almost every(?) instance needs cron, maybe it should be more prominent in the docs?
*(In Kubernetes you can use a CronJob to handle the cron script which feels somewhat nicer.)
Sorry to revive this a month later, but I am also facing issues with my Cron set-up.
My docker-compose.yml
version: '2'
services:
db:
image: mariadb:10.5
restart: always
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=[pw]
- MYSQL_PASSWORD=[pw]
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
redis:
image: redis:alpine
restart: always
app:
image: nextcloud
restart: always
ports:
- 80:80
depends_on:
- db
links:
- redis
volumes:
- ./config:/var/www/html/config
- ./apps:/var/www/html/custom_apps
- /nextcloud-data:/var/www/html/data
environment:
- MYSQL_PASSWORD=[pw]
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_HOST=db
- SMTP_HOST=mail.me.eu
- SMTP_SECURE=tls
- SMTP_PORT=587
- [email protected]
- SMTP_PASSWORD=[pw]
- MAIL_DOMAIN=me.eu
- MAIL_FROM_ADDRESS=system
- TRUSTED_PROXIES=192.xxx.xxx.xx
- TRUSTED_DOMAIN=cloud.me.eu
- REDIS_HOST=redis
cron:
image: nextcloud
restart: always
volumes:
- ./config:/var/www/html/config
- ./apps:/var/www/html/custom_apps
- /nextcloud-data:/var/www/html/data
entrypoint: /cron.sh
depends_on:
- db
- redis
Despite copying the proposed cron container description - except the volumes as I'm only using more specific ones rather than just the generic /var/www/html. However, docker doesn't seem to do anything. I am still seeing the notification in Nextcloud admin pages that the 'last executed job was yesterday'.
I asked support on the forum but unfortunately the answers provided there don't really get me much further. On the one hand I'm hoping to get feedback on my situation. On the other hand I'm here to support the call for more documentation/explanation on using docker (more than only an example file that doesn't explain anything and isn't of much help when debugging).
@keunes the /var/www/html is an essential for not just cron but also for upgrading you should have it first then take every custom data or config as you want after so try to make a volume for /var/www/html If you need help you can email me at [email protected] I'd love to help
@keunes try setting the MYSQL variables in the environment of the cron container as well. They're not specifying any in the example, but I am going to guess that is because they are using defaults.
@danieljkemp it's getting it from the config file no need to he just need to mount the /var/www/html
@keunes the /var/www/html is an essential for not just cron but also for upgrading you should have it first then take every custom data or config as you want after so try to make a volume for /var/www/html
You're amazing, this worked! Just for my understanding: why is it that adding this 'parent' volume fixed it? Which directories/files are there that cron needs (or that the app needs to know that cron is running)?
I think it would be helpful to mention in the docs (docker Readme) what you told me also, namely that the parent folder must be there, and that child directories may be specified after. I see now that it is mentioned Persistent data somewhat implicitly, but not mentioned in the Docker compose section. I'll prepare a PR with some suggested changes later on.
Also, another question for my understanding: what happens behind the scenes when mounting a parent and then some child directories? On the first run with the global/first volume (when the nextcloud volume doesn't exist yet), does it work like this?
- first main volume created (replicating the files & structure from the image in the virtual file system), after which
- any other volume I defined is mounted in the 'parent'/first volume (for which I suppose the original files that were taken from the image are removed first)
The essential thing is the /var/www/html in your cron and app need to be inline, if it run separately, the data generated from cron won't available / written to /var/www/html in app. Dunno exactly what is it written or read, /var/www/html/cron.php if you love investigate further.
Assume you had /var/www/html called it base and you also had /var/www/html/config defined called override, both had /var/www/html/config. Container will read from the override not from the base.
The crazy part is that /var/www/html/ contains the php source of the app. It is actually copying the application source to a volume when the main container updates, then keeping it a volume.
You'd expect to just need to mount the config and data directories into the app containers (main and cron included), and this is indeed how other applications work, but no, the the nextcloud containers references that volume (the one containing just copied source) directly.
@keunes the /var/www/html is an essential for not just cron but also for upgrading you should have it first then take every custom data or config as you want after so try to make a volume for /var/www/html
You're amazing, this worked! Just for my understanding: why is it that adding this 'parent' volume fixed it? Which directories/files are there that cron needs (or that the app needs to know that cron is running)?
I think it would be helpful to mention in the docs (docker Readme) what you told me also, namely that the parent folder must be there, and that child directories may be specified after. I see now that it is mentioned Persistent data somewhat implicitly, but not mentioned in the Docker compose section. I'll prepare a PR with some suggested changes later on.
Also, another question for my understanding: what happens behind the scenes when mounting a parent and then some child directories? On the first run with the global/first volume (when the
nextcloudvolume doesn't exist yet), does it work like this?
- first main volume created (replicating the files & structure from the image in the virtual file system), after which
- any other volume I defined is mounted in the 'parent'/first volume (for which I suppose the original files that were taken from the image are removed first)
The reason that cron didn't work is that the /var/www/html is just empty because you didn't call the entrypoint.sh which checks the version of your nextcloud and if it's existing or not then copy from /usr/src/nextcloud as i remember not sure. So that does happen only if you started the entrypoint.sh so that you don't have problems with the app container but it's surely slow at starting because it copies everytime it starts and for the cron container it doesn't find the php source of nextcloud at /var/www/html so it can't run. I hope I managed to describe it in a good way.
Thanks all for the help and explanations (and sorry for replying only now). I managed to get it working! I think indeed the trick was to add the volume nextcloud:/var/www/html both to app and cron.
@danieljkemp it's getting it from the config file no need to he just need to mount the /var/www/html
Thanks for that info, it answered my question, hope it helps someone else too.
Quesion:
since the config file needs to be retrieved from /var/www/html, why don't we just make the cron service's depends_on parameter to be on app instead of db & redis ? Sounds this could be a good Pull Request?
I feel, from the current example, if it only depends on DB, then we gotta give it all the environment parameters! Which is not really great thing to do.
Quesion: since the config file needs to be retrieved from /var/www/html, why don't we just make the
cronservice'sdepends_onparameter to be onappinstead ofdb & redis? Sounds this could be a good Pull Request?
depends_on only makes the containers start after the dependency containers start what you want is
volumes_from:
- app
and I did a pull request #1710 for it but it doesn't work with stack so they didn't implement it
Hello to all, I've the same problems, but adding the nextcloud:apache to my docker-compose.yml did not solve the problem! I've a Synology DS 220+ and installed portainer to do all the docker installations. In this installation I've to adapt the volume part to the right path of my synology. But I think this is the only modifcation. Nextcloud is working for a few weeks, but I've always the error message with cron, so I try to fix this...
Here is my portainer stack (I think it's nearly the same as the docker-compose.yml):
`services: db: image: mariadb:latest container_name: mariadb restart: always ports: - 3306:3306 command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed volumes: - /volume1/docker/nextcloud_db:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_USER=${MYSQL_USER} - TZ=Europe/Berlin networks: - web
redis: image: redis:latest restart: always networks: - web volumes: - /volume1/docker/redis:/var/lib/redis
app: image: nextcloud:latest container_name: nextcloud restart: always links: - db volumes: - /volume1/docker/nextcloud:/var/www/html - /volume1/docker/configfiles/nextcloud/.htaccess:/var/www/html/.htaccess logging: driver: "json-file" options: max-size: 10m max-file: "3" environment: - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_USER=${MYSQL_USER} - MYSQL_HOST=db - REDIS_HOST=redis - TZ=Europe/Berlin networks: - web depends_on: - db - redis
cron: image: nextcloud:apache restart: always volumes: - /volume1/docker/nextcloud:/var/www/html entrypoint: /cron.sh networks: - web depends_on: - app - db - redis
networks: web: external: true`
It's fantastic: after posting my comment I've rebooted my Diskstation and now nextcloud cron works fine. :)
Personally, I think docker exec is a better way, because is does not requires to change official nextcloud docker image, and automatic upgrade is possible.
The background cron should be run in a separate container If you provide the docker-compose.yml you using I can help you with how to set up the cron container. Or the docker compose examples right here can help you. https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/insecure/mariadb/apache/docker-compose.yml It should be like that
app: image: nextcloud:apache restart: always ports: - 127.0.0.1:8080:80 volumes: - nextcloud:/var/www/html environment: - MYSQL_HOST=db - REDIS_HOST=redis env_file: - db.env depends_on: - db - redis cron: image: nextcloud:apache restart: always volumes: - nextcloud:/var/www/html entrypoint: /cron.sh depends_on: - db - redis
mine doesn't work. i check the container log for the cron service and here's what i found:
cron_1 | crond: file www-data: cron_1 | crond: line php -f /var/www/html/cron.php cron_1 | crond: wakeup dt=60 cron_1 | crond: file www-data: cron_1 | crond: line php -f /var/www/html/cron.php cron_1 | crond: job: 0 php -f /var/www/html/cron.php cron_1 | crond: child running /bin/bash cron_1 | crond: USER www-data pid 17 cmd php -f /var/www/html/cron.php cron_1 | Exception: Not installed in /var/www/html/lib/base.php:282 cron_1 | Stack trace: cron_1 | #0 /var/www/html/lib/base.php(663): OC::checkInstalled(Object(OC\SystemConfig)) cron_1 | #1 /var/www/html/lib/base.php(1104): OC::init() cron_1 | #2 /var/www/html/cron.php(43): require_once('/var/www/html/l...') cron_1 | #3 {main} cron_1 | crond: wakeup dt=10
for reference, this is my docker-compose:
version: '3' services: proxy: image: jwilder/nginx-proxy:alpine labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" container_name: nextcloud-proxy networks: - nextcloud_network ports: - 24280:80 - 24443:443 volumes: - ./proxy/conf.d:/etc/nginx/conf.d:rw - ./proxy/vhost.d:/etc/nginx/vhost.d:rw - ./proxy/html:/usr/share/nginx/html:rw - ./proxy/certs:/etc/nginx/certs:ro - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/tmp/docker.sock:ro environment: - upload_max_filesize=2048M restart: unless-stopped letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nextcloud-letsencrypt depends_on: - proxy networks: - nextcloud_network volumes: - ./proxy/certs:/etc/nginx/certs:rw - ./proxy/vhost.d:/etc/nginx/vhost.d:rw - ./proxy/html:/usr/share/nginx/html:rw - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped db: image: mariadb container_name: nextcloud-mariadb networks: - nextcloud_network volumes: - ./db:/var/lib/mysql - /etc/localtime:/etc/localtime:ro environment: - MYSQL_ROOT_PASSWORD=***************** - MYSQL_PASSWORD=***************** - MYSQL_DATABASE=***************** - MYSQL_USER=***************** restart: unless-stopped app: image: nextcloud:latest container_name: nextcloud-app networks: - nextcloud_network depends_on: - letsencrypt - proxy - db volumes: - ./nextcloud_html:/var/www/html - ./app/config:/var/www/html/config - ./app/custom_apps:/var/www/html/custom_apps - ./app/data:/var/www/html/data - ./app/themes:/var/www/html/themes - /etc/localtime:/etc/localtime:ro environment: - VIRTUAL_HOST=***************** - LETSENCRYPT_HOST=***************** - LETSENCRYPT_EMAIL=***************** - PHP_MEMORY_LIMIT=2048M - PHP_UPLOAD_LIMIT=2048M restart: unless-stopped cron: image: nextcloud:apache restart: always volumes: - ./nextcloud_html:/var/www/html entrypoint: /cron.sh networks: - nextcloud_network depends_on: - letsencrypt - proxy - db volumes: nextcloud: db: networks: nextcloud_network:
The nextcloud volumes and cron volumes must inline
The nextcloud volumes and cron volumes must inline
already did
- ./nextcloud_html:/var/www/html
The nextcloud volumes and cron volumes must inline
already did
- ./nextcloud_html:/var/www/html
The config? The data? The custom?
so i have to add these too?
- ./nextcloud_html:/var/www/html - ./app/config:/var/www/html/config - ./app/custom_apps:/var/www/html/custom_apps - ./app/data:/var/www/html/data - ./app/themes:/var/www/html/themes - /etc/localtime:/etc/localtime:ro