Jak przekazać zmienne środowiskowe do kontenerów Docker?

827

Jestem nowy w Docker i nie jest jasne, jak uzyskać dostęp do zewnętrznej bazy danych z kontenera. Czy najlepszy sposób na kodowanie w ciągu połączenia?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
AJcodez
źródło

Odpowiedzi:

1240

Możesz przekazać zmienne środowiskowe do swoich kontenerów za pomocą -eflagi.

Przykład ze skryptu uruchamiania:

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

Lub, jeśli nie chcesz, aby wartość w wierszu polecenia, w której będzie wyświetlana przez psitd., -eMoże pobrać wartość z bieżącego środowiska, jeśli podasz ją bez =:

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

Jeśli masz wiele zmiennych środowiskowych, a zwłaszcza jeśli mają one być tajne, możesz użyć pliku env :

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

Flaga --env-file przyjmuje nazwę pliku jako argument i oczekuje, że każda linia ma format VAR = VAL, naśladując argument przekazany do --env. Wiersze komentarza muszą być poprzedzone tylko znakiem #

errata
źródło
Czy jest na to łatwiejszy sposób? Naprawdę irytujące jest konieczność ponownego tworzenia kontenera z różnymi zmiennymi za każdym razem. Może przechowywać go w pliku?
Jason Axelson
29
Przechowuję polecenia uruchamiania dokera w skryptach powłoki ((./start_staging.sh itp.)), A następnie wykonuję je zdalnie za pomocą Ansible.
errata
1
Mam problem z uruchomieniem drugiej wersji; Ustawiam PASSWORD = foo w środowisku, następnie przekazuję --env PASSWORD, i tylko słowo „PASSWORD” pojawia się w config.json kontenera; każda inna zmienna środowiskowa ma klucz i wartość. Korzystam z Docker 1.12.1.
Kevin Burke,
@KevinBurke: Myślę, że chcesz -e HASŁO = $ HASŁO, jeśli czytasz z bieżącego środowiska powłoki
errata
8
@KevinBurke: Zrób to, export PASSWORD=fooa zmienna zostanie przekazana docker runjako zmienna środowiskowa, dzięki czemu będzie docker run -e PASSWORDdziałać.
qerub
93

Możesz przekazać za pomocą -eparametrów z docker run ..poleceniem, jak wspomniano tutaj i jak wspomniano w @errata.
Jednak możliwym minusem tego podejścia jest to, że twoje poświadczenia będą wyświetlane na liście procesów, gdzie je uruchomisz.
Aby zwiększyć bezpieczeństwo, możesz zapisać swoje poświadczenia w pliku konfiguracyjnym i postępować zgodnie docker runz --env-fileopisem tutaj . Następnie możesz kontrolować dostęp do tego pliku konfiguracyjnego, aby inne osoby mające dostęp do tego komputera nie widziały twoich poświadczeń.

Sabin
źródło
2
Dodałem inny sposób rozwiązania tego problemu do odpowiedzi @ errata.
Bryan
21
Uważaj --env-file, kiedy użyjesz --envwartości env, będą one cytowane / oznaczone znakami ucieczki ze standardową semantyką jakiejkolwiek powłoki, której używasz, ale kiedy użyjesz --env-filewartości, które dostaniesz się do kontenera, będzie inaczej. Komenda uruchamiania dokera po prostu odczytuje plik, wykonuje bardzo podstawowe analizowanie i przekazuje wartości do kontenera, nie jest to równoważne z zachowaniem powłoki. Wystarczy mała uwaga, jeśli chcesz przekonwertować kilka --envwpisów na --env-file.
Shorn
5
Aby rozwinąć odpowiedź Shorna, podczas korzystania z pliku env musiałem umieścić bardzo długą wartość zmiennej środowiskowej w jednym wierszu, ponieważ wydaje się, że nie ma sposobu na wstawienie w niej podziału linii lub podzielenie go na wiele wierszy, takich jak: $ MY_VAR = rzeczy $ MY_VAR = $ MY_VAR więcej rzeczy
Jason White,
53

Jeśli używasz metody „docker-compose” jako metody rozbijania kontenerów, istnieje faktycznie przydatny sposób przekazania zmiennej środowiskowej zdefiniowanej na serwerze do kontenera Docker.

W twoim docker-compose.ymlpliku załóżmy, że rozpakowujesz podstawowy kontener hapi-js, a kod wygląda następująco:

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

Powiedzmy, że lokalny serwer, na którym znajduje się projekt dokera, ma zmienną środowiskową o nazwie „NODE_DB_CONNECT”, którą chcesz przekazać do kontenera hapi-js, i chcesz, aby jego nowa nazwa brzmiała „HAPI_DB_CONNECT”. Następnie w docker-compose.ymlpliku przekazujesz lokalną zmienną środowiskową do kontenera i zmieniasz jej nazwę w następujący sposób:

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

Mam nadzieję, że pomoże to uniknąć zakodowania na stałe ciągu połączenia z bazą danych w dowolnym pliku w kontenerze!

Marquistador
źródło
6
To nie zadziała. Te zmienne nie są przekazywane do kontenera.
Frondor
@Frondor naprawdę? Według tych dokumentów wydaje się, że tak powinno być.
darda
1
Problem z tym podejściem polega na tym, że zatwierdzasz zmienne środowiskowe w pliku docker-compose.yml do repozytorium git, czego nie powinieneś. Jak sobie z tym poradzisz? idealnie byłoby mieć osobny plik env, który jest gitignored i może importować / ładować do Dockerfile lub docker-compose.yml
Khaled Osman
35

Za pomocą docker-composemożna dziedziczyć zmienne env w pliku docker-compose.yml, a następnie w dowolnym pliku Docker, do którego są wywoływane docker-composekompilacje obrazów. Jest to przydatne, gdy Dockerfile RUNpolecenie powinno wykonywać polecenia specyficzne dla środowiska.

(twoja powłoka RAILS_ENV=developmentjuż istnieje w środowisku)

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}

Plik 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

W ten sposób dont potrzebę określenia zmiennych środowiskowych w plikach lub docker-compose build/ uppoleceń:

docker-compose build
docker-compose up
Joshweir
źródło
Czy muszą mieć to samo imię? Wydaje się to trochę mylące ... I jak miałbym zastąpić argumenty, jeśli zamiast tego chcę uruchomić programowanie?
CyberMew
@CyberMew Tak, muszą mieć tę samą nazwę między środowiskiem, docker-compose i Dockerfile. Jeśli zamiast tego chcesz uruchomić programowanie, przed uruchomieniem kompilacji dokera, uruchom RAILS_ENV = programowanie w swoim terminalu, aby ustawić zmienną środowiskową, w ten sposób kompilacja dokera i z kolei plik Docker odziedziczy tę wartość ze środowiska.
joshweir
30

Użyj -elub --env, aby ustawić zmienne środowiskowe (domyślnie []).

Przykład ze skryptu uruchamiania:

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

Jeśli chcesz używać wielu środowisk z wiersza poleceń, to przed każdą zmienną środowiskową użyj -eflagi.

Przykład:

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

Uwaga: pamiętaj, aby umieścić nazwę kontenera za zmienną środowiskową, a nie wcześniej.

Jeśli musisz skonfigurować wiele zmiennych, użyj --env-fileflagi

Na przykład,

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

Aby uzyskać inną pomoc, zajrzyj do pomocy Dockera:

 $ docker run --help

Oficjalna dokumentacja: https://docs.docker.com/compose/environment-variables/

Wisznu Miszra
źródło
2
Dlaczego potrzebujemy ubuntu bash? Czy ma to zastosowanie do obrazów utworzonych za pomocą ubuntu jako obrazu podstawowego czy do każdego obrazu?
Reyansh Kharga
Chciałbym przeczytać trochę o umieszczeniu nazwy kontenera po -eargumentach sprzed wieków! Nie mogę nawet zrozumieć, dlaczego sprawili, że stało się to konieczne ...
ironchicken
13

Jest fajny hack, w jaki sposób potokować zmienne środowiskowe komputera hosta do kontenera dokującego:

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

Użyj tej techniki bardzo ostrożnie, ponieważ env > env_filezrzuci WSZYSTKIE zmienne ENV maszyny hosta env_filei udostępni je w uruchomionym kontenerze.

Alex T.
źródło
5

Innym sposobem jest wykorzystanie mocy /usr/bin/env:

docker run ubuntu env DEBUG=1 path/to/script.sh
sanmai
źródło
2

Jeśli masz zmienne środowiskowe env.shlokalnie i chcesz je skonfigurować podczas uruchamiania kontenera, możesz spróbować

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

To polecenie uruchomiłoby kontener z powłoką bash (chcę powłoki bash, ponieważ sourcejest to polecenie bash), źródło env.shpliku (który ustawia zmienne środowiskowe) i wykonuje plik jar.

Że env.shwygląda to tak,

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

Dodałem printenvpolecenie tylko w celu przetestowania, czy faktycznie działa polecenie źródłowe. Prawdopodobnie powinieneś go usunąć, gdy potwierdzisz, że polecenie źródłowe działa poprawnie lub zmienne środowiskowe pojawią się w dziennikach dokera.

akilesh raj
źródło
2
dzięki temu podejściu będziesz musiał odbudować swój obraz dokera za każdym razem, gdy chcesz przekazać inny / zmodyfikowany zestaw env. Przekazywanie env podczas "docker --run --env-file ./somefile.txt" jest podejściem wyższym / dynamicznym.
Dmitrij Szewkoplyas
2
@DmitryShevkoplyas Zgadzam się. Mój przypadek użycia jest taki, że nie ma opcji podania --env-fileargumentu docker runpolecenia. Na przykład jeśli wdrażasz aplikację za pomocą silnika aplikacji Google, a aplikacja działająca w kontenerze wymaga zmiennych środowiskowych ustawionych w kontenerze dokera, nie masz bezpośredniego podejścia do ustawiania zmiennych środowiskowych, ponieważ nie masz kontroli nad docker runpoleceniem . W takim przypadku możesz mieć skrypt, który odszyfrowuje zmienne env przy użyciu powiedzmy KMS, i dodaje je do tych, env.shktóre można uzyskać w celu ustawienia zmiennych env.
akilesh raj
zamiast tego możesz użyć polecenia POSIX .(kropka) dostępnego regularnie . ( jest taki sam jak )shsourcesource.
go2null
1

Używając jq do konwersji env na JSON:

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

wymaga to jq w wersji 1.6 lub nowszej

to pusta env hosta jako json, zasadniczo tak jak w Dockerfile:

ENV HOST_ENV  (all env from the host as json)
Alexander Mills
źródło
Jak ta linia działa dla Ciebie docker run -e HOST_ENV="$env_as_json" <image>? : ? W moim przypadku Docker nie wydaje się rozpoznawać zmiennych lub podpowłok ( ${}lub $()), gdy jest przekazywany jako argument dokera . Na przykład: A=123 docker run --rm -it -e HE="$A" ubuntunastępnie wewnątrz tego kontenera: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HEZmienna tego nie robi.
Perplexabot
0

możemy również hostować zmienną środowiskową komputera za pomocą flagi -e i $:

Przed uruchomieniem należy wyeksportować (oznacza zestaw) lokalną zmienną env i plik lub tuż przed użyciem

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 

Korzystając z tej metody, ustaw zmienną env automatycznie z Twoim imieniem w moim przypadku (MG_HOST, MG_USER)

Dodatkowy:

Jeśli używasz Pythona, możesz uzyskać dostęp do tych zmiennych envment wewnątrz dokera

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
źródło
0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') Jest sposobem na grepowanie danych przechowywanych w a .envi przekazywanie ich do Dockera, bez przechowywania danych w sposób niezabezpieczony (więc nie można po prostu patrzeć docker historyi chwytać kluczy.

Załóżmy, że masz mnóstwo AWS .env:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

uruchomienie dokera z `` `docker run --rm -it --env-file <(bash -c 'env | grep AWS_') złapie wszystko i przekaże bezpiecznie, aby było dostępne z poziomu kontenera.

MadDanWithABox
źródło