Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute scripts after docker-compose up?

I'm trying to make my dev process easier/maintainable using docker(-compose). I do not want to use any volumes (if that's possible). Why does import.sh not get executed after I run 'docker-compose up -d'?

I have the following files:

docker-compose.yml   mysql   ---- import.sh   ---- db.sql   ---- Dockerfile 

in docker-compose.yml there is:

version: '2'  services:   database:     image: mysql     build:       context: ./mysql/       dockerfile: Dockerfile     container_name: mysqltest     ports:       - "3306:3306"     environment:       MYSQL_ROOT_PASSWORD: 123456 

in /mysql/Dockerfile there is:

ADD import.sh /tmp/import.sh ADD db.sql /tmp/db.sql RUN /tmp/import.sh 

in /mysql/db.sql there is:

CREATE DATABASE test1; CREATE DATABASE test2; CREATE DATABASE test3; 
like image 521
p0rter Avatar asked Feb 08 '17 15:02

p0rter


People also ask

What happens when you run docker compose up?

The docker compose up command aggregates the output of each container (like docker compose logs --follow does). When the command exits, all containers are stopped. Running docker compose up --detach starts the containers in the background and leaves them running.

How do I run multiple commands in docker compose?

We can also use the | operator to run multiple commands in Docker Compose. The syntax of the | operator is a bit different from the && operator. Here, we added the commands on separate lines. Everything is the same except for the command instruction.


2 Answers

You can use ENTRYPOINT or CMD in your Dockerfile to execute a command when the container starts. The difference between them is that ENTRYPOINT is executed any time the container is started, while CMD might be replaced with an command line option. Assuming the command you want to execute is X

docker run my-image Y 

will execute X if ENTRYPOINT X was in the Dockerfile and Y if CMD X was in the Dockerfile.

However, there are two caveats:

  1. The command will be executed every time the container is started.
  2. After the command terminates the container is shut down.

Therefore, a typical solution is to have a docker-entrypoint script. It checks whether it is run in a fresh container initiating its environment and afterwards executes the container's actual program. Have a look at the official mysql Dockerfile and entrypoint to get an idea.

An example entrypoint script could look like this:

$ cat docker_entrypoint.sh                                                                                                                                           if [ ! -f .initialized ]; then                                                                                                                                                                                         echo "Initializing container"                                                                                                                                                                                      # run initializing commands                                                                                                                                                                                        touch .initialized                                                                                                                                                                                             fi                                                                                                                                                                                                                  exec "$@" 

First, it checks whether there is a file called .initialized. If there is none, some commands are run to initialize the container environment. After which touch .initialized creates .initialized as an empty file. Therefore, subsequent container starts won't execute the initialization command again. Secondly, it starts the actual service. Doing this with exec will replace the shell process with the service's process. Hence, docker will keep the container running until the service terminates. "$@" will contain the "container/image command". This is set with CMD X in the Dockerfile and is overriden on the command, as I already pointed out above. By using exec "$@" you will be able to start different programs in the container for inspection, e.g. bash, and start the service by default, as specified in the Dockerfile's CMD statement.

like image 175
fzgregor Avatar answered Sep 28 '22 09:09

fzgregor


If you just want to initialize your db in the very first time, you can use this easy way.

    volumes:       - [the scripts dir]:/docker-entrypoint-initdb.d 

Initializing a fresh instance When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.

Doc is here: https://docs.docker.com/samples/library/mysql/

like image 33
helsonxiao Avatar answered Sep 28 '22 11:09

helsonxiao