วิธีการใช้ตัวแปรสภาพแวดล้อมในนักเทียบท่าเขียน


217

ฉันต้องการใช้ตัวแปร env ภายใน docker-compose.yml โดยมีค่าที่ส่งผ่านไปในเวลาที่นักเทียบท่าเขียนขึ้น นี่คือตัวอย่าง ฉันกำลังทำสิ่งนี้ในวันนี้โดยใช้คำสั่งเรียกใช้นักเทียบท่าพื้นฐานซึ่งมีสคริปต์ของตัวเอง มีวิธีการที่จะทำให้มันสำเร็จโดยการเขียน

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

2
ดูตัวเลือกอื่น ๆ ได้ที่: docs.docker.com/compose/environment-variables
Massood Khaari

2
มันได้รับการแก้ไขในการเรียบเรียงรุ่นสุดท้ายตัวอย่างของคุณจะใช้ได้เหมือนเดิม ตรวจสอบdocs.docker.com/compose/compose-file/#variable-substitutionเกี่ยวกับการทดแทนตัวแปร
natbusa

1
อย่าลืมนักเทียบท่าแอพ (ตั้งแต่มิถุนายน 2018): stackoverflow.com/a/51007138/6309
VonC

คำตอบ:


93
  1. สร้าง a template.ymlซึ่งเป็นdocker-compose.ymlตัวแปรสภาพแวดล้อมของคุณ
  2. สมมติว่าตัวแปรสภาพแวดล้อมของคุณอยู่ในไฟล์ 'env.sh'
  3. ใส่ชิ้นส่วนของรหัสด้านล่างในไฟล์ sh และเรียกใช้

แหล่ง env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

ไฟล์ใหม่docker-compose.ymlจะถูกสร้างขึ้นด้วยค่าที่ถูกต้องของตัวแปรสภาพแวดล้อม

ไฟล์ 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}

ตัวอย่างไฟล์ env.sh:

#!/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 อย่าลังเลที่จะตรวจสอบคำตอบของฉันร้องภายใต้ "วิธีการแก้ปัญหา BASH" ที่ฉันร่างวิธีการนี้อย่างละเอียดมากขึ้น
modulitos

7
ยังไม่มีวิธีแก้ปัญหาที่ดีกว่าในตอนนี้?
lvthillo

13
เหตุใดคุณจึงต้องลบไฟล์ซ้ำซ้ำ (rm -rf
docker

@ lorenzvth7 คุณสามารถตรวจสอบคำตอบของฉันด้านล่างซึ่งฉันคิดว่าละเอียดมากกว่านี้เล็กน้อย: stackoverflow.com/a/33186458/1884158
modulitos

5
-1 โซลูชันนี้ทำให้สิ่งต่าง ๆ มีความซับซ้อนเท่านั้นและควรได้รับการอัปเดตตามความสามารถใหม่ของนักเทียบท่าdocs.docker.com/compose/environment-variables/…
Efrat Levitan

240

โซลูชัน DOCKER:

ดูเหมือนว่านักเทียบท่าประกอบด้วย 1.5+ ได้เปิดใช้งานการแทนที่ตัวแปร: https://github.com/docker/compose/releases

Compose Docker ล่าสุดช่วยให้คุณเข้าถึงตัวแปรสภาพแวดล้อมจากไฟล์การเขียนของคุณ ดังนั้นคุณสามารถระบุตัวแปรสภาพแวดล้อมของคุณแล้วเรียกใช้ Compose ดังนี้:

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

จากนั้นคุณสามารถอ้างอิงตัวแปรใน docker-compose.yml โดยใช้ $ {VARIABLE} ได้เช่น:

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

และนี่คือข้อมูลเพิ่มเติมจากเอกสารนำมาที่นี่: https://docs.docker.com/compose/compose-file/#variable-substitution

เมื่อคุณรัน docker-compose ด้วยการกำหนดค่านี้ Compose จะค้นหาตัวแปรสภาพแวดล้อม POSTGRES_VERSION ในเชลล์และทดแทนค่าในระบบตัวอย่างการเขียนแก้ไขรูปภาพเพื่อ postgres: 9.3 ก่อนรันการกำหนดค่า

หากไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมให้ทำการแทนที่ด้วยสตริงว่าง ในตัวอย่างด้านบนหากไม่ได้ตั้งค่า POSTGRES_VERSION ค่าสำหรับตัวเลือกรูปภาพจะเป็น postgres:

สนับสนุนทั้งไวยากรณ์ $ VARIABLE และ $ {VARIABLE} ไม่รองรับคุณสมบัติสไตล์เชลล์เช่น $ {VARIABLE-default} และ $ {VARIABLE / foo / bar}

หากคุณต้องการใส่สัญลักษณ์ดอลลาร์ตามตัวอักษรในค่าการกำหนดค่าให้ใช้เครื่องหมายดอลลาร์สอง ($$)

และฉันเชื่อว่าคุณสมบัตินี้ได้รับการเพิ่มเข้ามาในคำขอแบบดึงนี้: https://github.com/docker/compose/pull/1765

วิธีการทุบตี:

ฉันสังเกตเห็นว่าคนมีปัญหากับการสนับสนุนตัวแปรสภาพแวดล้อมของ Docker แทนที่จะจัดการกับตัวแปรสภาพแวดล้อมใน Docker เรากลับไปสู่พื้นฐานเช่นทุบตี! นี่คือวิธีการที่ยืดหยุ่นมากขึ้นโดยใช้ bash script และ.envไฟล์

ตัวอย่างไฟล์. 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

จากนั้นรันสคริปต์ทุบตีนี้ในไดเรกทอรีเดียวกันซึ่งควรปรับใช้ทุกอย่างให้ถูกต้อง:

#!/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

เพียงแค่อ้างอิงตัวแปร env ของคุณในไฟล์การเขียนของคุณด้วยไวยากรณ์ bash ตามปกติ (เช่น${SECRET_KEY}การแทรกSECRET_KEYจาก.envไฟล์)

สังเกตว่าCOMPOSE_CONFIGมีการกำหนดไว้ใน.envไฟล์ของฉันและใช้ในสคริปต์ทุบตีของฉัน แต่คุณสามารถแทนที่{$COMPOSE_CONFIG}ด้วยmy-compose-file.ymlในสคริปต์ทุบตีได้อย่างง่ายดาย

โปรดทราบว่าฉันติดป้ายการปรับใช้นี้โดยการตั้งชื่อคอนเทนเนอร์ทั้งหมดด้วยคำนำหน้า "myproject" คุณสามารถใช้ชื่อใดก็ได้ที่คุณต้องการ แต่มันจะช่วยระบุภาชนะของคุณเพื่อให้คุณสามารถอ้างอิงได้อย่างง่ายดายในภายหลัง สมมติว่าคอนเทนเนอร์ของคุณไร้สัญชาติอย่างที่ควรจะเป็นสคริปต์นี้จะทำการลบและปรับใช้คอนเทนเนอร์ของคุณใหม่อย่างรวดเร็วตามพารามิเตอร์. env ของคุณและการเขียนไฟล์ YAML

อัปเดต เนื่องจากคำตอบนี้ค่อนข้างเป็นที่นิยมฉันเขียนโพสต์บล็อกที่อธิบายขั้นตอนการปรับใช้ Docker ในเชิงลึกยิ่งขึ้น: http://lukeswart.net/2016/03/lets-deploy-part-1/นี่อาจเป็นประโยชน์เมื่อคุณเพิ่ม ความซับซ้อนมากขึ้นในการกำหนดค่าการปรับใช้เช่น nginx configs LetsEncrypt certs และคอนเทนเนอร์ที่เชื่อมโยง


2
คุณสามารถแทนgrep foo file.text ในกรณีของฉันฉันได้ไปcat file.text | grep fooexport $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst
Jorge Lavín

"ฉันสังเกตเห็นว่าผู้คนมีปัญหากับการสนับสนุนตัวแปรสภาพแวดล้อมของ Docker" - คุณมีรายละเอียดหรือลิงค์ไปยังตั๋วหรือไม่?
tleyden

ขออภัยฉันไม่ได้บันทึกปัญหาเฉพาะที่ฉันพบและนานมาแล้ว (~ 6 เดือน) ฉันไม่รู้ว่ายังเกี่ยวข้องหรือไม่ แต่ใช่คุณสมบัติบางอย่างในการสนับสนุนตัวแปรสภาพแวดล้อมของ Docker นั้นมีความผิดพลาดและรายงานโดยผู้ใช้หลายคน ฉันเชื่อว่าตอนนี้ดีขึ้นมาก แต่เมื่อการกำหนดค่าการปรับใช้มีความซับซ้อนอย่างมากฉันต้องการทำให้เป็นโมดูลโดยใช้ bash เพื่อจัดการกับตรรกะการกำหนดค่าและ Docker Compose สำหรับการจัดวางคอนเทนเนอร์
modulitos

8
PSA: สิ่งนี้ใช้ได้กับdocker-compose upและไม่ใช่docker-compose runเท่านั้น
Kriegslustig

5
มีการแก้ปัญหานี้คือdocs.docker.com/compose/compose-file/#envfileที่ผมใช้ที่คุณเพิ่มตัวแปรสภาพแวดล้อมจากภายใต้.env env_fileจากนั้นคุณสามารถอ้างอิงตัวแปรในการdocker-compose.ymlใช้${VARIABLE}
musale

112

ดูเหมือนว่านักเทียบท่า-เขียนมีการสนับสนุนในขณะนี้สำหรับตัวแปรสภาพแวดล้อมเริ่มต้นในแฟ้ม

สิ่งที่คุณต้องทำคือการประกาศตัวแปรของคุณในไฟล์ชื่อ.envและพวกเขาจะสามารถใช้ได้ใน docker-compose.yml

ตัวอย่างเช่นสำหรับ.envไฟล์ที่มีเนื้อหา:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

คุณสามารถเข้าถึงตัวแปรของคุณภายใน docker-compose.ymlหรือส่งต่อไปยังคอนเทนเนอร์:

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

4
นี่คือทางออกที่ดีที่สุด!
Ladenkov Vladislav

4
สิ่งนี้ใช้ได้สำหรับฉันเช่นกัน ฉันไม่รู้ว่าทำไม แต่ชื่อไฟล์ควรเป็นอักษรอย่างแท้จริง.envตัวอย่างเช่นใช้งานconfig.envไม่ได้สำหรับฉัน
HBat

1
@Hat เป็น "." หมายถึงไฟล์ที่ซ่อน - นี่เป็นขั้นตอนปกติสำหรับไฟล์กำหนดค่าในท้องที่
Jeremy Hajek

2
ทางออกที่ดีที่สุด และเราสามารถเพิ่ม / etc / environment props และใช้สิ่งเหล่านั้นเป็นสภาพแวดล้อมที่มีการใช้. env มันจะปลอดภัยมากขึ้น
Chinthaka Dinadasa

24

ต่อไปนี้ใช้สำหรับนักจัดองค์ประกอบ 3.x ตั้งค่าตัวแปรสภาพแวดล้อมภายในคอนเทนเนอร์

วิธีการ - 1 วิธีการตรง

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

method - 2 ไฟล์“ .env”

สร้างไฟล์. env ในตำแหน่งเดียวกับ docker-compose.yml

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

และไฟล์เขียนของคุณจะเป็นเหมือน

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

แหล่ง


2
ฉันต้องการดูตัวอย่างที่สมบูรณ์ของวิธีที่ 1 ฉันไม่สามารถทำงานนี้ได้ดังนั้นจึงใช้ไฟล์. env (ซึ่งใช้ได้ดี)
BobHy

20

เมื่อใช้ตัวแปรสภาพแวดล้อมสำหรับโวลุ่มคุณต้อง:

  1. สร้างไฟล์. envในโฟลเดอร์เดียวกันซึ่งมีdocker-compose.yaml ไฟล์

  2. ประกาศตัวแปรใน.envไฟล์:

    HOSTNAME=your_hostname
    
  3. เปลี่ยน$hostnameไป${HOSTNAME}ที่docker-compose.yaml ไฟล์

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

แน่นอนคุณสามารถทำเช่นนั้นในแต่ละบิลด์เช่น:

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

9
หมายเหตุตามเอกสาร: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

วิธีที่ดีที่สุดคือการระบุตัวแปรสภาพแวดล้อมนอกdocker-compose.ymlไฟล์ คุณสามารถใช้ได้env_fileการตั้งค่าและกำหนดไฟล์สภาพแวดล้อมของคุณภายในบรรทัดเดียวกัน จากนั้นการสร้างนักเทียบท่าขึ้นอีกครั้งควรสร้างคอนเทนเนอร์ด้วยตัวแปรสภาพแวดล้อมใหม่

นี่คือลักษณะที่นักเทียบท่า-compose.yml ของฉันมีลักษณะ:

services:
  web:
    env_file: variables.env

หมายเหตุ: นักเทียบท่าเขียนข้อความคาดว่าแต่ละบรรทัดในไฟล์ env จะอยู่ในVAR=VALรูปแบบ หลีกเลี่ยงการใช้exportภายใน.envไฟล์ นอกจากนี้.envควรวางไฟล์ไว้ในโฟลเดอร์ที่คำสั่ง comper-compose ดำเนินการ


2
วิธีที่ดีที่สุดแน่นอน
Dany

NO มันจะไม่ทำให้ตัวแปรสภาพแวดล้อมพร้อมใช้งานโดยอัตโนมัติภายในคอนเทนเนอร์นักเทียบท่า คุณยังต้องกล่าวถึงสิ่งเหล่านี้อย่างชัดเจนในส่วนของสภาพแวดล้อม
kta

6

คุณยังไม่สามารถ ... แต่นี่เป็นทางเลือกคิดเหมือนตัวสร้าง docker-composer.yml:

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

โดยทั่วไปแล้วเชลล์สคริปต์ที่จะแทนที่ตัวแปรของคุณ นอกจากนี้คุณสามารถใช้งาน Grunt เพื่อสร้างไฟล์นักเทียบท่าของคุณในตอนท้ายของกระบวนการ CI ของคุณ


4

ฉันมีสคริปต์ทุบตีง่าย ๆ ที่ฉันสร้างขึ้นสำหรับมันมันหมายถึงการเรียกใช้มันบนไฟล์ของคุณก่อนการใช้งาน: https://github.com/antonosmond/subber

โดยทั่วไปเพียงสร้างไฟล์การเขียนของคุณโดยใช้เครื่องหมายปีกกาคู่เพื่อแสดงถึงตัวแปรสภาพแวดล้อมเช่น:

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

สิ่งใดในวงเล็บปีกกาคู่จะถูกแทนที่ด้วยตัวแปรสภาพแวดล้อมที่มีชื่อเดียวกันดังนั้นถ้าฉันมีชุดตัวแปรสภาพแวดล้อมดังต่อไปนี้:

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

ในการเรียกใช้subber docker-compose.ymlไฟล์ผลลัพธ์จะมีลักษณะดังนี้:

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

2

เท่าที่ฉันรู้นี่เป็นงานที่อยู่ระหว่างดำเนินการ พวกเขาต้องการที่จะทำ แต่มันยังไม่ออก ดู1377 ("ใหม่" 495ที่ถูกกล่าวถึงโดย @Andy)

ฉันลงเอยด้วยการใช้วิธี "generate .yml เป็นส่วนหนึ่งของ CI" ตามที่เสนอโดย @Thomas


1

เพิ่ม env ให้กับไฟล์. env

เช่น

VERSION=1.0.0

จากนั้นบันทึกลงใน 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

ใช้ไฟล์. env เพื่อกำหนดค่าแบบไดนามิกใน docker-compse.yml ไม่ว่าจะเป็นพอร์ตหรือค่าอื่น ๆ

ตัวอย่างนักเทียบท่าประกอบ:

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}

ภายในไฟล์. env คุณสามารถกำหนดค่าของตัวแปรเหล่านี้:

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

ใช้เวอร์ชั่น 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"

ฉันได้มันจากลิงค์นี้ https://github.com/docker/cli/issues/939


1

ตั้งแต่ 1.25.4, นักเทียบท่าเขียนตัวเลือกการสนับสนุน--env-fileที่ช่วยให้คุณสามารถระบุไฟล์ที่มีตัวแปร

คุณควรมีลักษณะเช่นนี้:

hostname=my-host-name

และคำสั่ง:

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