The Ultimate Guide to Docker Cron Jobs: Effortlessly Scheduling PHP Tasks in Containers from the Host

Published: 2025-12-29
Author: DP
Views: 19
Category: Docker
Content
## Problem Background In modern web application development, we frequently need to execute scheduled tasks, such as generating reports, clearing caches, or, as mentioned in the user's query, creating a sitemap. When applications are deployed in Docker containers, a common question arises: How can we reliably use the host machine's Cron service to execute a PHP command inside a container, save the generated file to a specific location, and log the execution output on the host? This article, based on a real technical Q&A, provides a complete and validated solution, and also corrects a very common command-line redirection error. --- ## Core Solution: Using `docker exec` with Cron The most direct and stable method is to utilize the host's `crontab` and the `docker exec` command. `docker exec` allows you to run a command inside a running container. ### Option 1: Store Logs on the Host (Recommended) This is the recommended approach because it decouples application runtime logs from the container itself, facilitating centralized management and analysis. 1. **Crontab Configuration** Edit the host's scheduled tasks list using the `crontab -e` command and add an entry in the following format: ```bash # Format: minute hour day_of_month month day_of_week command # Execute at 2 AM every day, and append standard output and standard error to a log file on the host 0 2 * * * docker exec my-php-container-lib00 php /var/www/wiki.lib00.com/scripts/task.php >> /var/log/wiki.lib00/php-task.log 2>&1 ``` **Command Breakdown**: * `docker exec my-php-container-lib00`: Specifies that the command should be run inside the container named `my-php-container-lib00`. * `php /var/www/wiki.lib00.com/scripts/task.php`: This is the actual command to be executed inside the container. * `>> /var/log/wiki.lib00/php-task.log`: The `>>` is the append redirection operator. It appends the command's standard output (`stdout`) to the specified log file. If the file doesn't exist, it will be created. * `2>&1`: This is a crucial part. It redirects standard error (`stderr`, file descriptor 2) to standard output (`stdout`, file descriptor 1). This ensures that both normal output and error messages are captured in the same log file. ### Option 2: Store Logs Inside the Container If you prefer to keep logs together with your application code, you can also write the logs directly to a file inside the container. This requires wrapping the command with `sh -c` to ensure the redirection is correctly interpreted inside the container. ```bash # Execute at 2 AM every day and write logs to /var/log/app/task.log inside the container 0 2 * * * docker exec my-php-container-lib00 sh -c "php /var/www/wiki.lib00.com/scripts/task.php >> /var/log/app/task.log 2>&1" ``` You can view the logs inside the container with the following commands: ```bash # View directly docker exec my-php-container-lib00 cat /var/log/app/task.log # Or copy from the container docker cp my-php-container-lib00:/var/log/app/task.log ./ ``` --- ## Common Mistake and Correction: Handling File Generation and Logging A frequent error is attempting to redirect output to two different files in a single command, like this: ```bash # Incorrect Example: Using > and >> simultaneously ... > /path/to/sitemap.xml >> /path/to/log.log 2>&1 ``` This command is **invalid** because a command's standard output cannot be redirected to two destinations at once. Here is the correct approach recommended by DP@lib00. ### The Right Way: Let the Script Handle File Generation, Let Cron Handle Logging This is the clearest and most reliable method. Let your PHP script handle the file-writing logic internally, and have the Cron command simply capture the script's `echo` or `print` output for logging purposes. **Crontab Command:** ```bash # Cron only logs the standard output of the script (e.g., status messages) 0 2 * * * docker exec ee-php-fpm-8.4.13 php /pathToPro/php_app/index.php /sitemap/generate >> /pathToLog/sitemap_generate.log 2>&1 ``` **PHP Script (`index.php` or relevant logic):** ```php <?php // /pathToPro/php_app/index.php // Assuming this is the handler logic for the /sitemap/generate route function generateSitemapAction() { $sitemapContent = '<?xml version="1.0" encoding="UTF-8"?><urlset></urlset>'; // Example content $outputPath = '/pathToPro/php_app/public_frontend/sitemap.xml'; // Use file_put_contents to write the content to a file // Note: The user running PHP needs write permissions for the target directory file_put_contents($outputPath, $sitemapContent); // Print the execution result to standard output, which will be captured by Cron in the log file echo "[" . date('Y-m-d H:i:s') . "] Sitemap generated successfully at {$outputPath} "; } // ... call generateSitemapAction() ``` ### Alternative: Using the `tee` Command If you really need to save a command's output to a file and see it in the logs simultaneously, you can use the `tee` command. `tee` reads from standard input and writes to both standard output and a file. ```bash # Use a pipe and tee to write output to sitemap.xml and the log file 0 2 * * * docker exec ee-php-fpm-8.4.13 php ... /sitemap/generate 2>&1 | tee /path/to/sitemap.xml >> /path/to/log.log ``` While this works, its logic is less clear than the first method, as the log file will contain the entire content of the sitemap. --- ## Full Deployment Walkthrough 1. **Create Host Directories** ```bash mkdir -p /data/app_from_lib00/output mkdir -p /data/app_from_lib00/logs ``` 2. **Run Container with Volume Mounts** Use the `-v` flag to mount host directories into the container for data persistence. ```bash docker run -d \ --name my-php-container-lib00 \ -v /data/app_from_lib00/output:/var/www/html/output \ -v /data/app_from_lib00/logs:/var/log/app \ php:8.2-cli ``` 3. **Prepare and Copy the PHP Script** Create your `task.php` file and copy it into the container. 4. **Configure and Verify Crontab** ```bash # Add to crontab echo "0 2 * * * docker exec my-php-container-lib00 php /var/www/html/scripts/task.php >> /data/app_from_lib00/logs/cron.log 2>&1" | crontab - # Verify the configuration crontab -l ``` --- ## Conclusion By combining the host's Cron with `docker exec`, we can simply and effectively manage scheduled tasks for Docker containers. The best practice is to let the application script itself handle the core file-writing logic, while Cron focuses on scheduling and logging. This approach is not only logically cleaner but also easier to maintain and debug. Remembering the correct usage of `>>` and `2>&1` is key to ensuring complete and accurate logs.
Related Contents