Bagaimana cara meneruskan variabel lingkungan ke wadah Docker?

830

Saya baru mengenal Docker, dan tidak jelas cara mengakses database eksternal dari sebuah wadah. Apakah cara terbaik untuk kode-keras dalam string koneksi?

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

Jawaban:

1247

Anda dapat mengirimkan variabel lingkungan ke wadah Anda dengan -ebendera.

Contoh dari skrip startup:

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

Atau, jika Anda tidak ingin memiliki nilai pada baris perintah di mana itu akan ditampilkan oleh ps, dll., -eDapat menarik nilai dari lingkungan saat ini jika Anda hanya memberikannya tanpa =:

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

Jika Anda memiliki banyak variabel lingkungan dan terutama jika itu dimaksudkan untuk dirahasiakan, Anda dapat menggunakan file env :

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

Bendera --env-file mengambil nama file sebagai argumen dan mengharapkan setiap baris dalam format VAR = VAL, meniru argumen yang diteruskan ke --env. Baris komentar hanya perlu diawali dengan #

errata
sumber
Adakah cara yang lebih mudah untuk melakukan ini? Sangat menjengkelkan karena harus membuat ulang wadah dengan variabel yang berbeda setiap kali. Mungkin menyimpannya dalam file?
Jason Axelson
29
Saya menyimpan buruh pelabuhan menjalankan perintah dalam skrip shell, (./start_staging.sh dll.) Kemudian jalankan secara jarak jauh menggunakan Ansible.
errata
1
Saya mengalami masalah untuk membuat versi kedua berfungsi; Saya mengatur PASSWORD = foo di lingkungan, lalu meneruskan --env PASSWORD, dan hanya kata "PASSWORD" yang muncul di config.json penampung; setiap variabel lingkungan lainnya memiliki kunci dan nilai. Saya menggunakan Docker 1.12.1.
Kevin Burke
@KevinBurke: Saya pikir Anda ingin -e PASSWORD = $ PASSWORD jika Anda membaca dari lingkungan shell saat ini
errata
8
@KevinBurke: Lakukan export PASSWORD=foosebaliknya dan variabel akan diteruskan ke docker runsebagai variabel lingkungan, membuat docker run -e PASSWORDpekerjaan.
qerub
93

Anda dapat meneruskan menggunakan -eparameter dengan docker run ..perintah seperti yang disebutkan di sini dan seperti yang disebutkan oleh @errata.
Namun, kemungkinan kelemahan dari pendekatan ini adalah kredensial Anda akan ditampilkan dalam daftar proses, tempat Anda menjalankannya.
Untuk membuatnya lebih aman, Anda dapat menulis kredensial Anda dalam file konfigurasi dan melakukannya docker rundengan yang --env-filedisebutkan di sini . Kemudian Anda dapat mengontrol akses file konfigurasi itu sehingga orang lain yang memiliki akses ke mesin itu tidak akan melihat kredensial Anda.

Sabin
sumber
2
Saya menambahkan cara lain untuk mengatasi masalah ini ke jawaban @ errata.
Bryan
21
Hati-hati --env-file, ketika Anda menggunakan --envnilai-nilai ENV Anda akan dikutip / lolos dengan semantik standar dari shell apa pun yang Anda gunakan, tetapi ketika menggunakan --env-filenilai-nilai Anda akan masuk ke dalam wadah Anda akan berbeda. Perintah run docker hanya membaca file, melakukan parsing yang sangat mendasar dan meneruskan nilai-nilai ke wadah, itu tidak setara dengan cara shell Anda berperilaku. Hanya sedikit saja yang perlu diperhatikan jika Anda mengonversi banyak --enventri menjadi --env-file.
Shorn
5
Untuk menguraikan jawaban Shorn, ketika menggunakan env-file, saya harus meletakkan nilai variabel lingkungan yang sangat panjang pada satu baris karena tampaknya tidak ada cara untuk meletakkan garis di dalamnya, atau membaginya menjadi beberapa baris seperti: $ MY_VAR = barang $ MY_VAR = $ MY_VAR lebih banyak barang
Jason White
53

Jika Anda menggunakan 'docker-compose' sebagai metode untuk memutar wadah Anda, sebenarnya ada cara yang berguna untuk meneruskan variabel lingkungan yang ditentukan pada server Anda ke wadah Docker.

Dalam docker-compose.ymlfile Anda , katakanlah Anda memutar wadah hapi-js dasar dan kode tersebut terlihat seperti:

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

Katakanlah server lokal tempat proyek buruh pelabuhan Anda memiliki variabel lingkungan bernama 'NODE_DB_CONNECT' yang ingin Anda sampaikan ke wadah hapi-js Anda, dan Anda ingin nama barunya menjadi 'HAPI_DB_CONNECT'. Kemudian dalam docker-compose.ymlfile, Anda akan meneruskan variabel lingkungan lokal ke wadah dan menamainya seperti:

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

Saya harap ini membantu Anda untuk menghindari pengkodean keras string koneksi database dalam file apa pun di wadah Anda!

Marquistador
sumber
6
Ini tidak akan berhasil. Variabel-variabel itu tidak diteruskan ke wadah.
Frondor
@Fondor benar-benar? Menurut dokumen - dokumen ini sepertinya sudah seharusnya.
darda
1
Masalah dengan pendekatan ini adalah bahwa Anda mengkomit variabel lingkungan dalam file docker-compose.yml ke repositori git yang seharusnya tidak Anda lakukan. Bagaimana Anda mengatasi ini? idealnya Anda akan memiliki file env terpisah yang gitignored dan dapat mengimpor / memuat ke Dockerfile atau docker-compose.yml
Khaled Osman
35

Dengan menggunakan docker-compose, Anda dapat mewarisi variabel env di docker-compose.yml dan selanjutnya setiap Dockerfile dipanggil oleh docker-composeuntuk membuat gambar. Ini berguna ketika Dockerfile RUNperintah harus menjalankan perintah khusus untuk lingkungan.

(shell Anda RAILS_ENV=developmentsudah ada di lingkungan)

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

Dengan cara ini saya tidak perlu menentukan variabel lingkungan dalam file atau docker-compose build/ upperintah:

docker-compose build
docker-compose up
joshweir
sumber
Apakah mereka harus memiliki nama yang sama? Sepertinya agak membingungkan .. Dan bagaimana saya akan menimpa argumen jika saya ingin menjalankan pengembangan sebagai gantinya?
CyberMew
@CyberMew Ya mereka harus nama yang sama antara lingkungan Anda, docker-compose dan Dockerfile. Jika Anda ingin menjalankan pengembangan sebagai gantinya, sebelum menjalankan build-compose build, jalankan RAILS_ENV = development di terminal Anda untuk mengatur variabel lingkungan, dengan cara itu docker-compose dan pada gilirannya Dockerfile akan mewarisi nilai itu dari lingkungan Anda.
joshweir
30

Gunakan -eatau --env value untuk mengatur variabel lingkungan (default []).

Contoh dari skrip startup:

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

Jika Anda ingin menggunakan beberapa lingkungan dari baris perintah maka sebelum setiap variabel lingkungan menggunakan -ebendera.

Contoh:

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

Catatan: Pastikan meletakkan nama wadah setelah variabel lingkungan, bukan sebelum itu.

Jika Anda perlu mengatur banyak variabel, gunakan --env-fileflag

Sebagai contoh,

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

Untuk bantuan lain, lihat bantuan Docker:

 $ docker run --help

Dokumentasi resmi: https://docs.docker.com/compose/environment-variables/

Wisnu Mishra
sumber
2
Mengapa kita membutuhkannya? ubuntu bash ? Apakah ini berlaku untuk gambar yang dibuat dengan ubuntu sebagai gambar dasar atau untuk setiap gambar?
Reyansh Kharga
Saya berharap saya akan membaca sedikit tentang meletakkan nama wadah setelah -eargumen yang lalu! Saya bahkan tidak bisa mulai mengerti mengapa mereka membuat ini perlu ...
ironchicken
13

Ada cara yang bagus untuk mem-pipe variabel lingkungan mesin host ke wadah buruh pelabuhan:

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

Gunakan teknik ini dengan sangat hati-hati, karena env > env_fileakan membuang semua variabel mesin host ENV ke env_filedan membuatnya dapat diakses dalam wadah yang sedang berjalan.

Alex T
sumber
5

Cara lain adalah dengan menggunakan kekuatan /usr/bin/env:

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

Jika Anda memiliki variabel lingkungan di env.shlokal dan ingin mengaturnya ketika wadah dimulai, Anda bisa mencoba

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

Perintah ini akan memulai wadah dengan bash shell (saya ingin bash shell karena sourcemerupakan perintah bash), sumber env.shfile (yang menetapkan variabel lingkungan) dan mengeksekusi file jar.

The env.shterlihat seperti ini,

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

Saya menambahkan printenvperintah hanya untuk menguji apakah perintah sumber yang sebenarnya berfungsi. Anda mungkin harus menghapusnya ketika Anda mengkonfirmasi perintah sumber berfungsi dengan baik atau variabel lingkungan akan muncul di log buruh pelabuhan Anda.

akilesh raj
sumber
2
dengan pendekatan ini Anda harus membangun kembali gambar buruh pelabuhan Anda setiap kali Anda ingin melewati set env yang berbeda / dimodifikasi. Melewati envs selama "docker --run --env-file ./somefile.txt" adalah pendekatan yang unggul / dinamis.
Dmitry Shevkoplyas
2
@DmitryShevkoplyas saya setuju. Kasus penggunaan saya adalah di mana tidak ada opsi untuk menentukan --env-filearg ke docker runperintah. Misalnya, jika Anda menggunakan aplikasi menggunakan mesin aplikasi Google dan aplikasi yang berjalan di dalam wadah membutuhkan variabel lingkungan yang ditetapkan di dalam wadah buruh pelabuhan, Anda tidak memiliki pendekatan langsung untuk mengatur variabel lingkungan karena Anda tidak memiliki kendali atas docker runperintah . Dalam kasus seperti itu, Anda bisa memiliki skrip yang mendekripsi variabel env menggunakan say, KMS, dan menambahkannya ke env.shyang dapat diambil dari sumber untuk mengatur variabel env.
akilesh raj
Anda dapat menggunakan perintah POSIX .(dot) yang tersedia secara teratur shalih-alih source. ( sourceSama seperti .)
go2null
1

Menggunakan jq untuk mengonversi env ke JSON:

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

ini membutuhkan versi jq 1.6 atau lebih baru

ini pust host env sebagai json, pada dasarnya seperti di Dockerfile:

ENV HOST_ENV  (all env from the host as json)
Alexander Mills
sumber
Bagaimana kalimat itu bekerja untuk Anda docker run -e HOST_ENV="$env_as_json" <image>? : ? Dalam kasus saya Docker tampaknya tidak menyelesaikan variabel atau subshell ( ${}atau $()) ketika dilewatkan sebagai docker args. Misalnya: A=123 docker run --rm -it -e HE="$A" ubuntulalu di dalam wadah itu: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HEVariabel tidak berhasil.
Perplexabot
0

kami juga dapat meng-host variabel lingkungan mesin menggunakan -e flag dan $:

Sebelum berjalan perlu mengekspor (berarti mengatur) variabel dan file env lokal atau sebelum menggunakan

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 

Dengan menggunakan metode ini, atur variabel env secara otomatis dengan nama yang Anda berikan dalam kasus saya (MG_HOST, MG_USER)

Tambahan:

Jika Anda menggunakan python, Anda dapat mengakses variabel envment ini di dalam docker dengan

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

docker run --rm -it --env-file <(bash -c 'env | grep <your env data>') Adalah cara untuk mengambil data yang disimpan di dalam .envdan meneruskannya ke Docker, tanpa ada yang disimpan secara tidak aman (jadi Anda tidak bisa hanya melihat docker historydan mengambil kunci.

Katakanlah Anda memiliki banyak barang AWS di .envseperti Anda :

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

menjalankan buruh pelabuhan dengan `` `buruh pelabuhan menjalankan --rm -it --env-file <(bash -c 'env | grep AWS_') akan mengambil semuanya dan meneruskannya dengan aman agar dapat diakses dari dalam wadah.

MadDanWithABox
sumber