1

I'm new in Docker and I'm facing a problem with my custom Dockerfile which needs some help from you guys. It's working fine until I add some code to run the cronjob in the docker container.

This is my Dockerfile file:

FROM php:7.2-fpm-alpine

COPY cronjobs /etc/crontabs/root

// old commands

ENTRYPOINT ["crond", "-f", "-d", "8"]

This is cronjobs file:

* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1

This is docker-compose.yml file:

version: '3'

networks:
  laravel:

services:

  nginx:
    image: nginx:stable-alpine
    container_name: nginx_ctrade
    ports:
      - "8081:80"
    volumes:
      - ./app:/var/www/html
      - ./config/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./config/certs:/etc/nginx/certs
      - ./log/nginx:/var/log/nginx
    depends_on:
      - php
      - mysql  
    networks:
      - laravel
    working_dir: /var/www/html

  php:
    build:
      context: ./build
      dockerfile: php.dockerfile
    container_name: php_ctrade
    volumes:
      - ./app:/var/www/html
      - ./config/php/php.ini:/usr/local/etc/php/php.ini
    networks:
      - laravel

  mysql:
    image: mysql:latest
    container_name: mysql_ctrade
    tty: true
    volumes:
      - ./data:/var/lib/mysql
      - ./config/mysql/my.cnf:/etc/mysql/my.cnf
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_USER=admin
      - MYSQL_DATABASE=laravel
      - MYSQL_PASSWORD=secret
    networks:
      - laravel

I re-build the docker images and run it. The cronjob is working ok but when I access the localhost at localhost:8081. It isn't working anymore. The page show 502 Bad Gateway, so I checked the Nginx error log. This is the Nginx error shown me:

2020/04/10 13:33:36 [error] 8#8: *28 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.224.1, server: localhost, request: "GET /trades HTTP/1.1", upstream: "fastcgi://192.168.224.3:9000", host: "localhost:8081", referrer: "http://localhost:8081/home"

All the containers are still running after updated.

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
a2403ece8509        nginx:stable-alpine   "nginx -g 'daemon of…"   18 seconds ago      Up 17 seconds       0.0.0.0:8081->80/tcp   nginx_ctrade
69032097b7e4        ctrade_php            "docker-php-entrypoi…"   19 seconds ago      Up 18 seconds       9000/tcp               php_ctrade
592b483305d5        mysql:latest          "docker-entrypoint.s…"   3 hours ago         Up 18 seconds       3306/tcp, 33060/tcp    mysql_ctrade

Is there someone get this issue before? Any help would be appreciated! Thanks so much!

Duy Nguyen
  • 334
  • 4
  • 10

1 Answers1

2

According to the documentation, running two (or more) services inside of a Docker container breaks it's philosophy of single responsability.

It is generally recommended that you separate areas of concern by using one service per container. That service may fork into multiple processes (for example, Apache web server starts multiple worker processes). It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application. [...]

If you choose to follow this recommendation, you will end up with two options:

Option 1. Create a separated container that will handle the scheduling tasks.

Example:

# File: Dockerfile
FROM php:7.4.8-fpm-alpine
COPY ./cron.d/tasks /cron-tasks
RUN touch /var/log/cron.log
RUN chown www-data:www-data /var/log/cron.log
RUN /usr/bin/crontab -u www-data /cron-tasks
CMD ["crond", "-f", "-l", "8"]

# File: cron.d/tasks
* * * * * echo "Cron is working :D" >> /var/log/cron.log 2>&1

# File: docker-compose.yml
services:
    [...]
    scheduling:
      build:
        context: ./build
        dockerfile: cron.dockerfile
      [...]

Option 2. Use own host's crontab to execute the scheduled tasks on containers (as defended in this post).

Example:

# File on host: /etc/cron.d/my-laravel-apps
*  *  *  *  *  root  docker exec -t laravel-container-A php artisan schedule:run >> /dev/null 2>&1
*  *  *  *  *  root  docker exec -t laravel-container-B php artisan schedule:run >> /dev/null 2>&1
*  *  *  *  *  root  docker exec -t laravel-container-C php artisan schedule:run >> /dev/null 2>&1

PS: In your case, replace <laravel-container-*> by php_ctrade.


Option 3: Use supervisord

On the other hand, if you really want just one container at all, you may still use supervisord as your main process and configure it to initialize (and supervise) both php-fpm and crontab applications.

Note that this is a moderately heavy-weight approach and requires you to package supervisord and its configuration in your image (or base your image on one that includes supervisord), along with the different applications it manages.

You will find an example of how to do it here.


References:

Recommended reading:

cleybertandre
  • 301
  • 4
  • 8