Dockerコンテナーに環境変数を渡すにはどうすればよいですか?


830

私はDockerを使い始めたばかりですが、コンテナから外部データベースにアクセスする方法がわかりません。接続文字列にハードコードする最善の方法はありますか?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

回答:


1247

-eフラグを使用して、環境変数をコンテナに渡すことができます。

起動スクリプトの例:

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

または、コマンドラインに値が表示されないようにしたい場合psなどは-e、現在の環境から値を取得できます=

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

多くの環境変数があり、特にそれらが秘密にされている場合は、env-fileを使用できます

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

--env-fileフラグはファイル名を引数として取り、各行がVAR = VAL形式であることを想定して、-envに渡される引数を模倣します。コメント行の先頭には#のみを付ける必要があります


これを行う簡単な方法はありますか?毎回異なる変数を使用してコンテナを再作成する必要があるのは本当に苛立たしいことです。多分それをファイルに保存しますか?
Jason Axelson 2016

29
docker runコマンドをシェルスクリプト(./start_staging.shなど)に保存し、Ansibleを使用してリモートで実行します。
エラータ2016

1
2番目のバージョンを機能させるのに問題があります。環境でPASSWORD = fooを設定してから--env PASSWORDを渡すと、コンテナのconfig.jsonに「PASSWORD」という単語のみが表示されます。他のすべての環境変数にはキーと値があります。Docker 1.12.1を使用しています。
Kevin Burke

@KevinBurke:現在のシェル環境から読み取っている場合は、-e PASSWORD = $ PASSWORDが必要だと思います
エラータ

8
@KevinBurke:export PASSWORD=foo代わりに実行すると、変数がdocker run環境変数として渡され、docker run -e PASSWORD機能します。
qerub 2016年

93

ここと@errataで述べられているように-edocker run ..コマンドでパラメーターを使用して渡すことができます。 ただし、このアプローチの潜在的な欠点は、資格情報が実行されるプロセスリストに表示されることです。 それをより安全にするには、設定ファイルに資格情報を作成し、実行することがで述べたように、ここで。次に、その構成ファイルへのアクセスを制御して、そのマシンにアクセスできる他のユーザーがあなたの資格情報を見ることができないようにします。

docker run--env-file


2
この問題に対処する別の方法を@errataの回答に追加しました。
ブライアン、

21
に注意してください。env値--env-fileを使用すると--env、使用しているシェルの標準的なセマンティクスで引用/エスケープされ--env-fileますが、値を使用すると、コンテナー内で取得される値が異なります。docker runコマンドはファイルを読み取り、非常に基本的な解析を行って値をコンテナーに渡します。これはシェルの動作とは異なります。一連の--envエントリをに変換する場合に注意する必要があるのは、ちょっとした落とし穴です--env-file
Shorn、2016年

5
Shornの回答について詳しく説明するために、env-fileを使用する場合、非常に長い環境変数の値をすべて1行に入力する必要がありました。改行を入れたり、分割したりする方法がないためです。次のような複数行:$ MY_VAR = stuff $ MY_VAR = $ MY_VAR more stuff
Jason White

53

コンテナーを起動する方法として「docker-compose」を使用している場合、実際には、サーバーで定義されている環境変数をDockerコンテナーに渡す便利な方法があります。

あなたにはdocker-compose.yml、ファイル、あなたは基本的なHAPI-jsからコンテナとコードルックスなどをスピンアップしているとしましょう:

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

dockerプロジェクトが置かれているローカルサーバーに、hapi-jsコンテナーに渡す「NODE_DB_CONNECT」という名前の環境変数があり、その新しい名前を「HAPI_DB_CONNECT」にしたいとします。次に、docker-compose.ymlファイルでローカル環境変数をコンテナに渡し、次のように名前を変更します。

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

これが、コンテナ内の任意のファイルでデータベース接続文字列をハードコーディングすることを回避するのに役立つことを願っています!


6
これは機能しません。これらの変数はコンテナに渡されません。
Frondor、2018年

@フロンドール本当に?これらのドキュメントによると、それはそうであるようです。
darda

1
このアプローチの問題は、docker-compose.ymlファイルの環境変数をgitリポジトリにコミットする必要があることです。これをどのように回避しますか?理想的には、gitignoredであり、Dockerfileまたはdocker-compose.ymlにインポート/ロードできる個別のenvファイルがあるはずです
Khaled Osman

35

を使用するとdocker-compose、docker-compose.ymlの環境変数を継承し、続いてによって呼び出されdocker-composeてイメージをビルドするDockerfileを継承できます。これは、Dockerfile RUNコマンドが環境に固有のコマンドを実行する必要がある場合に役立ちます。

(あなたのシェルはRAILS_ENV=developmentすでに環境に存在しています)

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

このように、ファイルまたはdocker-compose build/ upコマンドで環境変数を指定する必要はありません。

docker-compose build
docker-compose up

それらは同じ名前でなければなりませんか?ちょっと混乱しているようです。そして、代わりに開発を実行したい場合、どのように引数をオーバーライドしますか?
Cyber​​Mew 2018年

@Cyber​​Mewはい、環境、docker-compose、Dockerfile間で同じ名前にする必要があります。代わりに開発を実行する場合は、docker-composeビルドを実行する前に、ターミナルでRAILS_ENV = developmentを実行して環境変数を設定します。これにより、docker-composeがDockerfileによって環境からその値を継承します。
joshweir 2018年

30

-eまたは--env valueを使用して、環境変数を設定します(デフォルト[])。

起動スクリプトの例:

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

コマンドラインから複数の環境を使用する場合は、すべての環境変数の前に-eフラグを使用します。

例:

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

注:コンテナ名は、環境変数の前ではなく、必ず環境変数の後に置いてください。

多くの変数を設定する必要がある場合は、--env-fileフラグを使用します

例えば、

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

その他のヘルプについては、Dockerのヘルプをご覧ください。

 $ docker run --help

公式ドキュメント:https : //docs.docker.com/compose/environment-variables/


2
なぜ必要なのubuntu bashですか?ubuntuでベースイメージとして作成されたイメージに適用されますか、それともすべてのイメージに適用されますか?
Reyansh Kharga

何年も-e前に引数の後にコンテナ名を置くことについて少し読んでみたいです!彼らがなぜこれを必要としたのか理解することすらできません...
ironchicken

13

ホストマシンの環境変数をDockerコンテナーにパイプする方法には、素晴らしいハックがあります。

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

すべてのホストマシンのENV変数をenv > env_fileダンプして、実行中のコンテナでそれらにアクセスできるようにするため、この手法は慎重に使用してください。env_file



5

もう1つの方法は、次の機能を使用することです/usr/bin/env

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

2

env.shローカルに環境変数があり、コンテナの起動時にそれを設定したい場合は、

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

このコマンドは、コンテナーをbashシェルで起動し(sourcebashコマンドなのでbashシェルが必要です)、env.shファイルをソースし(環境変数を設定)、jarファイルを実行します。

env.shこのようになり、

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

printenv実際のソースコマンドが機能することをテストするためにのみ、コマンドを追加しました。sourceコマンドが正常に機能することを確認するか、Dockerログに環境変数が表示される場合は、おそらく削除する必要があります。


2
このアプローチでは、異なる/変更された環境セットを渡すたびに、Dockerイメージを再構築する必要があります。「docker --run --env-file ./somefile.txt」中にenvsを渡すことは、優れた動的なアプローチです。
Dmitry Shevkoplyas

2
@DmitryShevkoplyas私は同意します。私の使用例は--env-filedocker runコマンドに引数を指定するオプションがない場合です。たとえば、Googleアプリエンジンを使用してアプリケーションをデプロイしていて、コンテナー内で実行されているアプリにDockerコンテナー内で設定された環境変数が必要な場合、docker runコマンドを制御できないため、環境変数を設定する直接的な方法はありません。。このような場合、たとえばKMSを使用してenv変数を復号化し、それらをenv.shenv変数を設定するために取得できるに追加するスクリプトを作成できます。
akilesh raj 2018

の代わりに.、通常のPOSIX (ドット)コマンドを使用できます。(と同じ)shsourcesource.
go2null

1

jqを使用してenvをJSONに変換します。

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

これにはjqバージョン1.6以降が必要です

これは、ホストenvをjsonとして貼り付けます。Dockerfileの場合と同様です。

ENV HOST_ENV  (all env from the host as json)

そのラインはどのように機能していますかdocker run -e HOST_ENV="$env_as_json" <image>?:?私の場合、Dockerは、Docker 引数として渡されたときに変数またはサブシェル(${}または$())を解決していないようです。例:A=123 docker run --rm -it -e HE="$A" ubuntu次に、そのコンテナの内部:root@947c89c79397:/# echo $HE root@947c89c79397:/# ... HE変数はそれを作成しません。
Perplexabot

0

-eフラグと$を使用して、マシン環境変数をホストすることもできます。

実行する前に、ローカル環境変数とファイルをエクスポートする(設定する)か、使用する直前

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 

この方法を使用することにより、私の場合、指定した名前で環境変数を自動的に設定します(MG_HOST、MG_USER)

追加:

Pythonを使用している場合は、Docker内でこれらの環境変数にアクセスできます。

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>') 内に保存されているデータをgrep .envしてDockerに渡す方法です。安全に保存されているものは何もありません(そのため、単にdocker historyキーを見て取得することはできません)。

あなたの.envようにたくさんのAWSのものを持っているとしましょう:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

`` `docker run --rm -it --env-file <(bash -c 'env | grep AWS_')でdockerを実行すると、すべてが取得され、コンテナー内からアクセスできるように安全に渡されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.