'Dockerfile RUN instruction not working correctly when using jelastic/nginxphp

I just started with Jelastic and I'm trying to create a container based on jelastic/nginxphp:1.20.2-php-8.0.13. The final goal is to integrate my Symfony development in a container I will execute in Jelastic. As first step I tried to run 'composer install' in my docker file. It builds fine (no error) but when looking into the container the vendor directory is not there. If I rerun the 'composer install' directly into the container, the vendor directory is well created. Here is the content of my Dockerfile:

FROM jelastic/nginxphp:1.20.2-php-8.0.13
    
# Set build arguments
ARG APP_ENV=prod
   
# Set main params
ENV APP_HOME /var/www/webroot
ENV APP_ENV $APP_ENV
  
COPY infra/jelastic/index.php $APP_HOME/ROOT/
    
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
  
COPY symfony/composer.* $APP_HOME/
    
WORKDIR $APP_HOME
    
RUN set -xe \
    && if [ "$APP_ENV" = "prod" ]; then export ARGS="--no-dev"; fi \
    && composer install --prefer-dist --optimize-autoloader --classmap-authoritative --no-interaction --no-ansi $ARGS
    
RUN composer dump-autoload --classmap-authoritative
    
CMD service php-fpm start && nginx -g "daemon off;"

More globally, it seems the RUN instruction in the docker file doesn't work as exepected: I also tried to remove some files/directories but at the end nothing is removed and no error is shown during build.

Advanced thanks. Jacques

Is the end goal to run this as a "certified container" within Jelastic, so you have access to Jelastic add-ons like Let's Encrypt and so on, or do you simply want to run a Docker image in Jelastic? For the latter, I would recommend to use a more "standard" image as your base. – Damien

Following the recommendation of Damien, I have created a new Dockerfile based on a more standard base. When testing n my development machine everything is fine but when using the container in Jelastic, I see the following errors in the run.log file:

No valid login shell found for user nobody 2021-12-22 11:21:58,046 INFO Set uid to user 65534 succeeded 2021-12-22 11:21:58,081 CRIT could not write pidfile /run/supervisord.pid 2021-12-22 11:21:59,082 INFO spawnerr: unknown error making dispatchers for 'nginx': EACCES 2021-12-22 11:21:59,083 INFO spawnerr: unknown error making dispatchers for 'php-fpm': EACCES 2021-12-22 11:22:00,083 INFO gave up: nginx entered FATAL state, too many start retries too quickly 2021-12-22 11:22:00,084 INFO gave up: php-fpm entered FATAL state, too many start retries too quickly

Here are the files I'm using.

Dockerfile:

# 1st stage : build js & css
FROM node:14-alpine AS builder
    
WORKDIR /wamsbot
    
ENV WAMS_BASE_URL=http://127.0.0.1:8000
    
ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV
    
COPY symfony/package.json symfony/yarn.lock symfony/webpack.config.js ./
COPY symfony/assets ./assets
    
RUN mkdir -p public \
    && NODE_ENV=development yarn install \
    && yarn run build
    
FROM composer AS composer
    
# Copy the source directory and install the dependencies with composer
WORKDIR /wamsbot
COPY symfony/composer.* ./
  
# Run composer install to install the dependencies
RUN if [ "$APP_ENV" = "prod" ]; then export ARGS="--no-dev"; fi \
    && composer install --prefer-dist --optimize-autoloader --classmap-authoritative --no-interaction --no-ansi $ARGS
    
COPY symfony/ ./
    
RUN composer dump-autoload --classmap-authoritative
    
    
# continue stage build with the desired image and copy the source including the
# dependencies downloaded by composer
FROM alpine:3
    
# Install packages and remove default server definition
RUN apk --no-cache add \
    curl \
    nginx \
    php8 \
    php8-ctype \
    php8-curl \
    php8-dom \
    php8-fpm \
    php8-gd \
    php8-intl \
    php8-json \
    php8-mbstring \
    php8-mysqli \
    php8-opcache \
    php8-openssl \
    php8-phar \
    php8-session \
    php8-simplexml \
    php8-xml \
    php8-tokenizer \
    php8-xmlreader \
    php8-zlib \
    supervisor \
    && rm -f /etc/nginx/conf.d/default.conf
    
# Create symlink so programs depending on `php` still function
RUN ln -s /usr/bin/php8 /usr/bin/php
    
# Configure nginx
COPY infra/prod/config/nginx.conf /etc/nginx/nginx.conf
    
# Configure PHP-FPM
COPY infra/prod/config/fpm-pool.conf /etc/php8/php-fpm.d/www.conf
COPY infra/prod/config/php.ini /etc/php8/conf.d/custom.ini
    
# Configure supervisord
COPY infra/prod/config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
    
# Setup document root
RUN mkdir -p /var/www/wamsbot
    
# Make sure files/folders needed by the processes are accessable when they run under the nobody user
RUN chown -R nobody.nobody /var/www/wamsbot \
    && chown -R nobody.nobody /run \
    && chown -R nobody.nobody /var/lib/nginx \
    && chown -R nobody.nobody /var/log/nginx
  
# Switch to use a non-root user from here on
USER nobody
   
# Add application
WORKDIR /var/www/wamsbot
COPY --chown=nobody symfony/ /var/www/wamsbot/
    
ARG APP_ENV=prod
ARG APP_DEBUG=0
    
ARG GOOGLE_APPLICATION_CREDENTIALS_PATH
    
ENV APP_ENV $APP_ENV
ENV APP_DEBUG $APP_DEBUG
    
COPY --from=composer --chown=nobody /wamsbot/ /var/www/wamsbot
COPY --from=builder --chown=nobody /wamsbot/public/build /var/www/wamsbot/public/build
/var/www/wamsbot/public/build
    
# Copy key files
RUN mkdir -p /tmp/keys
COPY $GOOGLE_APPLICATION_CREDENTIALS_PATH /tmp/keys/google_key.json
    
# Memory limit increase is required by the dev image
RUN php -d memory_limit=256M bin/console cache:clear
RUN php bin/console assets:install --symlink --relative public \
    && rm -rf /var/www/wamsbot/assets
    
# Expose the port nginx is reachable on
EXPOSE 8080
    
# Let supervisord start nginx & php-fpm
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
    
# Configure a healthcheck to validate that everything is up&running
HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1:8080/fpm-ping

fpm-pool.conf:

[global]
; Log to stderr
error_log = /dev/stderr
    
[www]
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on
;                            a specific port;
;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
;                            a specific port;
;   'port'                 - to listen on a TCP socket to all addresses
;                            (IPv6 and IPv4-mapped) on a specific port;
;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = 127.0.0.1:9000
    
; Enable status page
pm.status_path = /fpm-status
    
; Ondemand process manager
pm = ondemand
    
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 100
    
; The number of seconds after which an idle process will be killed.
; Note: Used only when pm is set to 'ondemand'
; Default Value: 10s
pm.process_idle_timeout = 10s;
    
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
; Default Value: 0
pm.max_requests = 1000
    
; Make sure the FPM workers can reach the environment variables for configuration
clear_env = no
    
; Catch output from PHP
catch_workers_output = yes
    
; Remove the 'child 10 said into stderr' prefix in the log and only show the actual message
decorate_workers_output = no
    
; Enable ping page to use in healthcheck
ping.path = /fpm-ping

nginx.conf:

worker_processes auto;
error_log stderr warn;
pid /run/nginx.pid;
    
events {
    worker_connections 1024;
}
    
http {
    include mime.types;
    default_type application/octet-stream;
    
    # Define custom log format to include reponse times
    log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" '
                          '$request_time $upstream_response_time $pipe $upstream_cache_status';
    
    access_log /dev/stdout main_timed;
    error_log /dev/stderr notice;
    
    keepalive_timeout 65;
    
    # Write temporary files to /tmp so they can be created as a non-privileged user
    client_body_temp_path /tmp/client_temp;
    proxy_temp_path /tmp/proxy_temp_path;
    fastcgi_temp_path /tmp/fastcgi_temp;
    uwsgi_temp_path /tmp/uwsgi_temp;
    scgi_temp_path /tmp/scgi_temp;
    
    # Default server definition
    server {
        listen [::]:8080 default_server;
        listen 8080 default_server;
        server_name _;
    
        sendfile off;
    
        root /var/www/wamsbot/public;
        index index.php index.html;
    
        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to index.php
            try_files $uri $uri/ /index.php?q=$uri&$args;
        }
    
        # Redirect server error pages to the static page /50x.html
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /var/lib/nginx/html;
        }
    
        # Pass the PHP scripts to PHP-FPM listening on 127.0.0.1:9000
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME $fastcgi_script_name;
            fastcgi_index index.php;
            include fastcgi_params;
        }
    
        location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
            expires 5d;
        }
    
        # Deny access to . files, for security
        location ~ /\. {
            log_not_found off;
            deny all;
        }
    
        # Allow fpm ping and status from localhost
        location ~ ^/(fpm-status|fpm-ping)$ {
            access_log off;
            allow 127.0.0.1;
            deny all;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_pass 127.0.0.1:9000;
        }
    }
    
    gzip on;
    gzip_proxied any;
    gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;
    gzip_vary on;
    gzip_disable "msie6";
    
    # Include other server configs
    include /etc/nginx/conf.d/*.conf;
}

php.ini:

[Date]
date.timezone="UTC"

supervisord.conf:

[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
user=nobody
    
[program:php-fpm]
command=php-fpm8 -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
    
[program:nginx]
command=nginx -g 'daemon off;'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0

I would appreciate some help. Thanks.



Solution 1:[1]

The mentioned behavior occurred because the /var/www/webroot is declared as volume for jelastic/nginxphp:1.20.2-php-8.0.13 - so any changes made by RUN command inside this directory during the build do not persist. But the files which are created by the COPY or ADD commands persist, so the workaround would be to use the multi-stage build:

  1. On the first stage, you use the mentioned above jelastic/nginxphp:1.20.2-php-8.0.13 image, put the symfony/composer.* in any directory other than the /var/www/webroot (for example '/var/www/app') and run the "composer install" in '/var/www/app'.

  2. On the second stage, you use the jelastic/nginxphp:1.20.2-php-8.0.13 again, and copy the content of 'app' directory from step 1 using the following instruction:

    COPY --from=0 /var/www/app /var/www/webroot/ROOT

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jelastic