Docker, PHP, Symfony et les Crons sont dans un bateau

Docker, PHP, Symfony et les Crons sont dans un bateau

Il existe plusieurs façons de faire pour gérer des crons avec des containers Docker, comme par exemple, utiliser la crontab du serveur hébergeant les containers et déclencher les commandes voulues dans le container, mais nous allons voir une autre façon de faire, avec une application Symfony

Le principe est assez simple : déployer deux fois le même container mais en modifiant la commande sur le container chargé de faire de lancer les crons

On créé un fichier cron, avec les commandes que nous souhaitons lancer

MAILTO=root
* * * * * cd /app && /usr/local/bin/php bin/console lacommande > /dev/null 2>&1

On inclut dans le container Docker (via le Dockerfile) le nécessaire pour que le daemon cron puisse s’exécuter

RUN apt-get install -y --no-install-recommends cron
COPY cron /etc/cron.d/cron
RUN chmod 0644 /etc/cron.d/cron
RUN crontab /etc/cron.d/cron
RUN touch /var/log/cron.log

On se retrouve alors avec une image Symfony contenant tout l’environnement d’execution (PHP, Serveur Web). et un exécutable cron prêt à être lancé.

Dans notre docker compose, on met deux services, un pour la partie HTTP, un autre pour la partie Cron.

volumes:
  shared-tmpfs:
    driver: local
    driver_opts:
      type: "tmpfs"
      device: "tmpfs"
      o: "size=256m"

services:
  php:
    image: XXX
    pull_policy: always
    restart: always
    ports:
        - target: 80
          published: 80
          protocol: tcp
    environment:
      SERVER_NAME: :80

    volumes:
      - shared-tmpfs:/app/var
      - "/etc/timezone:/etc/timezone:ro"
      - "/etc/localtime:/etc/localtime:ro"

  crond:
    image: XXX
    pull_policy: always
    restart: always
    command: cron -f
    healthcheck:
       test: ['CMD','true']
    volumes:
      - shared-tmpfs:/app/var
      - "/etc/timezone:/etc/timezone:ro"
      - "/etc/localtime:/etc/localtime:ro"

On peut voir ici qu’on lance deux fois le même container mais un lance cron -f au démarrage alors que l’autre lance son ENTRYPOINT habituel.

Ici, nous utilisons une base Sqlite3 qui sert de cache un peu évolué, nous avons fait le choix de mettre en place un système de fichiers en RAM partagé entre les deux instances. De cette façon, nous avons la même base de données sur les deux containers. La base de données est automatiquement créé au démarrage du container php.

Installer facilement des extensions PHP (PECL) dans vos conteneurs Docker
FrankenPHP : mise en place de la CI/CD avec Gitlab
Docker, Python et FastAPI sont dans un bateau
Effacer le cache Symfony directement dans son application