Làm thế nào để tôi chuyển các biến môi trường cho các container Docker?


830

Tôi chưa quen với Docker và chưa rõ cách truy cập cơ sở dữ liệu bên ngoài từ một container. Là cách tốt nhất để mã cứng trong chuỗi kết nối?

# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string

Câu trả lời:


1244

Bạn có thể truyền các biến môi trường cho các thùng chứa của bạn bằng -ecờ.

Một ví dụ từ tập lệnh khởi động:

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

Hoặc, nếu bạn không muốn có giá trị trên dòng lệnh nơi nó sẽ được hiển thị ps, v.v., -ecó thể lấy giá trị từ môi trường hiện tại nếu bạn chỉ đưa ra mà không có =:

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

Nếu bạn có nhiều biến môi trường và đặc biệt nếu chúng có nghĩa là bí mật, bạn có thể sử dụng tệp env :

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

Cờ tệp --env lấy tên tệp làm đối số và hy vọng mỗi dòng có định dạng VAR = VAL, bắt chước đối số được truyền cho --env. Các dòng bình luận chỉ cần có tiền tố #


Có cách nào dễ dàng hơn để làm điều này? Thật khó chịu khi phải tạo lại container với các biến khác nhau mỗi lần. Có thể lưu trữ nó trong một tập tin?
Jason Axelson

29
Tôi lưu trữ các lệnh chạy docker trong các kịch bản shell, (./start_staging.sh, v.v.) sau đó thực hiện chúng từ xa bằng cách sử dụng Ansible.
errata

1
Tôi gặp khó khăn khi phiên bản thứ hai hoạt động; Tôi đặt PASSWORD = foo trong môi trường, sau đó vượt qua --env PASSWORD và chỉ từ "PASSWORD" hiển thị trong tệp config.json; mỗi biến môi trường khác có một khóa và một giá trị. Tôi đang sử dụng Docker 1.12.1.
Kevin Burke

@KevinBurke: Tôi nghĩ rằng bạn muốn -e PASSWORD = $ PASSWORD nếu bạn đang đọc từ môi trường shell hiện tại
errata

8
@KevinBurke: export PASSWORD=fooThay vào đó và biến sẽ được chuyển sang docker rundưới dạng biến môi trường, làm cho docker run -e PASSWORDcông việc.
qerub

93

Bạn có thể chuyển bằng cách sử dụng -ecác tham số với docker run ..lệnh như được đề cập ở đây và như được đề cập bởi @errata.
Tuy nhiên, nhược điểm có thể có của phương pháp này là thông tin đăng nhập của bạn sẽ được hiển thị trong danh sách quy trình, nơi bạn chạy nó.
Để làm cho nó an toàn hơn, bạn có thể viết thông tin quan trọng của bạn trong một tập tin cấu hình và làm docker runvới --env-filenhư đã đề cập ở đây . Sau đó, bạn có thể kiểm soát quyền truy cập của tệp cấu hình đó để những người khác có quyền truy cập vào máy đó sẽ không thấy thông tin đăng nhập của bạn.


2
Tôi đã thêm một cách khác để giải quyết mối quan tâm này cho câu trả lời của @ errata.
Bryan

21
Hãy cẩn thận --env-file, khi bạn sử dụng --envcác giá trị env của bạn sẽ được trích dẫn / thoát với ngữ nghĩa chuẩn của bất kỳ shell nào bạn đang sử dụng, nhưng khi sử dụng --env-filecác giá trị bạn sẽ nhận được bên trong container của bạn sẽ khác. Lệnh chạy docker chỉ đọc tệp, thực hiện phân tích cú pháp rất cơ bản và chuyển các giá trị qua vùng chứa, nó không tương đương với cách hành xử của trình bao của bạn. Chỉ cần một chú chó nhỏ để nhận biết nếu bạn đang chuyển đổi một loạt các --envmục thành một --env-file.
Shorn

5
Để giải thích cho câu trả lời của Shorn, khi sử dụng tệp env, tôi phải đặt tất cả giá trị của biến môi trường rất dài trên một dòng vì dường như không có cách nào để ngắt dòng trong đó hoặc chia nó thành nhiều dòng như: $ MY_VAR = Stuff $ MY_VAR = $ MY_VAR nhiều thứ hơn
Jason White

53

Nếu bạn đang sử dụng 'docker-compose' làm phương pháp để tăng (các) bộ chứa của mình, thì thực sự có một cách hữu ích để chuyển một biến môi trường được xác định trên máy chủ của bạn sang bộ chứa Docker.

Trong docker-compose.ymltệp của bạn , giả sử bạn đang tạo ra một thùng chứa hapi-js cơ bản và mã trông như sau:

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

Giả sử máy chủ cục bộ mà dự án docker của bạn đang bật có biến môi trường có tên 'NODE_DB_CONNECT' mà bạn muốn chuyển đến vùng chứa hapi-js của mình và bạn muốn tên mới của nó là 'HAPI_DB_CONNECT'. Sau đó, trong docker-compose.ymltệp, bạn sẽ chuyển biến môi trường cục bộ vào vùng chứa và đổi tên nó như sau:

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

Tôi hy vọng điều này sẽ giúp bạn tránh mã hóa cứng một chuỗi kết nối cơ sở dữ liệu trong bất kỳ tệp nào trong vùng chứa của bạn!


6
Điều này sẽ không làm việc. Các biến đó không được chuyển đến vùng chứa.
Frondor

@Frondor thật sao? Theo những tài liệu này có vẻ như nó nên.
darda

1
Vấn đề với cách tiếp cận này là bạn cam kết các biến môi trường trong tệp docker-compose.yml vào kho git mà bạn không nên. Làm thế nào để bạn đi xung quanh này? lý tưởng là bạn sẽ có một tệp env riêng được gitignored và có thể nhập / tải vào Dockerfile hoặc docker-compose.yml
Khaled Osman

35

Sử dụng docker-compose, bạn có thể kế thừa các biến env trong docker-compose.yml và sau đó bất kỳ (các) Dockerfile nào được gọi docker-composeđể xây dựng hình ảnh. Điều này rất hữu ích khi Dockerfile RUNlệnh sẽ thực thi các lệnh cụ thể cho môi trường.

(vỏ của bạn RAILS_ENV=developmentđã tồn tại trong môi trường)

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

Bằng cách này, tôi không cần chỉ định các biến môi trường trong tệp hoặc docker-compose build/ uplệnh:

docker-compose build
docker-compose up

Họ có phải cùng tên không? Có vẻ hơi khó hiểu .. Và làm thế nào tôi có thể ghi đè các đối số nếu tôi muốn chạy phát triển thay thế?
CyberMew

@CyberMew Có, chúng phải có cùng tên giữa môi trường của bạn, docker-compose và Dockerfile. Thay vào đó, nếu bạn muốn chạy phát triển, trước khi chạy docker-compose build, hãy chạy RAILS_ENV = Development trong thiết bị đầu cuối của bạn để đặt biến môi trường, theo cách đó Docker-compose và đến lượt Dockerfile sẽ kế thừa giá trị đó từ môi trường của bạn.
joshweir

30

Sử dụng -ehoặc --env value để đặt các biến môi trường (mặc định []).

Một ví dụ từ tập lệnh khởi động:

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

Nếu bạn muốn sử dụng nhiều môi trường từ dòng lệnh thì trước mỗi biến môi trường đều sử dụng -ecờ.

Thí dụ:

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

Lưu ý: Đảm bảo đặt tên thùng chứa sau biến môi trường, không phải trước đó.

Nếu bạn cần thiết lập nhiều biến, hãy sử dụng --env-filecờ

Ví dụ,

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

Đối với bất kỳ trợ giúp nào khác, hãy xem trợ giúp Docker:

 $ docker run --help

Tài liệu chính thức: https://docs.docker.com/compose/envir-variabled/


2
Tại sao chúng ta cần ubuntu bash? Nó có áp dụng cho hình ảnh được tạo bằng ubfox làm hình ảnh cơ sở hoặc cho mọi hình ảnh không?
Reyansh Kharga

Tôi ước tôi đã đọc một chút về việc đặt tên container sau các -eđối số từ lâu! Tôi thậm chí không thể bắt đầu hiểu lý do tại sao họ làm điều này cần thiết ...
trớ trêu

13

Có một cách hay để làm thế nào để chuyển các biến môi trường của máy chủ sang bộ chứa docker:

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

Sử dụng kỹ thuật này rất cẩn thận, vì env > env_filesẽ đổ TẤT CẢ các biến ENV của máy chủ sang env_filevà làm cho chúng có thể truy cập được trong vùng chứa đang chạy.



5

Một cách khác là sử dụng quyền hạn của /usr/bin/env:

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

2

Nếu bạn có các biến môi trường trong một env.shcục bộ và muốn thiết lập nó khi container bắt đầu, bạn có thể thử

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

Lệnh này sẽ khởi động container với shell bash (tôi muốn bash shell vì sourcelà lệnh bash), lấy env.shtệp (đặt các biến môi trường) và thực thi tệp jar.

Các env.shngoại hình như thế này,

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

Tôi đã thêm printenvlệnh chỉ để kiểm tra rằng lệnh nguồn thực sự hoạt động. Bạn có thể nên loại bỏ nó khi bạn xác nhận lệnh nguồn hoạt động tốt hoặc các biến môi trường sẽ xuất hiện trong nhật ký docker của bạn.


2
với phương pháp này, bạn sẽ phải xây dựng lại hình ảnh docker của mình mỗi lần bạn muốn vượt qua bộ env khác nhau / được sửa đổi. Vượt qua envs trong "docker --run --env-file ./somefile.txt" là cách tiếp cận ưu việt / năng động.
Dmitry Shevkoplyas 23/03/18

2
@DmitryShevkoplyas Tôi đồng ý. Trường hợp sử dụng của tôi là khi không có tùy chọn chỉ định --env-filearg cho docker runlệnh. Ví dụ: nếu bạn đang triển khai một ứng dụng bằng công cụ ứng dụng Google và ứng dụng chạy bên trong bộ chứa cần các biến môi trường được đặt bên trong bộ chứa docker, bạn không có cách tiếp cận trực tiếp để đặt các biến môi trường vì bạn không có quyền kiểm soát docker runlệnh . Trong trường hợp như vậy, bạn có thể có một tập lệnh giải mã các biến env bằng cách sử dụng say, KMS và thêm chúng vào tập lệnh env.shcó thể có nguồn gốc để đặt các biến env.
akilesh raj

bạn có thể sử dụng lệnh POSIX .(dấu chấm) có sẵn thông thường shthay vì source. ( sourcegiống như .)
go2null

1

Sử dụng jq để chuyển đổi env thành JSON:

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

cái này yêu cầu jq phiên bản 1.6 trở lên

điều này làm cho máy chủ env là json, về cơ bản là như vậy trong Dockerfile:

ENV HOST_ENV  (all env from the host as json)

Làm thế nào là dòng làm việc cho bạn?: docker run -e HOST_ENV="$env_as_json" <image>? Trong trường hợp của tôi, Docker dường như không giải quyết được các biến hoặc các chuỗi con ( ${}hoặc $()) khi được chuyển như docker args. Ví dụ: A=123 docker run --rm -it -e HE="$A" ubuntusau đó bên trong container đó: root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HEBiến không tạo ra nó.
Perplexabot

0

chúng tôi cũng có thể lưu trữ biến môi trường máy bằng cờ -e và $:

Trước khi chạy cần xuất (có nghĩa là đặt) biến và tệp env cục bộ hoặc ngay trước khi sử dụng

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 

Bằng cách sử dụng phương thức này, hãy đặt biến env tự động với tên đã cho của bạn trong trường hợp của tôi (MG_HOST, MG_USER)

Bổ sung:

Nếu bạn đang sử dụng python, bạn có thể truy cập các biến envment bên trong docker bằng cách

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>') Là một cách để grep dữ liệu được lưu trữ trong a .envvà chuyển chúng đến Docker, mà không có gì được lưu trữ không an toàn (vì vậy bạn không thể chỉ nhìn docker historyvà lấy khóa.

Giả sử bạn có rất nhiều thứ AWS .envgiống như vậy:

AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx

đang chạy docker với `` `docker run --rm -it --env-file <(bash -c 'env | grep AWS_') sẽ lấy tất cả và chuyển nó an toàn để có thể truy cập từ trong container.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.