Laravel Task Scheduling with Cron and Docker
Summary: Schedule Laravel commands using cronjob inside Docker.
Automating repetitive tasks like sending emails, cleaning up old records, or generating reports is a crucial part of any robust Laravel application. Laravel offers a powerful task scheduling mechanism through its scheduler
that allows you to define scheduled tasks right in your PHP code. However, when deploying Laravel in a Dockerized environment, especially in production, integrating cron jobs with Docker containers presents unique challenges.
In this article, we'll walk through how to properly set up and run Laravel's task scheduler using cron within a Docker container.
Understanding Laravel Task Scheduling
Laravel uses the command-line tool artisan schedule:run
to check for tasks defined in the app/Console/Kernel.php
file and execute those due at the current time.
A typical Laravel cron entry looks like this:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
This runs Laravel's scheduler every minute, letting Laravel decide which scheduled commands need to run.
The Challenge with Docker
When your application runs inside Docker, the traditional server-level crontab can no longer directly execute commands within your application container. Instead, you need the cron process to run inside your container. This setup gives you control and environment consistency but requires some extra orchestration.
Step 1: Defining Scheduled Tasks in Laravel
Open your app/Console/Kernel.php
file and define a sample scheduled command:
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:send')->daily();
}
This registers a custom command (emails:send
) to run every day.
Step 2: Create a Dockerfile with Cron
To add cron to your Laravel Docker container, you need to:
- Install cron.
- Copy or create a crontab file.
- Start both cron and PHP processes.
Below is a simple Dockerfile
for a Laravel application based on an official PHP image:
FROM php:8.2-cli
# Install system dependencies
RUN apt-get update && apt-get install -y cron git unzip libzip-dev
# Install PHP extensions
RUN docker-php-ext-install zip pdo pdo_mysql
# Set working directory
WORKDIR /var/www
# Copy application files
COPY . /var/www
# Install Composer
COPY --from=composer:2.5 /usr/bin/composer /usr/bin/composer
# Install application dependencies
RUN composer install --no-dev --optimize-autoloader
# Add Laravel's crontab file
COPY docker/laravel.cron /etc/cron.d/laravel
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/laravel
# Apply cron job
RUN crontab /etc/cron.d/laravel
# The command to run both cron and PHP-FPM
CMD ["sh", "-c", "cron && php-fpm"]
Note: Replace
php-fpm
withphp artisan serve
if you're running the development server, though for production a proper web server (nginx/apache) is recommended.
Step 3: Create the Crontab File
Create a file at docker/laravel.cron
with the following content:
* * * * * www-data cd /var/www && php artisan schedule:run >> /dev/null 2>&1
- Runs every minute as the
www-data
user. - Change paths and users depending on your image setup.
Step 4: Permissions and Entry Point
Make sure permissions for your Laravel files suit the user running cron (often www-data
). Also, ensure your container's entrypoint launches both the cron daemon and your web server or supervisor process.
Example (docker-compose.yml
service):
services:
app:
build: .
image: laravel-app
container_name: laravel-app
volumes:
- .:/var/www
ports:
- "8000:8000"
environment:
- APP_ENV=production
Step 5: Build and Run the Container
Build your container and run it:
docker-compose up --build
Step 6: Verifying Cron Execution
Check cron logs inside the container:
docker exec -it laravel-app tail -f /var/log/cron.log
Or, temporarily redirect the cron output in your laravel.cron
file for debugging:
* * * * * www-data cd /var/www && php artisan schedule:run >> /var/log/laravel-schedule.log 2>&1
Look for your scheduled command’s output in storage/logs/laravel.log
or the custom cron log.
Considerations and Best Practices
- One Process per Container: Running both cron and a web server in one container works for simple setups. For strict microservice adherence, use separate containers for each service and supervisor to manage multiple processes.
- Time Zones: Ensure the container time zone matches your application's requirement.
- Mail/Queue Drivers: If your schedule interacts with mail or queues, ensure the correct drivers and environment variables are configured.
- Persistent Data: Cron job logs or outputs should be stored in volumes if you want to retain them between container restarts.
Conclusion
Running Laravel's scheduler inside Docker using cron is a straightforward, scalable way to automate tasks within modern deployments. By defining scheduled commands in code, setting up cron inside your Dockerfile, and managing processes smartly, you unlock the full power of Laravel's automation.
Experiment with more complex schedules and tailor your Docker workflow for even greater reliability and maintainability.
Further Reading: