Wie übergebe ich Umgebungsvariablen an Docker-Container?

829

Ich bin neu in Docker und es ist unklar, wie man von einem Container aus auf eine externe Datenbank zugreift. Ist der beste Weg, um die Verbindungszeichenfolge fest zu codieren?

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

Antworten:

1243

Sie können Umgebungsvariablen mit dem -eFlag an Ihre Container übergeben .

Ein Beispiel aus einem Startskript:

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

Wenn Sie den Wert nicht in der Befehlszeile haben möchten, in der er angezeigt wird psusw., -ekönnen Sie den Wert aus der aktuellen Umgebung abrufen, wenn Sie ihn nur ohne Folgendes angeben =:

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

Wenn Sie viele Umgebungsvariablen haben und diese insbesondere geheim sein sollen, können Sie eine env-Datei verwenden :

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

Das Flag --env-file verwendet einen Dateinamen als Argument und erwartet, dass jede Zeile das Format VAR = VAL hat, das das an --env übergebene Argument nachahmt. Kommentarzeilen müssen nur mit # vorangestellt werden

Errata
quelle
Gibt es einen einfacheren Weg, dies zu tun? Es ist wirklich irritierend, den Container jedes Mal mit verschiedenen Variablen neu erstellen zu müssen. Vielleicht in einer Datei speichern?
Jason Axelson
29
Ich speichere die Docker-Ausführungsbefehle in Shell-Skripten (./start_staging.sh usw.) und führe sie dann mit Ansible remote aus.
Errata
1
Ich habe Probleme, die zweite Version zum Laufen zu bringen. Ich setze PASSWORD = foo in der Umgebung und übergebe dann --env PASSWORD, und nur das Wort "PASSWORD" wird in der config.json des Containers angezeigt. Jede andere Umgebungsvariable hat einen Schlüssel und einen Wert. Ich verwende Docker 1.12.1.
Kevin Burke
@ KevinBurke: Ich denke, Sie wollen -e PASSWORD = $ PASSWORD, wenn Sie aus der aktuellen Shell-Umgebung lesen
Errata
8
@ KevinBurke: Tun Sie export PASSWORD=foostattdessen und die Variable wird docker runals Umgebungsvariable übergeben, damit die docker run -e PASSWORDArbeit funktioniert.
Qerub
93

Sie können -eParameter mit dem docker run ..Befehl übergeben, wie hier erwähnt und wie von @errata erwähnt.
Der mögliche Nachteil dieses Ansatzes besteht jedoch darin, dass Ihre Anmeldeinformationen in der Prozessliste angezeigt werden, in der Sie sie ausführen.
Um es sicherer zu machen, können Sie Ihre Anmeldeinformationen in einer Konfigurationsdatei schreiben und docker runmit --env-filewie erwähnt hier . Anschließend können Sie den Zugriff auf diese Konfigurationsdatei so steuern, dass andere Benutzer, die Zugriff auf diesen Computer haben, Ihre Anmeldeinformationen nicht sehen.

Sabin
quelle
2
Ich habe der Antwort von @ errata eine weitere Möglichkeit hinzugefügt, dieses Problem anzugehen.
Bryan
21
Seien Sie vorsichtig --env-file, wenn Sie --envIhre env-Werte verwenden, werden sie mit der Standardsemantik der von Ihnen verwendeten Shell in Anführungszeichen gesetzt / maskiert. Bei Verwendung --env-fileder Werte, die Sie in Ihrem Container erhalten, ist dies jedoch anders. Der Befehl docker run liest nur die Datei, analysiert sie sehr einfach und leitet die Werte an den Container weiter. Dies entspricht nicht dem Verhalten Ihrer Shell. Nur ein kleiner Punkt, den Sie beachten sollten, wenn Sie eine Reihe von --envEinträgen in einen konvertieren --env-file.
Geschoren
5
Um die Antwort von Shorn näher zu erläutern, musste ich bei der Verwendung der env-Datei den Wert einer sehr langen Umgebungsvariablen in eine Zeile setzen, da es anscheinend keine Möglichkeit gibt, einen Zeilenumbruch einzufügen oder in einen zu unterteilen mehrere Zeilen wie: $ MY_VAR = Zeug $ MY_VAR = $ MY_VAR mehr Zeug
Jason White
53

Wenn Sie "Docker-Compose" als Methode zum Hochfahren Ihrer Container verwenden, gibt es tatsächlich eine nützliche Möglichkeit, eine auf Ihrem Server definierte Umgebungsvariable an den Docker-Container zu übergeben.

docker-compose.ymlAngenommen, Sie drehen in Ihrer Datei einen einfachen Hapi-JS-Container und der Code sieht folgendermaßen aus:

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

Angenommen, der lokale Server, auf dem sich Ihr Docker-Projekt befindet, verfügt über eine Umgebungsvariable mit dem Namen 'NODE_DB_CONNECT', die Sie an Ihren hapi-js-Container übergeben möchten, und der neue Name lautet 'HAPI_DB_CONNECT'. Dann würden Sie in der docker-compose.ymlDatei die lokale Umgebungsvariable an den Container übergeben und wie folgt umbenennen:

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

Ich hoffe, dies hilft Ihnen dabei, das Festcodieren einer Datenbankverbindungszeichenfolge in einer beliebigen Datei in Ihrem Container zu vermeiden!

Marquistador
quelle
6
Das wird nicht funktionieren. Diese Variablen werden nicht an den Container übergeben.
Frondor
@Frondor wirklich? Nach diesen Unterlagen scheint es so, als ob es sollte.
Darda
1
Das Problem bei diesem Ansatz besteht darin, dass Sie die Umgebungsvariablen in der Datei docker-compose.yml in das Git-Repository übertragen, was Sie nicht sollten. Wie gehst du damit um? Idealerweise hätten Sie eine separate env-Datei, die gitignored ist und in die Docker-Datei oder docker-compose.yml importieren / laden kann
Khaled Osman
35

Mit docker-composekönnen Sie env-Variablen in docker-compose.yml und anschließend alle Docker-Dateien erben, die docker-composezum Erstellen von Images aufgerufen werden . Dies ist nützlich, wenn der Dockerfile RUNBefehl umgebungsspezifische Befehle ausführen soll.

(Ihre Shell ist RAILS_ENV=developmentbereits in der Umgebung vorhanden.)

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

Auf diese Weise muss ich keine Umgebungsvariablen in Dateien oder docker-compose build/ upBefehlen angeben :

docker-compose build
docker-compose up
Joshweir
quelle
Müssen sie den gleichen Namen haben? Scheint etwas verwirrend. Und wie würde ich die Argumente überschreiben, wenn ich stattdessen die Entwicklung ausführen möchte?
CyberMew
@CyberMew Ja, sie müssen zwischen Ihrer Umgebung, Docker-Compose und Dockerfile denselben Namen haben. Wenn Sie stattdessen die Entwicklung ausführen möchten, führen Sie vor dem Ausführen des Docker-Compose-Builds RAILS_ENV = development in Ihrem Terminal aus, um die Umgebungsvariable festzulegen. Auf diese Weise übernimmt Docker-Compose und Dockerfile diesen Wert von Ihrer Umgebung.
Joshweir
30

Verwenden -eSie den Wert oder --env, um Umgebungsvariablen festzulegen (Standard []).

Ein Beispiel aus einem Startskript:

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

Wenn Sie mehrere Umgebungen über die Befehlszeile verwenden möchten, verwenden Sie vor jeder Umgebungsvariablen das -eFlag.

Beispiel:

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

Hinweis: Stellen Sie sicher, dass der Containername nach der Umgebungsvariablen und nicht davor steht.

Wenn Sie viele Variablen einrichten müssen, verwenden Sie das --env-fileFlag

Zum Beispiel,

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

Weitere Hilfe finden Sie in der Docker-Hilfe:

 $ docker run --help

Offizielle Dokumentation: https://docs.docker.com/compose/environment-variables/

Vishnu Mishra
quelle
2
Warum brauchen wir ubuntu bash? Gilt dies für Bilder, die mit Ubuntu als Basisbild erstellt wurden, oder für jedes Bild?
Reyansh Kharga
Ich wünschte, ich hätte etwas darüber gelesen, wie man den Containernamen nach den -eArgumenten vor langer Zeit einfügt! Ich kann nicht einmal verstehen, warum sie dies notwendig gemacht haben ...
Ironchicken
13

Es gibt einen netten Hack, wie Host-Computer-Umgebungsvariablen an einen Docker-Container weitergeleitet werden:

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

Verwenden Sie sehr sorgfältig diese Technik, da env > env_filewird Dump alle Host - Maschine ENV Variablen env_fileund machen sie im laufenden Behälter zugänglich.

Alex T.
quelle
5

Eine andere Möglichkeit besteht darin, die Kräfte von /usr/bin/env:

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

Wenn Sie die Umgebungsvariablen env.shlokal haben und sie beim Starten des Containers einrichten möchten, können Sie es versuchen

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

Dieser Befehl würde den Container mit einer Bash-Shell starten (ich möchte eine Bash-Shell, da sourcees sich um einen Bash-Befehl handelt), die env.shDatei als Quelle (die die Umgebungsvariablen festlegt) und die JAR-Datei ausführen.

Das env.shsieht so aus,

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

Ich habe den printenvBefehl nur hinzugefügt, um zu testen, ob der eigentliche Quellbefehl funktioniert. Sie sollten es wahrscheinlich entfernen, wenn Sie bestätigen, dass der Quellbefehl ordnungsgemäß funktioniert oder die Umgebungsvariablen in Ihren Docker-Protokollen angezeigt werden.

Akilesh Raj
quelle
2
Bei diesem Ansatz müssen Sie Ihr Docker-Image jedes Mal neu erstellen, wenn Sie einen anderen / geänderten Env-Satz übergeben möchten. Das Übergeben von envs während "docker --run --env-file ./somefile.txt" ist ein überlegener / dynamischer Ansatz.
Dmitry Shevkoplyas
2
@DmitryShevkoplyas Ich stimme zu. In meinem Anwendungsfall gibt es keine Möglichkeit, das --env-fileArgument für einen docker runBefehl anzugeben . Wenn Sie beispielsweise eine Anwendung mithilfe der Google App Engine bereitstellen und die im Container ausgeführte App Umgebungsvariablen benötigt, die im Docker-Container festgelegt sind, haben Sie keinen direkten Ansatz zum Festlegen der Umgebungsvariablen, da Sie keine Kontrolle über den docker runBefehl haben . In einem solchen Fall könnten Sie ein Skript haben, das die env-Variablen mit beispielsweise KMS entschlüsselt und zu dem hinzufügt env.sh, aus dem die env-Variablen festgelegt werden können.
Akilesh Raj
Sie können den .regulären Befehl POSIX (Punkt) shanstelle von verwenden source. ( sourceist das gleiche wie .)
go2null
1

Verwenden von jq zum Konvertieren der Umgebung in JSON:

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

Dies erfordert jq Version 1.6 oder neuer

Dies verdrängt den Host env als json, im Wesentlichen wie in Dockerfile:

ENV HOST_ENV  (all env from the host as json)
Alexander Mills
quelle
Wie funktioniert diese Linie für Sie?: docker run -e HOST_ENV="$env_as_json" <image>? In meinem Fall scheint Docker keine Variablen oder Subshells ( ${}oder $()) aufzulösen, wenn sie als Docker-Argumente übergeben werden. Zum Beispiel: A=123 docker run --rm -it -e HE="$A" ubuntudann in diesem Container: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... Die HEVariable schafft es nicht.
Perplexabot
0

Wir können auch Maschinenumgebungsvariablen mit dem Flag -e und $ hosten:

Vor dem Ausführen müssen lokale Env-Variablen und -Dateien oder kurz vor der Verwendung exportiert (dh festgelegt) werden

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 

Mit dieser Methode setzen Sie die env-Variable in meinem Fall automatisch mit Ihrem Vornamen (MG_HOST, MG_USER).

Zusätzlich:

Wenn Sie Python verwenden, können Sie über Docker auf diese Envment-Variable zugreifen

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
quelle
0

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') Ist eine Möglichkeit, die in a gespeicherten Daten zu erfassen .envund an Docker weiterzuleiten, ohne dass etwas unsicher gespeichert wird (Sie können also nicht nur docker historySchlüssel anzeigen und abrufen.

Angenommen, Sie haben eine Menge AWS-Inhalte auf Ihre .envArt und Weise:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

Wenn Sie Docker mit `` `Docker ausführen, führen Sie --rm -it --env-file <(bash -c 'env | grep AWS_') aus, um alles zu erfassen und sicher zu übergeben, damit Sie aus dem Container heraus darauf zugreifen können.

MadDanWithABox
quelle