'Executing a startup script when docker container is up

I built a docker image with Dockerfile as below. Everything's okay except but RUN php /var/www/api/startup.php This PHP code is simple, just an API request to get some data from outside server.

When I run this image, it works well but I get into the container and see the created file:ocr_url.json.. saying "error!!!".

When I run the php code in docker container in person, it works fine. So I checked the ENV variable: $SERVER. it returns "server-1" that I set in docker-compose.yml.

What's wrong? Does it execute PHP code before I get the ENV variable? Please help me through this problem. thanks

<?php

//echo $server = $_ENV['SERVER'];
$server = getenv('SERVER');

if($server) {
        $url = "https://{url}/?server=$server";

        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        //for debug only!
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($curl);

        curl_close($curl);

        //save to json file
        $file = fopen("ocr_url.json","w");
        fwrite($file, $resp);
        fclose($file);
}
else {
        $file = fopen("ocr_url.json","w");
        fwrite($file, 'error!!!');
        fclose($file);
}

Dockerfile

FROM server:v1.0

#startup program
CMD /root/startup.sh 
RUN php /var/www/api/startup.php

WORKDIR /var/www/api

docker-compose.yml

version: '3.8'

services:
  server1:
    image: '5318a9bfda5e'
    stdin_open: true
    tty: true
    ports:
      - '127.0.0.1:7771:80'
    environment:
      - 'SERVER=server-1'
  server2:
    image: '5318a9bfda5e'
    stdin_open: true
    tty: true
    ports:
      - '127.0.0.1:7772:80'
    environment:
      - 'SERVER=server-2'


Solution 1:[1]

Despite the order you have things in the Dockerfile, a RUN command always runs during the image build sequence, not at container startup, and it can never call out to other services. It also doesn't get to see Compose environment: settings or anything else outside a build: block. Whatever the output of the RUN command is will get compiled into the image, and since you're running the same image for both containers, they'll have the same downloaded file.

An entrypoint wrapper script might be a good match for this setup. When the container starts, make its main process be a script that first does the download from the other container, then runs the standard container CMD. The script could look like:

#!/bin/sh

# Download the file from elsewhere
php /var/www/api/startup.php
# (or consider writing it as a half-dozen lines of shell code)

# Run the main container process (from the Dockerfile CMD for example)
exec "$@"

Then in your Dockerfile, COPY this script in and make it be the ENTRYPOINT.

FROM server:v1.0

WORKDIR /var/www/api
# COPY entrypoint.sh .         # from the base image?
# RUN chmod +x entrypoint.sh   # Docker preserves permissions from the host

ENTRYPOINT ["./entrypoint.sh"] # must be JSON-array form
CMD /root/startup.sh           # unmodified from original Dockerfile

The file won't get downloaded during the image build, but if you launch a debugging shell

docker-compose run server1 sh

you will it will first download the file via the entrypoint script before launching the sh command.

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 David Maze