0

The following install.sh script file automate the installation of my Laravel dependencies inside a container:

#!/bin/bash

LOGFILE=/tmp/install_diario_$(date +"%Y%m%d%H%M%S").log


[ -f ../.env ] || cp ../.env.docker ../.env

function error {
    echo -e "\e[31m\e[1m[ERROR]"
    echo -e 'See' $LOGFILE 'to more information\e[0m'
    exit 1
}

function ok {
    echo -e "\t\e[32m\e[1m[OK]\e[0m"
}

function installed {
    echo -e "\t\e[29m\e[1m[OK]\e[0m"
}

echo '[+] Installing PHP packages'
composer install -d "/var/www/html" 2>> $LOGFILE >> $LOGFILE

if [ $? -eq 1 ]; then
    echo '[!] Configuration Aborted. Exiting...'    
fi

echo '[+] Generating app keys'
php ../artisan key:generate #2>> $LOGFILE >> $LOGFILE
php ../artisan passport:install #2>> $LOGFILE >> $LOGFILE


echo '[+] Populating database'
# cd .. && make resetdb

echo '[+] Backend installation sucessfull.'
echo ""

php ../artisan passport:show

echo '[+] Front-end install'
npm install 2>> $LOGFILE >> $LOGFILE

However, I don't want to run this manually, but while the container is starting. So I tried using the following commands in my Dockerfile:

WORKDIR /var/www/html/docker
ADD install.sh .
RUN chmod +x ./install.sh
CMD ./install.sh

Obs.: the script is inside a folder called docker

But when I run docker-compose up --build -d my container exits after a few seconds (when the script is done).

I tried looking for solutions but none worked for me (e.g. including /bin/bash in the end of my script).

Does anyone know if this is actually possible to be done, or should I just tell my workmates to run this script manually with docker exec -it <app_id> install.sh?

g medina
  • 43
  • 1
  • 8
  • Yeah the container exits, because the script finishes and exits, and a container with no running process in it is not a container anymore. Whatever you set CMD to needs to keep running as long as you want the container to be running for. – Sammitch Feb 01 '21 at 21:35
  • Also, a container re[initializing] external services during startup is probably going to turn into some form of problem in the long run. I would suggest at least separating the init and service portions into separate workflows. – Sammitch Feb 01 '21 at 21:37
  • _Also_ doing things like installing dependencies should happen during the _build_ process, not every time the container starts. – Sammitch Feb 01 '21 at 21:40
  • yeah I understand the container runs that and exits, but what do you mean with "separating the init and service portions into separate workflows"? Does it mean it's possible to accomplish what I want? – g medina Feb 01 '21 at 21:40
  • but can I run the commands in my install.sh script inside Dockerfile? No right? – g medina Feb 01 '21 at 21:42
  • https://stackoverflow.com/questions/37461868/difference-between-run-and-cmd-in-a-dockerfile – Sammitch Feb 01 '21 at 21:43

2 Answers2

1

The problem here is the following line in your Dockerfile:

CMD ./install.sh

Indeed, your script overrides (ie is called in place of) the default php-fpm command.

Solution 1: add a line at the end of your install.sh script to invoke php-fpm

exec "php-fpm"

CAVEAT: php-fpm MUST NOT be launched as a service, it must run in the foreground to keep the container up and running.

Solution 2: implement a custom entrypoint that launches the install script

  1. Remove/comment the CMD line from the Dockerfile
  2. Implement the customized entrypoint script.

Eg:

In the Dockerfile:

# Don't override COMMAND, use the default one
#CMD ./install.sh

COPY entrypoint /usr/bin/
RUN chmod +x /usr/bin/entrypoint
ENTRYPOINT /usr/bin/entrypoint

And the entrypoint script:

# Run the install script
/path/to/install.sh

# Execute the default command, ie php-fpm
exec "$@"

*NB: Here is the minimum basic working code, feel free to customize/enrich this example - using the official docker php entrypoint for instance.

Yannoff
  • 367
  • 2
  • 9
0

To a docker container, there is no distinction between its first start up from the consequence start unless you put some kind of file in a mounted volume.

What you probably want is a start up script that knows if this is the first start, run the install script, then remember to not run it again.

So besides your install script, you should probably have a start up script like this:

#!/bin/bash

# Assuming you mount this folder to your host system
MOUNTED_VAR=/var/run/laravel

# Only run the install on first run
if [ ! -f $MOUNTED_VAR/installed ]; then
  ./install.sh
fi

# Some command to start the service, for example
systemctl start php-fpm

In your docker file, you need to also include this script to start.

WORKDIR /var/www/html/docker
ADD install.sh .
RUN chmod +x ./install.sh
ADD start.sh .
RUN chmod +x ./start.sh
CMD ./start.sh
Koala Yeung
  • 7,475
  • 3
  • 30
  • 50