Cara menggunakan variabel lingkungan dalam komposisi buruh pelabuhan

217

Saya ingin dapat menggunakan variabel env di dalam docker-compose.yml, dengan nilai yang diteruskan pada saat docker-compose up. Ini adalah contohnya. Saya melakukan ini hari ini dengan perintah run docker dasar, yang melilit skrip saya sendiri. Apakah ada cara untuk mencapainya dengan menulis, tanpa bungkus bash seperti itu?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
sumber
2
Untuk opsi yang berbeda, lihat: docs.docker.com/compose/environment-variables
Massood Khaari
2
Itu dipecahkan dalam versi penulisan yang terakhir, contoh Anda akan bekerja seperti apa adanya. periksa docs.docker.com/compose/compose-file/#variable-substitution tentang subtitusi variabel.
natbusa
1
Jangan lupa aplikasi docker (sejak Juni 2018): stackoverflow.com/a/51007138/6309
VonC

Jawaban:

93
  1. Buat template.yml, yang merupakan docker-compose.ymlvariabel lingkungan Anda.
  2. Misalkan variabel lingkungan Anda ada di file 'env.sh'
  3. Masukkan potongan kode di bawah ini ke dalam file sh dan jalankan.

sumber env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

File baru docker-compose.ymlakan dihasilkan dengan nilai variabel lingkungan yang benar.

Contoh file 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}

Contoh file 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
Saurabh Kumar
sumber
@Meet Jangan ragu untuk memeriksa jawaban saya di bawah, di bawah "Solusi BASH", di mana saya menguraikan pendekatan ini sedikit lebih menyeluruh.
modulitos
7
masih belum ada solusi yang lebih baik saat ini?
lvthillo
13
mengapa Anda menghapus file secara rekursif? (rm -rf docker-
compose.yml
@ lorenzvth7 Anda dapat memeriksa jawaban saya di bawah ini, yang menurut saya sedikit lebih teliti: stackoverflow.com/a/33186458/1884158
modulitos
5
-1 solusi ini hanya memperumit masalah dan harus diperbarui sesuai dengan docker-menyusun kemampuan baru docs.docker.com/compose/environment-variables/…
Efrat Levitan
239

Solusi DOCKER:

Sepertinya docker-compose 1.5+ telah mengaktifkan substitusi variabel: https://github.com/docker/compose/releases

Susunan Docker terbaru memungkinkan Anda untuk mengakses variabel lingkungan dari file penulisan Anda. Jadi Anda dapat sumber variabel lingkungan Anda, lalu jalankan Tulis seperti ini:

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

Kemudian Anda dapat mereferensikan variabel dalam docker-compose.yml menggunakan $ {VARIABLE}, seperti:

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

Dan ini adalah info lebih lanjut dari dokumen, diambil di sini: https://docs.docker.com/compose/compose-file/#variable-substitution

Ketika Anda menjalankan docker-compose dengan konfigurasi ini, Compose mencari variabel lingkungan POSTGRES_VERSION di shell dan mengganti nilainya. Untuk contoh ini, Compose memutuskan gambar untuk postgres: 9.3 sebelum menjalankan konfigurasi.

Jika variabel lingkungan tidak disetel, tulis pengganti dengan string kosong. Pada contoh di atas, jika POSTGRES_VERSION tidak disetel, nilai untuk opsi gambar adalah postgres :.

Sintaks $ VARIABEL dan $ {VARIABEL} didukung. Fitur gaya-shell yang diperluas, seperti $ {VARIABLE-default} dan $ {VARIABLE / foo / bar}, tidak didukung.

Jika Anda perlu memasukkan tanda dolar literal ke dalam nilai konfigurasi, gunakan tanda dolar ganda ($$).

Dan saya yakin fitur ini ditambahkan dalam permintaan tarik ini: https://github.com/docker/compose/pull/1765

Solusi BASH:

Saya perhatikan ada masalah dengan dukungan variabel lingkungan Docker. Daripada berurusan dengan variabel lingkungan di Docker, mari kembali ke dasar-dasar, seperti bash! Berikut adalah metode yang lebih fleksibel menggunakan skrip bash dan a.env file.

Contoh file .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

kemudian jalankan skrip bash ini di direktori yang sama, yang seharusnya menyebarkan semuanya dengan benar:

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

Referensi saja variabel env Anda dalam file penulisan Anda dengan sintaks bash yang biasa (yaitu ${SECRET_KEY}untuk memasukkan SECRET_KEYdari .envfile).

Catatan COMPOSE_CONFIGdidefinisikan dalam .envfile saya dan digunakan dalam skrip bash saya, tetapi Anda dapat dengan mudah hanya mengganti {$COMPOSE_CONFIG}dengan my-compose-file.ymlskrip bash di.

Perhatikan juga bahwa saya memberi label penyebaran ini dengan memberi nama semua kontainer saya dengan awalan "myproject". Anda dapat menggunakan nama apa pun yang Anda inginkan, tetapi itu membantu mengidentifikasi wadah Anda sehingga Anda dapat dengan mudah merujuknya nanti. Dengan asumsi bahwa kontainer Anda tidak memiliki kewarganegaraan, sebagaimana mestinya, skrip ini akan dengan cepat menghapus dan mempekerjakan kembali kontainer Anda sesuai dengan param file .env Anda dan file YAML penulisan Anda.

Pembaruan Karena jawaban ini tampaknya cukup populer, saya menulis posting blog yang menjelaskan alur kerja penempatan Docker saya secara lebih mendalam: http://lukeswart.net/2016/03/lets-deploy-part-1/ Ini mungkin berguna ketika Anda menambahkan lebih rumit untuk konfigurasi penggunaan, seperti konfigurasi nginx, sertifikat LetsEncrypt, dan kontainer yang ditautkan.

modulitos
sumber
2
Anda bisa langsung grep foo file.textsaja cat file.text | grep foo. Dalam kasus saya, saya harus export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín
"Saya perhatikan orang-orang memiliki masalah dengan dukungan variabel lingkungan Docker" - apakah Anda memiliki detail atau tautan ke tiket?
tleyden
Maaf, saya tidak mencatat masalah spesifik yang saya alami, dan sudah lama sekali (~ 6 bulan), saya tidak tahu apakah itu masih relevan. Tapi ya, beberapa fitur dalam dukungan variabel lingkungan Docker bermasalah, dan dilaporkan oleh banyak pengguna. Saya percaya itu jauh lebih baik sekarang. Tetapi ketika konfigurasi penyebaran menjadi sangat kompleks, saya lebih suka memodulasi itu dengan menggunakan bash untuk menangani logika konfigurasi dan Susunan Docker untuk orkestrasi wadah.
modulitos
8
PSA: Ini hanya bekerja dengandocker-compose up dan tidak dengan docker-compose run.
Kriegslustig
5
Ada solusi ini docs.docker.com/compose/compose-file/#envfile yang saya gunakan di mana Anda menambahkan variabel lingkungan dari .envbawah env_file. Kemudian Anda dapat referensi variabel dalam docker-compose.ymlmenggunakan${VARIABLE}
musale
111

Tampaknya docker-compose memiliki dukungan asli sekarang untuk variabel lingkungan default dalam file .

yang perlu Anda lakukan adalah mendeklarasikan variabel Anda dalam file yang bernama .envdan mereka akan tersedia di docker-compose.yml.

Misalnya, untuk .envfile dengan konten:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Anda bisa mengakses variabel Anda di dalam docker-compose.ymlatau meneruskannya ke wadah:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P
sumber
4
ini solusi terbaik!
Ladenkov Vladislav
4
Ini juga bekerja untuk saya. Saya tidak tahu mengapa tetapi nama file harus benar-benar .env, misalnya config.envtidak berfungsi untuk saya.
HBat
1
@HBat the "." berarti file tersembunyi - ini adalah prosedur biasa untuk file konfigurasi lokal
Jeremy Hajek
2
Solusi terbaik. dan Kita dapat menambahkan / etc / environment props dan menggunakannya sebagai lingkungan dengan menggunakan .env. Itu akan lebih aman.
Chinthaka Dinadasa
24

Hal berikut ini berlaku untuk komposisi galangan 3.x Set variabel lingkungan di dalam wadah

metode - 1 Metode lurus

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

method - 2 File “.env”

Buat file .env di lokasi yang sama dengan docker-compose.yml

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

dan file menulis Anda akan seperti

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

sumber

Gajendra D Ambi
sumber
2
Saya ingin melihat contoh lengkap metode 1. Saya tidak bisa membuat ini berfungsi, jadi akhirnya menggunakan file .env (yang berfungsi dengan baik).
BobHy
20

Saat menggunakan variabel lingkungan untuk volume yang Anda butuhkan:

  1. buat file .env di folder yang sama yang berisi docker-compose.yaml file

  2. mendeklarasikan variabel dalam .envfile:

    HOSTNAME=your_hostname
    
  3. Ubah $hostnameke ${HOSTNAME}pada docker-compose.yaml file

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

Tentu saja Anda dapat melakukannya secara dinamis pada setiap bangunan seperti:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
sumber
9
Catatan, menurut dokumen: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

Cara terbaik adalah menentukan variabel lingkungan di luar docker-compose.ymlfile. Kamu bisa memakaienv_file pengaturan, dan menentukan file lingkungan Anda dalam baris yang sama. Kemudian melakukan penyusunan kembali buruh pelabuhan harus membuat ulang wadah dengan variabel lingkungan baru.

Begini tampilannya seperti docker-compose.yml:

services:
  web:
    env_file: variables.env

Catatan: docker-compose mengharapkan setiap baris dalam file env berada dalam VAR=VALformat. Hindari menggunakan exportdi dalam .envfile. Selain itu, .envfile tersebut harus ditempatkan di folder tempat perintah docker-compose dijalankan.

Jibu James
sumber
2
Cara terbaik memang
Dany
TIDAK. Itu tidak akan secara otomatis membuat variabel lingkungan tersedia di dalam wadah buruh pelabuhan. Anda masih perlu menyebutkan ini secara eksplisit di bagian lingkungan.
kta
6

Anda belum bisa ... Tapi ini alternatifnya, pikirkan generator generator docker-composer.yml:

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

Pada dasarnya skrip shell yang akan menggantikan variabel Anda. Anda juga dapat menggunakan tugas Grunt untuk membangun file komposisi buruh pelabuhan Anda di akhir proses CI Anda.

Thomas Decaux
sumber
4

Saya punya skrip bash sederhana yang saya buat untuk ini, artinya menjalankannya di file Anda sebelum digunakan: https://github.com/antonosmond/subber

Pada dasarnya hanya buat file penulisan Anda menggunakan kurung kurawal ganda untuk menunjukkan variabel lingkungan mis:

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

Apa pun dalam kurung kurawal ganda akan diganti dengan variabel lingkungan dengan nama yang sama jadi jika saya menetapkan variabel lingkungan berikut:

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

menjalankan subber docker-compose.ymlfile yang dihasilkan akan terlihat seperti:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"
Anton
sumber
2

Sejauh yang saya tahu, ini adalah pekerjaan dalam proses. Mereka ingin melakukannya, tetapi belum dirilis. Lihat 1377 ("baru" 495 yang disebutkan oleh @Andy).

Saya akhirnya menerapkan pendekatan "generate .yml sebagai bagian dari CI" seperti yang diusulkan oleh @Thomas.

anroot
sumber
1

tambahkan env ke file .env

Seperti

VERSION=1.0.0

lalu simpan ke 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
    
foxundermon
sumber
1

Gunakan file .env untuk menentukan nilai dinamis di docker-compse.yml. Baik itu port atau nilai lainnya.

Contoh komposisi buruh pelabuhan:

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}

Di dalam file .env Anda dapat menentukan nilai variabel-variabel ini:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002
sorabzone
sumber
1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Gunakan versi 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"

Saya mendapatkannya dari tautan ini https://github.com/docker/cli/issues/939

pengguna2851100
sumber
1

Sejak 1.25.4, komposisi buruh pelabuhan mendukung opsi --env-fileyang memungkinkan Anda menentukan file yang berisi variabel.

Milik Anda akan terlihat seperti ini:

hostname=my-host-name

Dan perintahnya:

docker-compose --env-file /path/to/my-env-file config
papillon
sumber