Cómo usar variables de entorno en Docker compose

217

Me gustaría poder usar variables env dentro de docker-compose.yml, con valores pasados ​​en el momento de docker-compose. Este es el ejemplo. Estoy haciendo esto hoy con el comando básico Docker Run, que está envuelto en mi propio script. ¿Hay alguna manera de lograrlo con componer, sin esos envoltorios de bash?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
fuente
2
Para conocer las diferentes opciones, consulte: docs.docker.com/compose/environment-variables
Massood Khaari
2
Está resuelto en la última versión de componer, su ejemplo funcionará tal cual. consulte docs.docker.com/compose/compose-file/#variable-substitution acerca de la sustitución de variables.
natbusa
1
No olvide la aplicación docker (desde junio de 2018): stackoverflow.com/a/51007138/6309
VonC

Respuestas:

93
  1. Cree un template.yml, que es su docker-compose.ymlvariable de entorno.
  2. Suponga que sus variables de entorno están en un archivo 'env.sh'
  3. Coloque el siguiente código en un archivo sh y ejecútelo.

fuente env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

Se docker-compose.ymlgenerará un nuevo archivo con los valores correctos de las variables de entorno.

Ejemplo de archivo template.yml:

oracledb:
        image: ${ORACLE_DB_IMAGE}
        privileged: true
        cpuset: "0"
        ports:
                - "${ORACLE_DB_PORT}:${ORACLE_DB_PORT}"
        command: /bin/sh -c "chmod 777 /tmp/start; /tmp/start"
        container_name: ${ORACLE_DB_CONTAINER_NAME}

Archivo env.sh de muestra:

#!/bin/bash 
export ORACLE_DB_IMAGE=<image-name> 
export ORACLE_DB_PORT=<port to be exposed> 
export ORACLE_DB_CONTAINER_NAME=ORACLE_DB_SERVER
Saurabh Kumar
fuente
@Meet Siéntase libre de revisar mi respuesta a continuación, en "Solución BASH", donde describo este enfoque un poco más a fondo.
modulitos
77
¿Todavía no hay una mejor solución en este momento?
lvthillo
13
¿por qué eliminarías recursivamente un archivo? (rm -rf docker-compose.yml)
moritzschaefer
@ lorenzvth7 Puede consultar mi respuesta a continuación, que creo que es un poco más exhaustiva: stackoverflow.com/a/33186458/1884158
modulitos
55
-1 esta solución solo complica las cosas y debe actualizarse de acuerdo con las nuevas habilidades de docker-compose docs.docker.com/compose/environment-variables/…
Efrat Levitan
240

La solución DOCKER:

Parece que docker-compose 1.5+ ha habilitado la sustitución de variables: https://github.com/docker/compose/releases

El último Docker Compose le permite acceder a variables de entorno desde su archivo de redacción. Para que pueda obtener sus variables de entorno, luego ejecute Compose así:

set -a
source .my-env
docker-compose up -d

Luego puede hacer referencia a las variables en docker-compose.yml usando $ {VARIABLE}, así:

db:
  image: "postgres:${POSTGRES_VERSION}"

Y aquí hay más información de los documentos, tomada aquí: https://docs.docker.com/compose/compose-file/#variable-substitution

Cuando ejecuta docker-compose con esta configuración, Compose busca la variable de entorno POSTGRES_VERSION en el shell y sustituye su valor en. Para este ejemplo, Compose resuelve la imagen en postgres: 9.3 antes de ejecutar la configuración.

Si no se establece una variable de entorno, Componer sustituye con una cadena vacía. En el ejemplo anterior, si POSTGRES_VERSION no está configurado, el valor de la opción de imagen es postgres :.

Se admiten las sintaxis $ VARIABLE y $ {VARIABLE}. Las características extendidas de estilo de shell, como $ {VARIABLE-default} y $ {VARIABLE / foo / bar}, no son compatibles.

Si necesita poner un signo de dólar literal en un valor de configuración, use un signo de dólar doble ($$).

Y creo que esta característica se agregó en esta solicitud de extracción: https://github.com/docker/compose/pull/1765

La solución BASH:

Noté que la gente tiene problemas con el soporte de variables de entorno de Docker. En lugar de tratar con variables de entorno en Docker, volvamos a lo básico, como bash! Aquí hay un método más flexible que utiliza un script bash y un .envarchivo.

Un ejemplo de archivo .env:

EXAMPLE_URL=http://example.com
# Note that the variable below is commented out and will not be used:
# EXAMPLE_URL=http://example2.com 
SECRET_KEY=ABDFWEDFSADFWWEFSFSDFM

# You can even define the compose file in an env variable like so:
COMPOSE_CONFIG=my-compose-file.yml
# You can define other compose files, and just comment them out
# when not needed:
# COMPOSE_CONFIG=another-compose-file.yml

luego ejecute este script bash en el mismo directorio, que debería implementar todo correctamente:

#!/bin/bash

docker rm -f `docker ps -aq -f name=myproject_*`
set -a
source .env
cat ${COMPOSE_CONFIG} | envsubst | docker-compose -f - -p "myproject" up -d

Simplemente haga referencia a sus variables env en su archivo de composición con la sintaxis bash habitual (es decir, ${SECRET_KEY}para insertarla SECRET_KEYdesde el .envarchivo).

Tenga en cuenta que COMPOSE_CONFIGse define en mi .envarchivo y se usa en mi script bash, pero puede reemplazarlo fácilmente {$COMPOSE_CONFIG}con el my-compose-file.ymlscript bash.

También tenga en cuenta que etiqueté esta implementación al nombrar todos mis contenedores con el prefijo "myproject". Puede usar cualquier nombre que desee, pero ayuda a identificar sus contenedores para que pueda consultarlos fácilmente más adelante. Suponiendo que sus contenedores no tienen estado, como deberían ser, este script eliminará y volverá a implementar sus contenedores rápidamente de acuerdo con sus parámetros de archivo .env y su archivo YAML de composición.

Actualización Dado que esta respuesta parece bastante popular, escribí una publicación de blog que describe mi flujo de trabajo de implementación de Docker con más profundidad: http://lukeswart.net/2016/03/lets-deploy-part-1/ Esto podría ser útil cuando agregue más complejidad para una configuración de implementación, como configuraciones nginx, certificados LetsEncrypt y contenedores vinculados.

modulitos
fuente
2
Puedes simplemente en grep foo file.textlugar de cat file.text | grep foo. En mi caso tuve que hacerlo export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín
"Me doy cuenta de que la gente tiene problemas con el soporte de variables de entorno de Docker". ¿Tiene algún detalle o un enlace a un ticket?
tleyden
Lo sentimos, no registré el problema específico que estaba experimentando, y fue hace mucho tiempo (~ 6 meses), no sé si aún es relevante. Pero sí, algunas funciones en el soporte variable de entorno Docker tenían errores, y varios usuarios lo informaron. Creo que es mucho mejor ahora. Pero cuando la configuración de implementación se vuelve significativamente compleja, preferiría modularizarla usando bash para manejar la lógica de configuración y Docker Compose para la orquestación del contenedor.
modulitos
8
PSA: esto solo funciona condocker-compose up y no con docker-compose run.
Kriegslustig
55
Existe esta solución docs.docker.com/compose/compose-file/#envfile que utilizo cuando agrega variables de entorno desde .envabajo env_file. Luego puede hacer referencia a las variables en el docker-compose.ymluso${VARIABLE}
musale
111

Parece que docker-compose tiene soporte nativo ahora para las variables de entorno predeterminadas en el archivo .

todo lo que necesita hacer es declarar sus variables en un archivo llamado .envy estarán disponibles en docker-compose.yml.

Por ejemplo, para .envarchivo con contenido:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Puede acceder a su variable dentro docker-compose.ymlo reenviarla al contenedor:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P
fuente
44
¡Esta es la mejor solución!
Ladenkov Vladislav
44
Esto funcionó para mí también. No sé por qué, pero el nombre del archivo debería ser literal .env, por ejemplo, config.envno me funcionó.
HBat
1
@HBat el "." significa un archivo oculto - este es el procedimiento habitual para los archivos de configuración locales
Jeremy Hajek
2
La mejor solucion. y podríamos agregar / etc / environment props y usarlos como entorno con el uso de .env. Eso será más seguro.
Chinthaka Dinadasa
24

Lo siguiente es aplicable para docker-compose 3.x Establecer variables de entorno dentro del contenedor

método - 1 método recto

web:
  environment:
    - DEBUG=1
      POSTGRES_PASSWORD: 'postgres'
      POSTGRES_USER: 'postgres'

método - 2 El archivo ".env"

Cree un archivo .env en la misma ubicación que docker-compose.yml

$ cat .env
TAG=v1.5
POSTGRES_PASSWORD: 'postgres'

y tu archivo de redacción será como

$ cat docker-compose.yml
version: '3'
services:
  web:
    image: "webapp:${TAG}"
    postgres_password: "${POSTGRES_PASSWORD}"

fuente

Gajendra D Ambi
fuente
2
Me gustaría ver un ejemplo completo del método 1. No pude hacer que esto funcionara, así que terminé usando el archivo .env (que funcionó bien).
BobHy
20

Cuando use variables de entorno para volúmenes que necesita:

  1. crear un archivo .env en la misma carpeta que contiene el docker-compose.yaml archivo

  2. declarar variable en el .envarchivo:

    HOSTNAME=your_hostname
    
  3. Cambiar $hostnamea ${HOSTNAME}en el docker-compose.yaml archivo

    proxy:
      hostname: ${HOSTNAME}
      volumes:
        - /mnt/data/logs/${HOSTNAME}:/logs
        - /mnt/data/${HOSTNAME}:/data
    

Por supuesto, puede hacerlo dinámicamente en cada compilación como:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
fuente
99
Nota, de acuerdo con los documentos:The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.
James Gentes
19

La mejor manera es especificar variables de entorno fuera del docker-compose.ymlarchivo. Puede usar la env_fileconfiguración y definir su archivo de entorno dentro de la misma línea. Luego, hacer un docker-componer nuevamente debería recrear los contenedores con las nuevas variables de entorno.

Así es como se ve mi docker-compose.yml:

services:
  web:
    env_file: variables.env

Nota: docker-compose espera que cada línea en un archivo env esté en VAR=VALformato. Evite usar exportdentro del .envarchivo. Además, el .envarchivo debe colocarse en la carpeta donde se ejecuta el comando docker-compose.

Jibu James
fuente
2
La mejor manera
Dany
NO. No hará que las variables de entorno estén disponibles automáticamente dentro del contenedor acoplable. Aún debe mencionarlos explícitamente en la sección de entorno.
kta
6

No puedes ... todavía. Pero esta es una alternativa, piense como un generador docker-composer.yml:

https://gist.github.com/Vad1mo/9ab63f28239515d4dafd

Básicamente un script de shell que reemplazará sus variables. También puede usar la tarea Grunt para construir su archivo de composición de Docker al final de su proceso de CI.

Thomas Decaux
fuente
4

Tengo un script bash simple que creé para esto, solo significa ejecutarlo en su archivo antes de usarlo: https://github.com/antonosmond/subber

Básicamente, simplemente cree su archivo de composición utilizando llaves dobles para denotar variables de entorno, por ejemplo:

app:
    build: "{{APP_PATH}}"
ports:
    - "{{APP_PORT_MAP}}"

Cualquier cosa entre llaves dobles se reemplazará con la variable de entorno del mismo nombre, así que si tuviera las siguientes variables de entorno establecidas:

APP_PATH=~/my_app/build
APP_PORT_MAP=5000:5000

al ejecutar subber docker-compose.ymlel archivo resultante se vería así:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"
Anton
fuente
2

Hasta donde yo sé, este es un trabajo en progreso. Quieren hacerlo, pero aún no se ha lanzado. Ver 1377 (el "nuevo" 495 que fue mencionado por @Andy).

Terminé implementando el enfoque "generar .yml como parte de CI" propuesto por @Thomas.

anroots
fuente
1

agregar env al archivo .env

Como

VERSION=1.0.0

luego guárdelo en deploy.sh

INPUTFILE=docker-compose.yml
RESULT_NAME=docker-compose.product.yml
NAME=test

prepare() {
        local inFile=$(pwd)/$INPUTFILE
        local outFile=$(pwd)/$RESULT_NAME
        cp $inFile $outFile
        while read -r line; do
            OLD_IFS="$IFS"
            IFS="="
            pair=($line)
            IFS="$OLD_IFS"
               sed -i -e "s/\${${pair[0]}}/${pair[1]}/g" $outFile
            done <.env
     }
       
deploy() {
        docker stack deploy -c $outFile $NAME
}

        
prepare
deploy
    
Foxundermon
fuente
1

Utilice el archivo .env para definir valores dinámicos en docker-compse.yml. Ya sea puerto o cualquier otro valor.

Muestra docker-compose:

testcore.web:
       image: xxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/testcore:latest
       volumes: 
            - c:/logs:c:/logs
       ports:
            - ${TEST_CORE_PORT}:80
       environment:
            - CONSUL_URL=http://${CONSUL_IP}:8500 
            - HOST=${HOST_ADDRESS}:${TEST_CORE_PORT}

Dentro del archivo .env puede definir el valor de estas variables:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002
Sorabzone
fuente
1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Use la versión 3.6:

version: "3.6"
services:
  one:
    image: "nginx:alpine"
    environment:
      foo: "bar"
      SOME_VAR:
      baz: "${OTHER_VAR}"
    labels:
      some-label: "$SOME_VAR"
  two:
    image: "nginx:alpine"
    environment:
      hello: "world"
      world: "${SOME_VAR}"
    labels:
      some-label: "$OTHER_VAR"

Lo obtuve de este enlace https://github.com/docker/cli/issues/939

usuario2851100
fuente
1

Desde 1.25.4, docker-compose admite la opción --env-file que le permite especificar un archivo que contiene variables.

El tuyo debería verse así:

hostname=my-host-name

Y el comando:

docker-compose --env-file /path/to/my-env-file config
Papillon
fuente