73
votes

I have a service that I am bringing up through Rancher via docker-compose. The issue I am running into is that I need to set a password after the container has been deployed.

The way rancher secrets work, is that I set my secret in and rancher will mount a volume on my container with a file containing my secret. I was hoping to be able to execute a script to grab that secret, and set it as a password on my config file.

I don't believe I have a way to get that secret in through the Dockerfile as I don't want the secret to be in git, so I'm left looking at doing it via docker-compose.

Does anyone know if this is possible?

4
Absolutely, that's a fairly normal way of setting secrets. Just add the relevant shell script as (or to) your CMD or ENTRYPOINT.Paul Hicks
to have access to secret without expose in Dockerfile, you can use .env file with docker-compose : docs.docker.com/compose/environment-variablesbcag2

4 Answers

38
votes

The trick is to overwrite the compose COMMAND to perform whatever init action you need before calling the original command.

  1. Add a script in your image that will perform the init work that you want like set password, change internal config files, etc. Let's call it init.sh. You add it to your image.

Dockerfile:

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

The above overrides whatever ENTRYPOINT is defined in the sourceimage. That's to make this example simpler. Make sure you understand what the ENTRYPOINT is doing in the Dockerfile from the sourceimage and call it in the command: of the docker-compose.yml file.

docker-compose.yml:

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

It's important to use exec before calling the main command. That will install the command as the first process (PID1) which will make it receive signals like STOP, KILL (Ctrl-C on keyboard) or HUP.

29
votes

This is the way I use for calling a script after a container is started without overriding the entrypoint.

In my example, I used it for initializing the replicaset of my local MongoDB

services:
  mongo:
    image: mongo:4.2.8
    hostname: mongo
    container_name: mongodb
    entrypoint: ["/usr/bin/mongod","--bind_ip_all","--replSet","rs0"]
    ports:
      - 27017:27017
  mongosetup:
    image: mongo:4.2.8
    depends_on:
      - mongo
    restart: "no"
    entrypoint: [ "bash", "-c", "sleep 10 && mongo --host mongo:27017 --eval 'rs.initiate()'"]      
  • In the first part, I simply launch my service (mongo)
  • The second service use a "bash" entry point AND a restart: no <= important

I also use a depends_on between service and setup service for manage the launch order.

6
votes

You can also use volumes to do this:

services:
  example:
    image: <whatever>
    volume: ./init.sh:/init.sh
    entrypoint: sh -c "/init.sh"

Note that this will mount init.sh to the container, not copy it (if that matters, usually it doesn't). Basically processes within the container can modify init.sh and it would modify the file as it exists in your actual computer.

4
votes

docker-compose specify how to launch containers, not how to modify an existing running container.

The Rancher documentation mentions that, for default usage of secrets, you can reference the secret by name in the secrets array in the docker-compose.yml.

The target filename will be the same name as the name of the secret.
By default, the target filename will be created as User ID and Group ID 0, and File Mode of 0444.
Setting external to true in the secrets part will make sure it knows the secret has already been created.

Example of a basic docker-compose.yml:

version: '2'
services:
  web:
    image: sdelements/lets-chat
    stdin_open: true
    secrets:
    - name-of-secret
    labels:
      io.rancher.container.pull_image: always
secrets:
  name-of-secret:
    external: true

As illustrated in "How to Update a Single Running docker-compose Container", updating a container would involve a "build, kill, and up" sequence.

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