Come faccio a passare le variabili di ambiente ai contenitori Docker?


830

Sono nuovo di Docker ed è poco chiaro come accedere a un database esterno da un contenitore. È il modo migliore per codificare nella stringa di connessione?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

Risposte:


1247

È possibile passare le variabili di ambiente ai contenitori con il -eflag.

Un esempio da uno script di avvio:

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

Oppure, se non si desidera avere il valore sulla riga di comando in cui verrà visualizzato ps, ecc., È -epossibile estrarre il valore dall'ambiente corrente se lo si dà semplicemente senza =:

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

Se hai molte variabili d'ambiente e specialmente se sono pensate per essere segrete, puoi usare un file env :

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

Il flag --env-file prende un nome file come argomento e si aspetta che ogni riga sia nel formato VAR = VAL, imitando l'argomento passato a --env. Le righe di commento devono essere precedute solo da #


C'è un modo più semplice per farlo? È davvero irritante dover ricreare ogni volta il contenitore con variabili diverse. Forse salvarlo in un file?
Jason Axelson,

29
Memorizzo i comandi di esecuzione della finestra mobile in script shell, (./start_staging.sh ecc.), Quindi li eseguo in remoto utilizzando Ansible.
errata,

1
Ho problemi a far funzionare la seconda versione; Ho impostato PASSWORD = pippo nell'ambiente, quindi ho passato --env PASSWORD e solo la parola "PASSWORD" appare nel file config.json del contenitore; ogni altra variabile d'ambiente ha una chiave e un valore. Sto usando Docker 1.12.1.
Kevin Burke,

@KevinBurke: Penso che tu voglia -e PASSWORD = $ PASSWORD se stai leggendo dall'attuale ambiente shell
errata

8
@KevinBurke: Do export PASSWORD=fooinvece e la variabile verrà passata docker runcome variabile d'ambiente, facendo docker run -e PASSWORDfunzionare.
qerub,

93

Puoi passare usando i -eparametri con il docker run ..comando come menzionato qui e come indicato da @errata.
Tuttavia, il possibile svantaggio di questo approccio è che le credenziali verranno visualizzate nell'elenco dei processi, dove lo si esegue.
Per renderlo più sicuro, è possibile scrivere le proprie credenziali in un file di configurazione e fare docker runcon --env-filecome accennato qui . Quindi puoi controllare l'accesso a quel file di configurazione in modo che gli altri che hanno accesso a quel computer non vedano le tue credenziali.


2
Ho aggiunto un altro modo per rispondere a questa preoccupazione alla risposta di @ errata.
Bryan,

21
Fai attenzione --env-file, quando usi i --envtuoi valori env verranno quotati / sfuggiti alla semantica standard di qualunque shell tu stia usando, ma quando usi --env-filei valori che otterrai all'interno del tuo contenitore sarà diverso. Il comando docker run legge solo il file, esegue analisi di base e passa i valori al contenitore, non è equivalente al modo in cui la shell si comporta. Solo un piccolo gotcha da tenere presente se stai convertendo un sacco di --envvoci in un --env-file.
Shorn

5
Per elaborare la risposta Shorn, quando ho usato il file env, ho dovuto mettere il valore di una variabile d'ambiente molto lungo tutto su una riga poiché non sembra esserci alcun modo per inserire un'interruzione di riga o dividerlo in più righe come: $ MY_VAR = cose $ MY_VAR = $ MY_VAR altre cose
Jason White,

53

Se stai usando 'docker-compose' come metodo per far girare i tuoi container, c'è effettivamente un modo utile per passare una variabile d'ambiente definita sul tuo server al container Docker.

Nel tuo docker-compose.ymlfile, supponiamo che tu stia facendo girare un contenitore hapi-js di base e il codice assomigli a:

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

Supponiamo che il server locale su cui si trova il progetto docker abbia una variabile di ambiente denominata "NODE_DB_CONNECT" che si desidera passare al contenitore hapi-js e che si desideri che il suo nuovo nome sia "HAPI_DB_CONNECT". Quindi, nel docker-compose.ymlfile, passeresti la variabile di ambiente locale al contenitore e rinominalo in questo modo:

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

Spero che questo ti aiuti a evitare di codificare a fondo una stringa di connessione al database in qualsiasi file nel tuo contenitore!


6
Questo non funzionerà. Queste variabili non vengono passate al contenitore.
Frondor,

@Frondor davvero? Secondo questi documenti sembra che dovrebbe.
darda,

1
Il problema con questo approccio è che si impegnano le variabili di ambiente nel file docker-compose.yml nel repository git che non dovresti. Come si aggira questo? idealmente avresti un file env separato che è gitignored e può importare / caricare nel Dockerfile o docker-compose.yml
Khaled Osman

35

Usando docker-compose, puoi ereditare le variabili env in docker-compose.yml e successivamente in qualsiasi Dockerfile chiamato / i da compilare docker-composeper creare immagini. Ciò è utile quando il Dockerfile RUNcomando deve eseguire comandi specifici per l'ambiente.

(la tua shell è RAILS_ENV=developmentgià esistente nell'ambiente)

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}

File Docker :

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

In questo modo non è necessario specificare le variabili di ambiente nei file o docker-compose build/ upcomandi:

docker-compose build
docker-compose up

Devono essere lo stesso nome? Sembra un po 'confuso .. E come potrei ignorare gli arg se invece volessi eseguire lo sviluppo?
CyberMew,

@CyberMew Sì, devono avere lo stesso nome tra il tuo ambiente, docker-compose e Dockerfile. Se invece vuoi eseguire lo sviluppo, prima di eseguire la compilazione docker-compose, esegui RAILS_ENV = sviluppo nel tuo terminale per impostare la variabile d'ambiente, in questo modo docker-compose e a sua volta Dockerfile erediterà quel valore dal tuo ambiente.
joshweir,

31

Utilizzare -eo --env value per impostare le variabili di ambiente (default []).

Un esempio da uno script di avvio:

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

Se si desidera utilizzare più ambienti dalla riga di comando, prima di ogni variabile di ambiente utilizzare il -eflag.

Esempio:

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

Nota: assicurarsi di inserire il nome del contenitore dopo la variabile di ambiente, non prima.

Se devi impostare molte variabili, usa il --env-fileflag

Per esempio,

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

Per qualsiasi altro aiuto, consultare la guida di Docker:

 $ docker run --help

Documentazione ufficiale: https://docs.docker.com/compose/environment-variables/


2
Perché ne abbiamo bisogno ubuntu bash? Si applica alle immagini create con Ubuntu come immagine di base o ad ogni immagine?
Reyansh Kharga,

Vorrei aver letto un po 'di come mettere il nome del contenitore dopo gli -eargomenti di anni fa! Non riesco nemmeno a capire perché lo abbiano reso necessario ...
Ironchicken,

13

C'è un bel trucco su come convogliare le variabili di ambiente della macchina host in un contenitore docker:

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

Utilizzare questa tecnica con molta attenzione, perché env > env_filescaricherà TUTTE le variabili ENV della macchina host env_filee le renderà accessibili nel contenitore in esecuzione.



5

Un altro modo è utilizzare i poteri di /usr/bin/env:

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

2

Se le variabili di ambiente sono env.shlocalmente e si desidera impostarle all'avvio del contenitore, è possibile provare

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

Questo comando avvia il contenitore con una shell bash (voglio una shell bash poiché sourceè un comando bash), genera il env.shfile (che imposta le variabili di ambiente) ed esegue il file jar.

Gli env.shsguardi come questo,

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

Ho aggiunto il printenvcomando solo per verificare che il comando sorgente effettivo funzioni. Probabilmente dovresti rimuoverlo quando confermi che il comando source funziona correttamente o che le variabili di ambiente verranno visualizzate nei log della finestra mobile.


2
con questo approccio dovrai ricostruire l'immagine della finestra mobile ogni volta che vuoi passare un set di env diverso / modificato. Passare envs durante "docker --run --env-file ./somefile.txt" è un approccio superiore / dinamico.
Dmitry Shevkoplyas,

2
@DmitryShevkoplyas Sono d'accordo. Il mio caso d'uso è dove non c'è alcuna opzione per specificare l' --env-filearg ad un docker runcomando. Ad esempio, se si sta distribuendo un'applicazione utilizzando il motore dell'app di Google e l'app in esecuzione all'interno del contenitore necessita di variabili di ambiente impostate all'interno del contenitore docker, non si ha un approccio diretto per impostare le variabili di ambiente poiché non si ha il controllo sul docker runcomando . In tal caso, potresti avere uno script che decodifica le variabili env usando say, KMS e le aggiunge a quelle env.shche possono essere acquistate per impostare le variabili env.
Akilesh Raj,

puoi usare il .comando POSIX (punto) disponibile in maniera regolare shanziché source. ( sourceè uguale a .)
go2null

1

Utilizzando jq per convertire env in JSON:

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

questo richiede jq versione 1.6 o successiva

questo pust l'host env come json, essenzialmente come in Dockerfile:

ENV HOST_ENV  (all env from the host as json)

Come funziona quella linea per te docker run -e HOST_ENV="$env_as_json" <image>? : ? Nel mio caso Docker non sembra risolvere variabili o subshells ( ${}o $()) quando viene passato come argomento docker. Ad esempio: A=123 docker run --rm -it -e HE="$A" ubuntuquindi all'interno di quel contenitore: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... La HEvariabile non ce la fa.
Perplexabot,

0

possiamo anche ospitare la variabile di ambiente della macchina usando -e flag e $:

Prima di eseguire è necessario esportare (significa impostare) la variabile env locale e il file o appena prima dell'uso

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 

Utilizzando questo metodo imposta automaticamente la variabile env con il tuo nome nel mio caso (MG_HOST, MG_USER)

Ulteriori:

Se stai usando Python puoi accedere a queste variabili di ambiente all'interno della finestra mobile di

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')

0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') È un modo per eseguire il grep dei dati archiviati in a .enve passarli a Docker, senza che nulla venga archiviato in modo non sicuro (quindi non puoi semplicemente guardare docker historye afferrare le chiavi.

Supponi di avere un sacco di cose AWS nel tuo .envmodo così:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

eseguendo docker con `` docker run --rm -it --env-file <(bash -c 'env | grep AWS_') afferrerà tutto e lo passerà in modo sicuro per essere accessibile dall'interno del contenitore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.