docker-compose, run a script after container has started? – Docker

Photo of author
Written By M Ibrahim
boot2docker docker-compose dockerfile rancher

The Problem:

You have a service running on Rancher managed by docker-compose. You desire to set a password after the container has been deployed. Rancher secrets allow you to mount a volume on your container with a file containing the secret. You want to execute a script to retrieve this secret and set it as a password in your configuration file. However, you do not want the secret to be stored in your Git repository and are looking for a solution to achieve this through docker-compose.

The Solutions:

Solution 1: Use a “bash” entry point and `restart: no`

In this solution, a second service is created named "mongosetup" that uses a "bash" entry point and restart: no. This service depends on the "mongo" service, ensuring that it starts only after the "mongo" service is up and running.

The entry point for the "mongosetup" service is configured as follows:

entrypoint: [ "bash", "-c", "sleep 10 && mongo --host mongo:27017 --eval 'rs.initiate()'" ]

This entry point effectively executes a bash script that sleeps for 10 seconds and then uses the mongo client to connect to the "mongo" service and initialize the replica set using the rs.initiate() command.

The restart: no setting ensures that the "mongosetup" service is not automatically restarted if it exits. This prevents the initialization script from being executed multiple times.

The result is a setup where the "mongo" service is started first, and then the "mongosetup" service is executed to initialize the replica set. This approach allows you to run a script after the "mongo" container has started.

Solution 2: Docker Compose Custom Script Execution

To execute a script after a container has started using Docker Compose, follow these steps:

  1. Create an Initialization Script:

    Create a script, let’s call it init.sh, that will perform the desired actions after the container startup.
  2. Add the Script to the Image:

    Copy the init.sh script to the image using COPY instruction in the Dockerfile.

    Dockerfile


    FROM sourceimage:tag
    COPY init.sh /usr/local/bin/
    ENTRYPOINT []

  3. Override the Entrypoint:

    The ENTRYPOINT defined in the base image (sourceimage) is overridden with an empty array []. This allows us to specify a custom command in the docker-compose.yml file.
  4. Specify the Custom Command:

    In the docker-compose.yml file, under the command: key, specify the custom command that will execute the init.sh script and then start the main executable. Use the following syntax:

    docker-compose.yml


    services:
    myservice:
    image: something:tag
    ...
    command: sh -c "/usr/local/bin/init.sh && exec myexecutable"

  5. Use exec:

    It’s crucial to use exec before calling the main executable (myexecutable in the example). This ensures that the main executable becomes the first process (PID1) and correctly receives signals like STOP, KILL (Ctrl-C), or HUP.

Solution 3: Using Docker Volumes

You can also leverage Docker volumes to accomplish this task. Here’s how you can do it:

services:
  example:
    image: <whatever>
    volume: ./init.sh:/init.sh
    entrypoint: sh -c "/init.sh"
  1. Create an Initialization Script:

    • Start by creating an initialization script named init.sh.
    • The script should contain the commands you need to perform after the container has started.
  2. Define the Docker Compose Service:

    • In your docker-compose.yml file, define a service called example or any other name you prefer.
    • Specify the image that you want to use for the container.
    • Define a volume to map your local init.sh script to a specific path within the container. In this case, it’s mapped to /init.sh.
  3. Specify the Entrypoint:

    • Set the entrypoint property to the following command:
      • sh -c "/init.sh"
    • This command tells Docker to run the init.sh script as the container’s entrypoint when it starts.
  4. Volume Considerations:

    • Keep in mind that using volumes mounts the host’s file system inside the container. Changes made to the files внутри контейнера will be reflected on the host’s file system.
  5. Test and Verify:

    • After setting up the docker-compose.yml file, you can run docker-compose up to start the container.
    • Once the container starts, the init.sh script will be executed, and the necessary actions (such as setting passwords) will be performed.

Solution 4: Use Rancher secret and rebuild container

Docker-compose is used to launch containers, not modify running ones. Rancher secrets can be referenced in the docker-compose.yml file, which creates a volume containing the secret. The default permissions for the secret file are User ID and Group ID 0 with File Mode 0444. Setting external to true in the secrets part indicates that the secret has already been created.

To update a running container, use the following steps:

  1. docker-compose up -d --no-deps --build <service_name>

This command builds the container, stops the old one, and starts the new one.

References: