ฉันจะส่งตัวแปรสภาพแวดล้อมไปยังคอนเทนเนอร์ Docker ได้อย่างไร


828

ฉันใหม่สำหรับนักเทียบท่าและมันไม่ชัดเจนว่าจะเข้าถึงฐานข้อมูลภายนอกจากคอนเทนเนอร์ได้อย่างไร เป็นวิธีที่ดีที่สุดในรหัสยากในสตริงการเชื่อมต่อ?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

คำตอบ:


1242

คุณสามารถส่งผ่านตัวแปรสภาพแวดล้อมไปยังคอนเทนเนอร์ด้วย-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 :

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

แฟล็ก --env-file ใช้ชื่อไฟล์เป็นอาร์กิวเมนต์และคาดว่าแต่ละบรรทัดจะอยู่ในรูปแบบ VAR = VAL จำลองอาร์กิวเมนต์ที่ส่งผ่านไปยัง --env บรรทัดความคิดเห็นต้องขึ้นต้นด้วย #


มีวิธีที่ง่ายกว่านี้หรือไม่? มันน่ารำคาญจริง ๆ ที่ต้องสร้างคอนเทนเนอร์ใหม่ด้วยตัวแปรที่แตกต่างกันทุกครั้ง อาจเก็บไว้ในไฟล์หรือไม่?
Jason Axelson

29
ฉันเก็บคำสั่งเรียกใช้นักเทียบท่าในเชลล์สคริปต์ (./start_staging.sh ฯลฯ .. ) จากนั้นเรียกใช้คำสั่ง Ansible จากระยะไกล
errata

1
ฉันมีปัญหาในการทำให้รุ่นที่สองทำงาน ฉันตั้งค่ารหัสผ่าน = foo ในสภาพแวดล้อมจากนั้นผ่าน --env รหัสผ่านและเฉพาะคำว่า "รหัสผ่าน" แสดงขึ้นใน config.json ของคอนเทนเนอร์; ตัวแปรสภาพแวดล้อมอื่น ๆ ทุกตัวมีรหัสและค่า ฉันใช้นักเทียบท่า 1.12.1
Kevin Burke

@KevinBurke: ฉันคิดว่าคุณต้องการ -e PASSWORD = $ PASSWORD หากคุณกำลังอ่านจากสภาพแวดล้อมเชลล์ปัจจุบัน
errata

8
@KevinBurke: ทำexport PASSWORD=fooแทนและตัวแปรจะถูกส่งผ่านไปdocker runเป็นตัวแปรสภาพแวดล้อมทำให้การdocker run -e PASSWORDทำงาน
qerub

93

คุณสามารถส่งผ่านการใช้-eพารามิเตอร์พร้อมdocker run ..คำสั่งตามที่กล่าวถึงที่นี่และตามที่ระบุไว้โดย @errata
อย่างไรก็ตามข้อเสียที่เป็นไปได้ของวิธีการนี้คือข้อมูลประจำตัวของคุณจะปรากฏในรายการกระบวนการที่คุณเรียกใช้
ที่จะทำให้มันปลอดภัยมากขึ้นคุณอาจเขียนประจำตัวของคุณในแฟ้มการกำหนดค่าและทำdocker runด้วย--env-fileตามที่กล่าวไว้ที่นี่ จากนั้นคุณสามารถควบคุมการเข้าถึงไฟล์ปรับแต่งนั้นเพื่อให้คนอื่นที่มีสิทธิ์เข้าถึงเครื่องนั้นจะไม่เห็นข้อมูลรับรองของคุณ


2
ฉันได้เพิ่มอีกวิธีหนึ่งในการแก้ไขปัญหานี้ในคำตอบของ @ errata
ไบรอัน

21
ระวัง--env-fileเมื่อคุณใช้--envค่า env ของคุณจะถูกยกมา / หลบหนีด้วยความหมายมาตรฐานของเชลล์สิ่งที่คุณใช้ แต่เมื่อใช้--env-fileค่าที่คุณจะได้รับภายในคอนเทนเนอร์ของคุณจะแตกต่างกัน คำสั่งเรียกใช้นักเทียบท่าเพิ่งอ่านไฟล์ทำการแยกขั้นพื้นฐานและส่งค่าผ่านไปยังคอนเทนเนอร์มันไม่เทียบเท่ากับที่เชลล์ทำงานของคุณ เพียงแค่ gotcha ขนาดเล็กที่ต้องระวังหากคุณแปลง--envรายการเป็น--env-fileกลุ่ม
Shorn

5
ในการอธิบายอย่างละเอียดในคำตอบของ Shorn เมื่อใช้ไฟล์ env ฉันต้องใส่ค่าตัวแปรสภาพแวดล้อมที่ยาวมาก ๆ ในบรรทัดเดียวเนื่องจากไม่มีวิธีใดที่จะใส่ตัวแบ่งบรรทัดหรือแบ่งเป็น หลายบรรทัดเช่น: $ MY_VAR = สิ่ง $ MY_VAR = อีก $ MY_VAR รายการเพิ่มเติม
Jason White

53

หากคุณใช้ 'นักเทียบท่าเขียน' เป็นวิธีการหมุนตู้คอนเทนเนอร์ของคุณมีวิธีที่มีประโยชน์จริง ๆ ในการส่งตัวแปรสภาพแวดล้อมที่กำหนดไว้บนเซิร์ฟเวอร์ของคุณไปยังคอนเทนเนอร์นักเทียบท่า

ในdocker-compose.ymlไฟล์ของคุณสมมติว่าคุณกำลังหมุนคอนเทนเนอร์ hapi-js พื้นฐานและโค้ดดูเหมือนว่า:

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

สมมติว่าเซิร์ฟเวอร์ภายในเครื่องที่โปรเจ็กต์ docker ของคุณเปิดอยู่มีตัวแปรสภาพแวดล้อมชื่อ 'NODE_DB_CONNECT' ที่คุณต้องการส่งต่อไปยังคอนเทนเนอร์ hapi-js ของคุณและคุณต้องการให้ชื่อใหม่เป็น '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

@Frondor จริงเหรอ? ตามเอกสารเหล่านี้ดูเหมือนว่าควร
darda

1
ปัญหาของวิธีนี้คือคุณยอมรับตัวแปรสภาพแวดล้อมในไฟล์ docker-compose.yml ไปยังที่เก็บ git ซึ่งคุณไม่ควรทำ คุณจะไปรอบนี้ได้อย่างไร นึกคิดคุณจะมีไฟล์ env แยกต่างหากที่ gitignored และสามารถนำเข้า / โหลดลงใน Dockerfile หรือ docker-compose.yml
Khaled Osman

35

การใช้docker-composeคุณสามารถสืบทอดตัวแปร env ใน docker-compose.yml และต่อมา Dockerfile ใด ๆ ที่ถูกเรียกใช้docker-composeเพื่อสร้างภาพ สิ่งนี้มีประโยชน์เมื่อDockerfile RUNคำสั่งควรดำเนินการคำสั่งเฉพาะสำหรับสภาพแวดล้อม

(เปลือกของคุณมี RAILS_ENV=developmentอยู่แล้วในสภาพแวดล้อม)

นักเทียบท่า-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

พวกเขาจะต้องมีชื่อเดียวกันหรือไม่? ดูเหมือนจะค่อนข้างสับสน .. และฉันจะแทนที่ args อย่างไรถ้าฉันต้องการเรียกใช้การพัฒนาแทน?
CyberMew

@CyberMew ใช่พวกเขาจะต้องมีชื่อเดียวกันระหว่างสภาพแวดล้อมของคุณ docker-compose และ Dockerfile หากคุณต้องการเรียกใช้การพัฒนาแทนก่อนที่จะเรียกใช้บิลด์ - คอมโพสิตบิลด์ให้รัน RAILS_ENV = การพัฒนาในเทอร์มินัลของคุณเพื่อตั้งค่าตัวแปรสภาพแวดล้อมวิธีที่นักเขียนและนักเทียบท่าจะหันมารับค่าจากสภาพแวดล้อมของคุณ
joshweir

30

ใช้-eหรือ - ค่า env เพื่อตั้งค่าตัวแปรสภาพแวดล้อม (ค่าเริ่มต้น [])

ตัวอย่างจากสคริปต์เริ่มต้น:

 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? มันใช้กับภาพที่สร้างด้วยอูบุนตูเป็นภาพฐานหรือทุกภาพหรือไม่?
Reyansh Kharga

ฉันหวังว่าฉันจะอ่านนิดหน่อยเกี่ยวกับการใส่ชื่อคอนเทนเนอร์หลังจากการ-eโต้แย้งอายุที่ผ่านมา! ฉันไม่สามารถแม้แต่จะเข้าใจว่าทำไมพวกเขาถึงทำสิ่งนี้จำเป็น ...
ironchicken

13

มีแฮ็คที่ดีวิธีการวางท่อตัวแปรสภาพแวดล้อมของเครื่องโฮสต์ไปยังคอนเทนเนอร์นักเทียบท่า:

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

ใช้เทคนิคนี้อย่างระมัดระวังเพราะenv > env_fileจะถ่ายโอนทั้งหมดตัวแปรเครื่องโฮสต์ ENV ไปenv_fileและทำให้พวกเขาสามารถเข้าถึงได้ในภาชนะที่ทำงาน


5

สำหรับ Amazon AWS ECS / ECR คุณควรจัดการตัวแปรสภาพแวดล้อมของคุณ ( โดยเฉพาะความลับ ) ผ่าน S3 bucket ส่วนตัว ดูโพสต์บล็อกวิธีการจัดการความลับสำหรับการประยุกต์ใช้ Amazon EC2 คอนเทนเนอร์บริการโดยใช้ Amazon S3 และหาง


หรือที่เก็บพารามิเตอร์ SSM
joshweir

5

อีกวิธีหนึ่งคือการใช้พลังของ/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 shell (ฉันต้องการ bash shell เนื่องจากsourceเป็นคำสั่ง bash), แหล่งที่มาของenv.shไฟล์ (ซึ่งตั้งค่าตัวแปรสภาพแวดล้อม) และเรียกใช้ไฟล์ jar

env.shลักษณะเช่นนี้

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

ฉันเพิ่มprintenvคำสั่งเท่านั้นเพื่อทดสอบว่าคำสั่งแหล่งที่มาจริงทำงาน คุณควรลบออกเมื่อคุณยืนยันว่าคำสั่ง source ทำงานได้ดีหรือตัวแปรสภาพแวดล้อมจะปรากฏในบันทึกนักเทียบท่าของคุณ


2
ด้วยวิธีการนี้คุณจะต้องสร้างภาพนักเทียบท่าใหม่ทุกครั้งที่คุณต้องการผ่านชุด env ที่แตกต่าง / แก้ไข การส่ง envs ระหว่าง "นักเทียบท่า - รัน --env-file ./somefile.txt" เป็นวิธีการที่เหนือกว่า / ไดนามิก
Dmitry Shevkoplyas

2
@DmitryShevkoplyas ฉันเห็นด้วย กรณีใช้ของฉันคือที่ไม่มีตัวเลือกในการระบุ--env-fileหาเรื่องกับdocker runคำสั่ง ตัวอย่างเช่นหากคุณกำลังปรับใช้แอปพลิเคชันโดยใช้ Google App Engine และแอปที่ทำงานอยู่ภายในคอนเทนเนอร์นั้นต้องการตัวแปรสภาพแวดล้อมที่ตั้งไว้ภายใน Docker Container คุณไม่มีวิธีการโดยตรงในการตั้งค่าตัวแปรสภาพแวดล้อมเนื่องจากคุณไม่สามารถควบคุมdocker runคำสั่งได้ . ในกรณีเช่นนี้คุณสามารถมีสคริปต์ที่ถอดรหัสตัวแปร env โดยใช้คำพูด KMS และเพิ่มลงในสิ่งenv.shที่สามารถจัดหามาเพื่อตั้งค่าตัวแปร env
akilesh raj

คุณสามารถใช้ POSIX .(dot) คำสั่งที่มีอยู่ในปกติแทนsh source( sourceเหมือนกับ.)
go2null

1

การใช้ jq เพื่อแปลง env เป็น JSON:

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

ต้องใช้ jq เวอร์ชั่น1.6ขึ้นไป

ทำให้ pust นี้โฮสต์ env เป็น json, เป็นหลักเช่นนั้นใน Dockerfile:

ENV HOST_ENV  (all env from the host as json)

สายนั้นทำงานให้คุณได้อย่างไร: docker run -e HOST_ENV="$env_as_json" <image>? ในกรณีของฉันนักเทียบท่าดูเหมือนจะไม่สามารถแก้ไขตัวแปรหรือ subshells ( ${}หรือ$()) เมื่อส่งผ่านเป็นนักเทียบท่า args ตัวอย่างเช่น: A=123 docker run --rm -it -e HE="$A" ubuntuจากนั้นภายในคอนเทนเนอร์นั้น: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HEตัวแปรไม่สามารถทำได้
Perplexabot

0

เรายังสามารถโฮสต์ตัวแปรสภาพแวดล้อมของเครื่องโดยใช้แฟล็ก -e และ $:

ก่อนเรียกใช้จำเป็นต้องส่งออก (หมายถึงตั้งค่า) ตัวแปร env และไฟล์ภายในเครื่องหรือก่อนใช้งาน

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 

โดยใช้วิธีนี้ตั้งค่าตัวแปร env โดยอัตโนมัติด้วยชื่อของคุณในกรณีของฉัน (MG_HOST, MG_USER)

เพิ่มเติม:

หากคุณใช้ python คุณสามารถเข้าถึงตัวแปร envment ภายใน 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 ข้อมูลที่เก็บไว้ภายใน a .envและส่งต่อไปยัง Docker โดยไม่มีการจัดเก็บข้อมูลใด ๆ ที่ไม่ปลอดภัย (ดังนั้นคุณจึงไม่สามารถดูdocker historyและหยิบกุญแจได้

สมมติว่าคุณมีสิ่งต่างๆมากมายที่คุณ.envชอบAWS :

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

การทำงานนักเทียบท่าที่มี `` `run docker --rm -it --env-file <(bash -c 'env | grep AWS_') จะคว้ามันทั้งหมดและผ่านมันอย่างปลอดภัยเพื่อให้สามารถเข้าถึงได้จากภายในภาชนะ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.