dockercronmariadbdocker-exec

Cannot backup mariadb docker from crontab


So I have a mariadb in a container in /home/admin/containers/mariadb.

This directory also contains an .env-file with MARIADB_ROOT_PASSWORD specified.

I want to backup the database using the following command:

* * * * * root docker exec --env-file /home/admin/containers/mariadb/.env mariadb sh -c 'exec mysqldump --databases dbname -uroot -p"$MARIADB_ROOT_PASSWORD"' > /home/admin/containers/mariadb/backups/dbname.sql

The command works when running from the terminal but crontab only creates an empty sql file.

I assume there are some issues with cron ready the .env file.


Solution

  • Bash command line is nice.

    Cron is "different".

    Let me count the ways. Here are things to pay attention to. To simplify the description, let's assume you put the above instructions into backup.sh, so the crontab line is simply

    * * * * * root sh backup.sh
    
    1. Cron is running under UID zero here. Test interactively with: $ sudo backup.sh
    2. Cron uses a restricted $PATH. Test with: $ env PATH=/usr/bin:/bin backup.sh
    3. Cron's $CWD won't be your home directory.
    4. More generally, env will report different results from interactive. Your login dot files have not all been sourced.
    5. Cron doesn't necessarily set umask to 0022. Likely not an issue here.
    6. Output of ulimit -a might differ from what you see interactively.
    7. Cron does not provide a pty, which can affect e.g. password prompts. Likely not an issue here.

    Likely there are other details that differ.

    If you find that some aspect of the environment is crucial to a successful run, then arrange for that near the top of backup.sh. You might want to adjust PATH, source a file, or cd somewhere.


    Now let's examine what diagnostic clues you're gathering from each cron run. The most important detail is that while you're logging stdout, you are regrettably discarding messages sent to FD 2, stderr.

    You can accomplish your logging on the crontab command line, or within the backup.sh script. Use 2>&1 to merge stderr with stdout. Or capture each stream separately:

    docker ... 2> errors.txt  > dbname.sql
    

    With no errors, you will see a zero-byte text file.

    Also, remember the default behavior of crond. If you just run a command, with no redirect, cron assumes it should complete silently with zero exit status, such as /usr/bin/true does. If there's a non-zero status, cron will report the error. If there's any stdout text, such as /usr/bin/date produces, cron wants to email you that text. If there's any stderr text, again it should be emailed to you.

    Test your email setup. Set the cron MAILTO=me@some.where variable if the default of root wasn't suitable. Interactively verify that email sending on that server actually works. Repair your setup for postfix or whatever if you find that emails are not reliably being delivered.