Làm thế nào để sử dụng các biến môi trường trong soạn thảo docker


217

Tôi muốn có thể sử dụng các biến env bên trong docker-compose.yml, với các giá trị được truyền vào tại thời điểm docker-compose lên. Đây là ví dụ. Tôi đang làm điều này ngày hôm nay với lệnh chạy docker cơ bản, được bao bọc xung quanh kịch bản của riêng tôi. Có cách nào để đạt được nó với compose, mà không có bất kỳ hàm bash nào như vậy không?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data

2
Để biết các tùy chọn khác nhau, hãy xem: docs.docker.com/compose/envir-variable
Massood Khaari

2
Nó đã được giải quyết trong phiên bản sáng tác cuối cùng, ví dụ của bạn sẽ hoạt động như bình thường. kiểm tra docs.docker.com/compose/compose-file/#variable-substlation về thay thế biến.
natbusa

1
Đừng quên docker-app (kể từ tháng 6 năm 2018): stackoverflow.com/a/51007138/6309
VonC

Câu trả lời:


93
  1. Tạo một template.yml, đó là của bạn docker-compose.ymlvới biến môi trường.
  2. Giả sử các biến môi trường của bạn nằm trong một tệp 'env.sh'
  3. Đặt đoạn mã dưới đây vào một tệp sh và chạy nó.

nguồn env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

Một tệp mới docker-compose.ymlsẽ được tạo với các giá trị chính xác của các biến môi trường.

Mẫu template.yml:

oracledb:
        image: ${ORACLE_DB_IMAGE}
        privileged: true
        cpuset: "0"
        ports:
                - "${ORACLE_DB_PORT}:${ORACLE_DB_PORT}"
        command: /bin/sh -c "chmod 777 /tmp/start; /tmp/start"
        container_name: ${ORACLE_DB_CONTAINER_NAME}

Tệp env.sh mẫu:

#!/bin/bash 
export ORACLE_DB_IMAGE=<image-name> 
export ORACLE_DB_PORT=<port to be exposed> 
export ORACLE_DB_CONTAINER_NAME=ORACLE_DB_SERVER

@Meet Hãy xem phần trả lời của tôi dưới phần "Giải pháp BASH", trong đó tôi phác thảo phương pháp này kỹ hơn một chút.
modulitos

7
Vẫn không có giải pháp tốt hơn vào lúc này?
lvthillo

13
Tại sao bạn lại xóa một cách đệ quy một tập tin? (rm -rf
docker

@ lorenzvth7 Bạn có thể kiểm tra câu trả lời của tôi dưới đây, mà tôi nghĩ là kỹ lưỡng hơn một chút: stackoverflow.com/a/33186458/1884158
modulitos

5
-1 giải pháp này chỉ làm phức tạp mọi thứ và nên được cập nhật theo docker
Efrat Levitan

239

Giải pháp DOCKER:

Có vẻ như docker-compose 1.5+ đã cho phép thay thế các biến: https://github.com/docker/compose/release

Docker Compose mới nhất cho phép bạn truy cập các biến môi trường từ tệp soạn thảo của bạn. Vì vậy, bạn có thể nguồn các biến môi trường của mình, sau đó chạy Compose như vậy:

set -a
source .my-env
docker-compose up -d

Sau đó, bạn có thể tham chiếu các biến trong docker-compose.yml bằng cách sử dụng $ {VARIABLE}, như vậy:

db:
  image: "postgres:${POSTGRES_VERSION}"

Và đây là thông tin thêm từ các tài liệu, được lấy tại đây: https://docs.docker.com/compose/compose-file/#variable-substlation

Khi bạn chạy docker-compose với cấu hình này, Compose tìm biến môi trường POSTGRES_VERSION trong shell và thay thế giá trị của nó trong. Ví dụ này, Compose phân giải hình ảnh thành postgres: 9.3 trước khi chạy cấu hình.

Nếu một biến môi trường không được đặt, Soạn các thay thế bằng một chuỗi rỗng. Trong ví dụ trên, nếu POSTGRES_VERSION không được đặt, giá trị cho tùy chọn hình ảnh là postgres :.

Cả cú pháp $ VARIABLE và $ {VARIABLE} đều được hỗ trợ. Các tính năng kiểu vỏ mở rộng, như $ {VARIABLE-default} và $ {VARIABLE / foo / bar}, không được hỗ trợ.

Nếu bạn cần đặt ký hiệu đô la bằng chữ trong giá trị cấu hình, hãy sử dụng ký hiệu đô la kép ($$).

Và tôi tin rằng tính năng này đã được thêm vào trong yêu cầu kéo này: https://github.com/docker/compose/pull/1765

Giải pháp BASH:

Tôi nhận thấy mọi người có vấn đề với hỗ trợ biến môi trường của Docker. Thay vì xử lý các biến môi trường trong Docker, hãy quay lại những điều cơ bản, như bash! Đây là một phương pháp linh hoạt hơn bằng cách sử dụng tập lệnh bash và .envtập tin.

Một ví dụ tập tin .env:

EXAMPLE_URL=http://example.com
# Note that the variable below is commented out and will not be used:
# EXAMPLE_URL=http://example2.com 
SECRET_KEY=ABDFWEDFSADFWWEFSFSDFM

# You can even define the compose file in an env variable like so:
COMPOSE_CONFIG=my-compose-file.yml
# You can define other compose files, and just comment them out
# when not needed:
# COMPOSE_CONFIG=another-compose-file.yml

sau đó chạy tập lệnh bash này trong cùng thư mục, cần triển khai mọi thứ đúng cách:

#!/bin/bash

docker rm -f `docker ps -aq -f name=myproject_*`
set -a
source .env
cat ${COMPOSE_CONFIG} | envsubst | docker-compose -f - -p "myproject" up -d

Chỉ cần tham chiếu các biến env của bạn trong tệp soạn thảo của bạn với cú pháp bash thông thường (nghĩa là ${SECRET_KEY}chèn tệp SECRET_KEYtừ .envtệp).

Lưu ý COMPOSE_CONFIGđược xác định trong .envtệp của tôi và được sử dụng trong tập lệnh bash của tôi, nhưng bạn có thể dễ dàng chỉ cần thay thế {$COMPOSE_CONFIG}bằng my-compose-file.ymltập lệnh bash.

Cũng lưu ý rằng tôi đã gắn nhãn triển khai này bằng cách đặt tên cho tất cả các vùng chứa của tôi với tiền tố "myproject". Bạn có thể sử dụng bất kỳ tên nào bạn muốn, nhưng nó giúp xác định các thùng chứa của bạn để bạn có thể dễ dàng tham khảo chúng sau này. Giả sử rằng các thùng chứa của bạn không trạng thái, như vậy, tập lệnh này sẽ nhanh chóng loại bỏ và triển khai lại các thùng chứa của bạn theo thông số tệp .env và tệp YAML soạn thảo của bạn.

Cập nhật Vì câu trả lời này có vẻ khá phổ biến, tôi đã viết một bài đăng blog mô tả quy trình triển khai Docker của tôi sâu hơn: http://lukeswart.net/2016/03/lets-deploy-part-1/ Điều này có thể hữu ích khi bạn thêm phức tạp hơn đối với cấu hình triển khai, như cấu hình nginx, cerets LetsEncrypt và các thùng chứa được liên kết.


2
Bạn có thể chỉ đơn giản là grep foo file.textthay vì cat file.text | grep foo. Trong trường hợp của tôi, tôi đã phải export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín

"Tôi nhận thấy mọi người có vấn đề với hỗ trợ biến môi trường của Docker" - bạn có bất kỳ chi tiết hoặc liên kết đến một vé không?
tleyden

Xin lỗi, tôi đã không ghi lại vấn đề cụ thể mà tôi gặp phải và nó đã xảy ra cách đây rất lâu (~ 6 tháng), tôi không biết liệu nó có còn liên quan hay không. Nhưng vâng, một số tính năng trong hỗ trợ biến môi trường Docker đã bị lỗi và nó đã được báo cáo bởi nhiều người dùng. Tôi tin rằng nó tốt hơn nhiều bây giờ. Nhưng khi cấu hình triển khai trở nên phức tạp đáng kể, tôi muốn mô đun hóa nó bằng cách sử dụng bash để xử lý logic cấu hình và Docker Compose cho việc sắp xếp bộ chứa.
modulitos

8
PSA: Điều này chỉ hoạt động vớidocker-compose up và không với docker-compose run.
Kriegslustig

5
Có giải pháp này docs.docker.com/compose/compose-file/#envfile mà tôi sử dụng khi bạn thêm các biến môi trường từ .envbên dưới env_file. Sau đó, bạn có thể tham chiếu các biến trong docker-compose.ymlviệc sử dụng${VARIABLE}
musale

111

Dường như docker-compose hiện có hỗ trợ riêng cho các biến môi trường mặc định trong tệp .

tất cả những gì bạn cần làm là khai báo các biến của bạn trong một tệp có tên .envvà chúng sẽ có sẵn trong docker-compose.yml.

Ví dụ: đối với .envtệp có nội dung:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Bạn có thể truy cập biến của mình bên trong docker-compose.ymlhoặc chuyển tiếp chúng vào vùng chứa:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}

4
đây là giải pháp tốt nhất
Ladenkov Vladislav

4
Cái này cũng có tác dụng với tôi. Tôi không biết tại sao nhưng tên tệp nên theo nghĩa đen .env, ví dụ config.envnhư không làm việc cho tôi.
HBat

1
@ Xin chào "." có nghĩa là một tệp ẩn - đây là quy trình thông thường cho các tệp cấu hình cục bộ
Jeremy Hajek

2
Giải pháp tốt nhất. và Chúng tôi có thể thêm / etc / môi trường đạo cụ và sử dụng chúng làm môi trường với việc sử dụng .env. Điều đó sẽ an toàn hơn.
Chinthaka Dinadasa

24

Những điều sau đây có thể áp dụng cho docker-compose 3.x Đặt các biến môi trường bên trong vùng chứa

phương pháp - 1 phương pháp thẳng

web:
  environment:
    - DEBUG=1
      POSTGRES_PASSWORD: 'postgres'
      POSTGRES_USER: 'postgres'

phương thức - 2 Tập tin .env

Tạo tệp .env ở cùng vị trí với docker-compose.yml

$ cat .env
TAG=v1.5
POSTGRES_PASSWORD: 'postgres'

và tập tin soạn thảo của bạn sẽ như thế nào

$ cat docker-compose.yml
version: '3'
services:
  web:
    image: "webapp:${TAG}"
    postgres_password: "${POSTGRES_PASSWORD}"

nguồn


2
Tôi muốn xem một ví dụ hoàn chỉnh về phương pháp 1. Tôi không thể thực hiện công việc này, vì vậy cuối cùng đã sử dụng tệp .env (hoạt động tốt).
BobHy

20

Khi sử dụng biến môi trường cho khối lượng bạn cần:

  1. tạo tập tin .env trong cùng thư mục chứa docker-compose.yaml tập tin

  2. khai báo biến trong .envtệp:

    HOSTNAME=your_hostname
    
  3. Thay đổi $hostname để ${HOSTNAME}tại docker-compose.yaml tập tin

    proxy:
      hostname: ${HOSTNAME}
      volumes:
        - /mnt/data/logs/${HOSTNAME}:/logs
        - /mnt/data/${HOSTNAME}:/data
    

Tất nhiên bạn có thể làm điều đó một cách linh hoạt trên mỗi bản dựng như:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up

9
Lưu ý, theo các tài liệu:The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.
James Gentes

19

Cách tốt nhất là chỉ định các biến môi trường bên ngoài docker-compose.ymltệp. Bạn có thể dùngenv_file cài đặt và xác định tệp môi trường của mình trong cùng một dòng. Sau đó, thực hiện một docker-compose lên một lần nữa sẽ tạo lại các container với các biến môi trường mới.

Đây là cách docker-compose.yml của tôi trông như thế nào:

services:
  web:
    env_file: variables.env

Lưu ý: docker-compose hy vọng mỗi dòng trong tệp env có VAR=VALđịnh dạng. Tránh sử dụng exportbên trong .envtập tin. Ngoài ra, .envtập tin nên được đặt trong thư mục nơi lệnh docker-compose được thực thi.


2
Cách tốt nhất thực sự
Dany

KHÔNG. Nó sẽ không tự động làm cho các biến môi trường có sẵn bên trong container docker. Bạn vẫn cần đề cập rõ ràng những điều này trong phần môi trường.
kta

6

Bạn không thể ... được. Nhưng đây là một giải pháp thay thế, hãy suy nghĩ như một trình tạo docker-composer.yml:

https://gist.github.com/Vad1mo/9ab63f28239515d4dafd

Về cơ bản một kịch bản shell sẽ thay thế các biến của bạn. Ngoài ra, bạn có thể sử dụng tác vụ Grunt để xây dựng tệp soạn thảo docker của bạn ở cuối quy trình CI của bạn.


4

Tôi có một tập lệnh bash đơn giản mà tôi đã tạo cho nó, nó chỉ có nghĩa là chạy nó trên tệp của bạn trước khi sử dụng: https://github.com/antonosmond/subber

Về cơ bản chỉ cần tạo tệp soạn thảo của bạn bằng cách sử dụng dấu ngoặc kép để biểu thị các biến môi trường, ví dụ:

app:
    build: "{{APP_PATH}}"
ports:
    - "{{APP_PORT_MAP}}"

Bất cứ điều gì trong dấu ngoặc kép sẽ được thay thế bằng biến môi trường cùng tên, vì vậy nếu tôi có các biến môi trường sau được đặt:

APP_PATH=~/my_app/build
APP_PORT_MAP=5000:5000

đang chạy subber docker-compose.yml tệp kết quả sẽ như sau:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"

2

Theo tôi biết, đây là một công việc đang tiến triển. Họ muốn làm điều đó, nhưng nó chưa được phát hành. Xem 1377 ("mới" 495 được đề cập bởi @Andy).

Tôi đã kết thúc việc thực hiện phương pháp "tạo .yml như một phần của CI" theo đề xuất của @Thomas.


1

thêm env vào tập tin .env

Nhu la

VERSION=1.0.0

sau đó lưu nó vào deploy.sh

INPUTFILE=docker-compose.yml
RESULT_NAME=docker-compose.product.yml
NAME=test

prepare() {
        local inFile=$(pwd)/$INPUTFILE
        local outFile=$(pwd)/$RESULT_NAME
        cp $inFile $outFile
        while read -r line; do
            OLD_IFS="$IFS"
            IFS="="
            pair=($line)
            IFS="$OLD_IFS"
               sed -i -e "s/\${${pair[0]}}/${pair[1]}/g" $outFile
            done <.env
     }
       
deploy() {
        docker stack deploy -c $outFile $NAME
}

        
prepare
deploy
    

1

Sử dụng tệp .env để xác định các giá trị động trong docker-compse.yml. Có thể là cổng hoặc bất kỳ giá trị nào khác.

Mẫu docker-compose:

testcore.web:
       image: xxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/testcore:latest
       volumes: 
            - c:/logs:c:/logs
       ports:
            - ${TEST_CORE_PORT}:80
       environment:
            - CONSUL_URL=http://${CONSUL_IP}:8500 
            - HOST=${HOST_ADDRESS}:${TEST_CORE_PORT}

Bên trong tệp .env bạn có thể xác định giá trị của các biến này:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002

1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Sử dụng phiên bản 3.6:

version: "3.6"
services:
  one:
    image: "nginx:alpine"
    environment:
      foo: "bar"
      SOME_VAR:
      baz: "${OTHER_VAR}"
    labels:
      some-label: "$SOME_VAR"
  two:
    image: "nginx:alpine"
    environment:
      hello: "world"
      world: "${SOME_VAR}"
    labels:
      some-label: "$OTHER_VAR"

Tôi đã nhận được nó từ liên kết này https://github.com/docker/cli/issues/939


1

Kể từ 1.25.4, docker-compose hỗ trợ tùy chọn --env-filecho phép bạn chỉ định tệp chứa biến.

Bạn nên trông như thế này:

hostname=my-host-name

Và lệnh:

docker-compose --env-file /path/to/my-env-file config
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.