¿Cómo paso variables de entorno a los contenedores Docker?

830

Soy nuevo en Docker y no está claro cómo acceder a una base de datos externa desde un contenedor. ¿Es la mejor forma de codificar en la cadena de conexión?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
AJcodez
fuente

Respuestas:

1247

Puede pasar variables de entorno a sus contenedores con la -ebandera.

Un ejemplo de un script de inicio:

sudo docker run -d -t -i -e REDIS_NAMESPACE='staging' \ 
-e POSTGRES_ENV_POSTGRES_PASSWORD='foo' \
-e POSTGRES_ENV_POSTGRES_USER='bar' \
-e POSTGRES_ENV_DB_NAME='mysite_staging' \
-e POSTGRES_PORT_5432_TCP_ADDR='docker-db-1.hidden.us-east-1.rds.amazonaws.com' \
-e SITE_URL='staging.mysite.com' \
-p 80:80 \
--link redis:redis \  
--name container_name dockerhub_id/image_name

O, si no desea tener el valor en la línea de comandos donde se mostrará ps, etc., -epuede obtener el valor del entorno actual si solo lo proporciona sin =:

sudo PASSWORD='foo' docker run  [...] -e PASSWORD [...]

Si tiene muchas variables de entorno y especialmente si están destinadas a ser secretas, puede usar un archivo env :

$ docker run --env-file ./env.list ubuntu bash

El indicador --env-file toma un nombre de archivo como argumento y espera que cada línea esté en el formato VAR = VAL, imitando el argumento pasado a --env. Las líneas de comentarios solo necesitan tener el prefijo #

errata
fuente
¿Hay una manera más fácil para hacer esto? Es realmente irritante tener que volver a crear el contenedor con diferentes variables cada vez. ¿Quizás guardarlo en un archivo?
Jason Axelson
29
Guardo los comandos de ejecución de Docker en scripts de shell (./start_staging.sh, etc.) y luego los ejecuto de forma remota con Ansible.
errata
1
Tengo problemas para que funcione la segunda versión; Establezco PASSWORD = foo en el entorno, luego paso --env PASSWORD, y solo aparece la palabra "PASSWORD" en config.json del contenedor; cualquier otra variable de entorno tiene una clave y un valor. Estoy usando Docker 1.12.1.
Kevin Burke
@KevinBurke: Creo que quieres -e CONTRASEÑA = $ CONTRASEÑA si estás leyendo desde el entorno actual de la shell
erratas del
8
@KevinBurke: Haga en su export PASSWORD=foolugar y la variable se pasará a docker runcomo una variable de entorno, haciendo que docker run -e PASSWORDfuncione.
qerub
93

Puede pasar usando -eparámetros con el docker run ..comando como se menciona aquí y como lo menciona @errata.
Sin embargo, la posible desventaja de este enfoque es que sus credenciales se mostrarán en la lista de procesos, donde la ejecuta.
Para hacerlo más seguro, puede escribir sus credenciales en un archivo de configuración y hacer docker runcon --env-filecomo se ha mencionado aquí . Luego puede controlar el acceso a ese archivo de configuración para que otras personas que tengan acceso a esa máquina no vean sus credenciales.

Sabin
fuente
2
Agregué otra forma de abordar esta preocupación a la respuesta de @errata.
Bryan
21
Tenga cuidado --env-file, cuando use --envsus valores env, se citarán / escaparán con la semántica estándar de cualquier shell que esté usando, pero cuando use --env-filelos valores que obtendrá dentro de su contenedor serán diferentes. El comando docker run simplemente lee el archivo, realiza un análisis muy básico y pasa los valores al contenedor, no es equivalente al comportamiento de su shell. Solo un pequeño problema para tener en cuenta si está convirtiendo un montón de --enventradas a un --env-file.
Shorn
55
Para dar más detalles sobre la respuesta de Shorn, al usar el archivo env, tuve que poner el valor de una variable de entorno muy larga en una sola línea, ya que no parece haber ninguna forma de poner un salto de línea o dividirlo en múltiples líneas como: $ MY_VAR = cosas $ MY_VAR = $ MY_VAR más cosas
Jason White
53

Si está utilizando 'docker-compose' como método para hacer girar sus contenedores, en realidad hay una forma útil de pasar una variable de entorno definida en su servidor al contenedor Docker.

En su docker-compose.ymlarchivo, supongamos que está girando un contenedor básico de hapi-js y el código se ve así:

hapi_server:
  container_name: hapi_server
  image: node_image
  expose:
    - "3000"

Supongamos que el servidor local en el que se encuentra su proyecto de Docker tiene una variable de entorno llamada 'NODE_DB_CONNECT' que desea pasar a su contenedor hapi-js y desea que su nuevo nombre sea 'HAPI_DB_CONNECT'. Luego, en el docker-compose.ymlarchivo, debe pasar la variable de entorno local al contenedor y cambiarle el nombre de esta manera:

hapi_server:
  container_name: hapi_server
  image: node_image
  environment:
    - HAPI_DB_CONNECT=${NODE_DB_CONNECT}
  expose:
    - "3000"

¡Espero que esto te ayude a evitar codificar una cadena de conexión de base de datos en cualquier archivo de tu contenedor!

Marquistador
fuente
66
Esto no funcionara. Esas variables no se pasan al contenedor.
Frondor
@Frondor realmente? Según estos documentos , parece que debería.
Darda
1
El problema con este enfoque es que confirma las variables de entorno en el archivo docker-compose.yml en el repositorio git, lo que no debería hacer. ¿Cómo se soluciona esto? idealmente, tendría un archivo env separado que está oculto y puede importar / cargar en el Dockerfile o docker-compose.yml
Khaled Osman
35

Utilizando docker-compose, puede heredar variables env en docker-compose.yml y, posteriormente, cualquier Dockerfile (s) llamado por docker-composeconstruir imágenes. Esto es útil cuando el Dockerfile RUNcomando debe ejecutar comandos específicos para el entorno.

(su shell RAILS_ENV=developmentya existe en el entorno)

docker-compose.yml :

version: '3.1'
services:
  my-service: 
    build:
      #$RAILS_ENV is referencing the shell environment RAILS_ENV variable
      #and passing it to the Dockerfile ARG RAILS_ENV
      #the syntax below ensures that the RAILS_ENV arg will default to 
      #production if empty.
      #note that is dockerfile: is not specified it assumes file name: Dockerfile
      context: .
      args:
        - RAILS_ENV=${RAILS_ENV:-production}
    environment: 
      - RAILS_ENV=${RAILS_ENV:-production}

Dockerfile :

FROM ruby:2.3.4

#give ARG RAILS_ENV a default value = production
ARG RAILS_ENV=production

#assign the $RAILS_ENV arg to the RAILS_ENV ENV so that it can be accessed
#by the subsequent RUN call within the container
ENV RAILS_ENV $RAILS_ENV

#the subsequent RUN call accesses the RAILS_ENV ENV variable within the container
RUN if [ "$RAILS_ENV" = "production" ] ; then echo "production env"; else echo "non-production env: $RAILS_ENV"; fi

De esta manera yo no necesidad de especificar las variables de entorno en archivos o docker-compose build/ upcomandos:

docker-compose build
docker-compose up
joshweir
fuente
¿Tienen que ser el mismo nombre? Parece un poco confuso ... ¿Y cómo anularía los argumentos si quisiera ejecutar el desarrollo?
CyberMew
@CyberMew Sí, deben tener el mismo nombre entre su entorno, docker-compose y Dockerfile. Si desea ejecutar el desarrollo, antes de ejecutar la compilación docker-compose, ejecute RAILS_ENV = development en su terminal para establecer la variable de entorno, de esa manera docker-compose y Dockerfile heredará ese valor de su entorno.
joshweir
31

Use el -evalor o --env para establecer variables de entorno (predeterminado []).

Un ejemplo de un script de inicio:

 docker run  -e myhost='localhost' -it busybox sh

Si desea utilizar múltiples entornos desde la línea de comando, antes de cada variable de entorno utilice el -eindicador.

Ejemplo:

 sudo docker run -d -t -i -e NAMESPACE='staging' -e PASSWORD='foo' busybox sh

Nota: Asegúrese de colocar el nombre del contenedor después de la variable de entorno, no antes de eso.

Si necesita configurar muchas variables, use la --env-filebandera

Por ejemplo,

 $ docker run --env-file ./my_env ubuntu bash

Para cualquier otra ayuda, consulte la ayuda de Docker:

 $ docker run --help

Documentación oficial: https://docs.docker.com/compose/environment-variables/

Vishnu Mishra
fuente
2
¿Por qué lo necesitamos ubuntu bash? ¿Aplica para imágenes creadas con ubuntu como imagen base o para cada imagen?
Reyansh Kharga
¡Ojalá hubiera leído un poco sobre poner el nombre del contenedor después de los -eargumentos de hace años! Ni siquiera puedo empezar a entender por qué hicieron que esto fuera necesario ...
ironchicken
13

Hay un buen truco para canalizar las variables de entorno de la máquina host a un contenedor acoplable:

env > env_file && docker run --env-file env_file image_name

Use esta técnica con mucho cuidado, porque env > env_filevolcará TODAS las variables ENV de la máquina host env_filey las hará accesibles en el contenedor en ejecución.

Alex T
fuente
5

Otra forma es usar los poderes de /usr/bin/env:

docker run ubuntu env DEBUG=1 path/to/script.sh
sanmai
fuente
2

Si tiene las variables de entorno env.shlocalmente y desea configurarlo cuando se inicia el contenedor, puede intentar

COPY env.sh /env.sh
COPY <filename>.jar /<filename>.jar
ENTRYPOINT ["/bin/bash" , "-c", "source /env.sh && printenv && java -jar /<filename>.jar"]

Este comando iniciaría el contenedor con un shell bash (quiero un shell bash ya que sourcees un comando bash), obtiene el env.sharchivo (que establece las variables de entorno) y ejecuta el archivo jar.

Se env.shve así,

#!/bin/bash
export FOO="BAR"
export DB_NAME="DATABASE_NAME"

Agregué el printenvcomando solo para probar que el comando fuente real funciona. Probablemente debería eliminarlo cuando confirme que el comando de origen funciona bien o las variables de entorno aparecerían en los registros de su ventana acoplable.

akilesh raj
fuente
2
con este enfoque, tendrá que reconstruir su imagen de acoplador cada vez que desee pasar un conjunto de entornos diferente / modificado. Pasar envs durante "docker --run --env-file ./somefile.txt" es un enfoque superior / dinámico.
Dmitry Shevkoplyas
2
@DmitryShevkoplyas Estoy de acuerdo. Mi caso de uso es donde no hay opción de especificar el --env-fileargumento a un docker runcomando. Por ejemplo, si está implementando una aplicación utilizando el motor de aplicaciones de Google y la aplicación que se ejecuta dentro del contenedor necesita variables de entorno establecidas dentro del contenedor de docker, no tiene un enfoque directo para establecer las variables de entorno ya que no tiene control sobre el docker runcomando . En tal caso, podría tener un script que descifre las variables env usando say, KMS, y las agregue a las env.shque se pueden obtener para establecer las variables env.
akilesh raj
puede usar el .comando POSIX (punto) disponible en forma regular en shlugar de source. ( sourcees lo mismo que .)
go2null
1

Usando jq para convertir el env a JSON:

env_as_json=`jq -c -n env`
docker run -e HOST_ENV="$env_as_json" <image>

esto requiere jq versión 1.6 o posterior

esto empuja al host host como json, esencialmente así en Dockerfile:

ENV HOST_ENV  (all env from the host as json)
Alexander Mills
fuente
¿Cómo te funciona esa línea docker run -e HOST_ENV="$env_as_json" <image>? : En mi caso, Docker no parece resolver variables o subcapas ( ${}o $()) cuando se pasa como argumentos de Docker . Por ejemplo: A=123 docker run --rm -it -e HE="$A" ubuntuluego dentro de ese contenedor: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... La HEvariable no lo hace.
Perplexabot
0

también podemos hospedar la variable de entorno de la máquina usando -e flag y $:

Antes de ejecutar, necesita exportar (significa conjunto) la variable y archivo env local o justo antes de usar

docker run -it -e MG_HOST=$MG_HOST -e MG_USER=$MG_USER -e MG_PASS=$MG_PASS -e MG_AUTH=$MG_AUTH -e MG_DB=$MG_DB -t image_tag_name_and_version 

Al usar este método, establezca la variable env automáticamente con su nombre de pila en mi caso (MG_HOST, MG_USER)

Adicional:

Si está utilizando Python, puede acceder a estas variables de entorno dentro de Docker al

import os
host,username,password,auth,database=os.environ.get('MG_HOST'),os.environ.get('MG_USER'),os.environ.get('MG_PASS'),os.environ.get('MG_AUTH'),os.environ.get('MG_DB')
mobin alhassan
fuente
0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') Es una forma de recopilar los datos almacenados dentro de a .envy pasarlos a Docker, sin que nada se almacene de forma insegura (por lo que no puede simplemente mirar docker historyy tomar las teclas.

Digamos que tiene un montón de cosas de AWS en su .envgusto, así:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

ejecutando docker con `` docker run --rm -it --env-file <(bash -c 'env | grep AWS_') lo tomará todo y lo pasará de forma segura para que sea accesible desde dentro del contenedor.

MadDanWithABox
fuente