SSD Nodes Learn RAM 8GB — $66/tahun
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-01

Docker Compose: Beza .env, env_file dan environment

Fahami beza .env, env_file dan environment dalam Docker Compose, termasuk keutamaan apabila nilai bertindih serta sebab kata laluan patut disimpan sebagai secrets.

Tiga perkara yang dipanggil sebagai fail env

Docker Compose mempunyai tiga mekanisme berasingan dengan nama yang hampir sama dan boleh mengelirukan. Fail .env mengisi ruang letak ${VARIABLE} dalam compose.yaml itu sendiri, sebelum Compose menghuraikan fail tersebut. Atribut env_file: memuatkan fail pasangan kunci/nilai ke dalam persekitaran kontena. Atribut environment: menetapkan pemboleh ubah secara terus pada kontena, seperti yang ditulis dalam fail compose. Mekanisme ini tidak boleh saling menggantikan. Jika dua daripadanya menetapkan kunci yang sama, nilai yang digunakan ditentukan oleh susunan keutamaan yang didokumenkan.

Panduan ini menunjukkan cara setiap mekanisme berfungsi, membuktikan keutamaan tersebut menggunakan perintah yang boleh anda jalankan, kemudian menerangkan perkara yang lebih penting: pemboleh ubah persekitaran boleh dibaca oleh sesiapa yang boleh menjalankan docker inspect. Oleh itu, kata laluan tidak sepatutnya disimpan di dalamnya. Jika anda masih baharu dengan fail compose secara umum, mulakan dengan asas Docker Compose pada VPS dan kembali ke sini untuk konfigurasi.

Fail .env adalah untuk fail compose, bukan kontena

Cipta satu direktori dan letakkan dua fail di dalamnya.

mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .env
services:
  demo:
    image: alpine:${ALPINE_TAG}
    command: printenv ALPINE_TAG

Sekarang minta Compose menunjukkan perkara yang dihuraikannya.

docker compose config

Output menunjukkan image: alpine:3.20. Pemegang tempat itu sudah tiada kerana interpolasi berlaku semasa penghuraian. Compose mencari .env dalam direktori projek, iaitu direktori yang mengandungi fail compose, lalu menggantikan setiap ${NAME} yang ditemuinya.

Kemudian jalankan perkhidmatan itu.

docker compose run --rm demo

printenv ALPINE_TAG keluar dengan status 1 dan tidak mencetak apa-apa. Pemboleh ubah itu tidak wujud di dalam kontena. Inilah salah faham yang paling lazim: .env mengkonfigurasi fail compose, bukan proses tersebut. Fail .env yang mengandungi POSTGRES_PASSWORD=hunter2 langsung tidak memberi kesan kepada pangkalan data anda melainkan ada bahagian dalam fail compose yang merujuknya.

${NAME:-default} menyediakan nilai sandaran apabila pemboleh ubah tidak ditetapkan atau kosong. ${NAME:?message} menyebabkan Compose enggan dimulakan dan mencetak mesej anda. Ini pilihan yang tepat untuk nilai yang tidak mempunyai nilai lalai yang selamat.

env_file memuat pemboleh ubah ke dalam container

Atribut env_file: menentukan satu atau lebih fail yang kandungannya menjadi pemboleh ubah persekitaran container.

printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.env
services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
docker compose run --rm demo

Perintah ini mencetak from_env_file. Format fail ialah baris KEY=value biasa, satu setiap baris, dengan # pada permulaan baris menandakan ulasan. Format ini bukan shell. Dalam kebanyakan kes, tanda petik dikekalkan sebagai sebahagian daripada nilai, dan awalan export tidak diperlukan. Jangan letakkan ruang di sekeliling tanda =, kerana KEY = value menghasilkan pemboleh ubah yang dinamakan KEY secara literal, dengan ruang pada awal nilainya.

Laluan env_file yang tiada merupakan ralat dan Compose akan berhenti. Tandakan fail itu sebagai pilihan jika fail tersebut sememangnya boleh tiada:

    env_file:
      - path: ./app.env
        required: false

environment menetapkan pemboleh ubah sebaris

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    environment:
      GREETING: from_environment

Dua sintaks diterima: bentuk pemetaan di atas dan bentuk senarai yang menggunakan - GREETING=from_environment. Kedua-duanya berkelakuan sama. Bentuk senarai mempunyai satu helah tambahan: kunci tanpa nilai akan meneruskan pemboleh ubah daripada shell tempat anda menjalankan docker compose.

    environment:
      - GREETING
GREETING=from_my_shell docker compose run --rm demo

Perintah itu mencetak from_my_shell. Jalankan perintah tersebut tanpa menetapkan GREETING dalam shell, dan Compose tidak menetapkan apa-apa serta tidak memaparkan amaran. Kegagalan penerusan secara senyap perlu diketahui kerana perkhidmatan yang bermula dengan pemboleh ubah kata laluan kosong biasanya berjaya dimulakan dan dibiarkan terbuka sepenuhnya.

Yang manakah mempunyai keutamaan

Docker mendokumenkan susunan keutamaan, daripada yang tertinggi: docker compose run -e pada baris arahan, kemudian environment atau env_file yang nilainya diinterpolasi daripada shell anda atau daripada fail env, kemudian environment biasa dalam fail compose, kemudian env_file, dan akhirnya arahan ENV yang dibenamkan dalam imej.

Ringkasan untuk kerja harian: environment: mengatasi env_file:, manakala -e pada baris arahan mengatasi kedua-duanya. Buktikan dalam satu fail.

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
    environment:
      GREETING: from_environment
docker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETING

Perintah pertama memaparkan from_environment, jadi environment: mengatasi nilai dalam app.env. Perintah kedua memaparkan from_cli. Tiada apa-apa dalam fail compose mengatasi baris arahan.

Apabila bekas berkelakuan seolah-olah konfigurasi anda tidak pernah digunakan, jangan membuat andaian. docker compose config memaparkan fail yang telah diselesaikan sepenuhnya, manakala docker compose config --environment memaparkan pemboleh ubah interpolasi yang digunakan oleh Compose. Kebanyakan laporan "fail env saya diabaikan" sebenarnya berpunca daripada nilai yang ditetapkan dua kali pada dua tahap yang berbeza.

Mengapa pemboleh ubah persekitaran bocor

Tetapkan kata laluan dalam environment: dan kata laluan itu disimpan dalam konfigurasi kontena pada cakera, serta boleh dilihat oleh mana-mana pengguna dalam kumpulan docker.

docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'

Output tersebut mengandungi "DB_PASSWORD=hunter2" dalam teks biasa. Tiga laluan lain turut mendedahkan nilai yang sama. docker compose config mencetaknya ke terminal, lalu nilai itu boleh ditampal ke dalam forum sokongan. Mana-mana proses di dalam kontena boleh membaca /proc/1/environ, dan setiap proses anak mewarisi pemboleh ubah tersebut. Pengendali ranap aplikasi juga lazimnya membuang keseluruhan persekitaran ke dalam log atau laporan ralat.

Keahlian dalam kumpulan docker pada asasnya memberikan keistimewaan root pada hos. Oleh itu, kumpulan ini bukan sempadan keistimewaan yang boleh dijadikan sandaran. Panduan tentang akaun pengguna dengan keistimewaan minimum pada VPS menerangkan sebab kumpulan ini wajar dihadkan pada mana-mana pelayan yang dikongsi.

Compose secrets menyimpan nilai dalam fail

Compose menyokong secrets berasaskan fail. Nilai tersebut dipasang ke dalam container sebagai fail dan bukannya dimasukkan ke dalam persekitaran.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
secrets:
  db_password:
    file: ./db_password.txt

Secret dipasang pada /run/secrets/db_password di dalam container. Nama selepas garis miring ialah nama secret daripada blok peringkat teratas secrets:.

Sufiks _FILE ialah konvensyen yang digunakan oleh Docker Official Images, termasuk postgres, mysql dan mariadb. Skrip entrypoint tersebut menyemak VARNAME_FILE, membaca fail itu dan menggunakan kandungannya. Ini bukan ciri Docker, jadi ia hanya berfungsi apabila image melaksanakannya. Semak dokumentasi image sebelum menganggap bahawa SOMETHING_FILE akan digunakan. Aplikasi yang tidak menyokongnya biasanya boleh membaca fail tersebut sendiri semasa permulaan, atau anda boleh menghantar laluan itu dan membiarkan entrypoint anda sendiri mengendalikannya.

Sahkan dari dalam container yang sedang berjalan:

docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORD

Perintah pertama mencetak kata laluan. Perintah kedua tidak mencetak apa-apa kerana nilai tersebut tidak pernah dimasukkan ke dalam persekitaran. Itulah tujuannya: docker inspect pada container ini hanya menunjukkan laluan yang tidak sensitif.

Lindungi fail sumber pada hos kerana secret hanya selamat setakat fail yang menyimpannya:

chmod 600 db_password.txt

Pendekatan pertengahan yang praktikal pada VPS

Banyak imej yang dihoskan sendiri tidak menyokong pemboleh ubah _FILE, jadi pemboleh ubah persekitaran ialah satu-satunya cara untuk memasukkannya. Pada VPS dengan seorang pentadbir, matlamat yang realistik ialah mengelakkan nilai tersebut berada dalam fail yang boleh dibaca oleh semua pengguna dalam direktori projek, serta menjauhkannya daripada git.

sudo install -o root -g root -m 600 /dev/null /etc/myapp/app.env
sudo nano /etc/myapp/app.env
    env_file:
      - /etc/myapp/app.env

install -m 600 mencipta fail dengan mod yang telah ditetapkan, jadi tiada tempoh apabila fail itu boleh dibaca oleh semua pengguna. root ialah pemiliknya, jadi pengguna bukan root pada pelayan itu tidak dapat membacanya, walaupun sesiapa yang boleh menjalankan docker masih boleh membaca nilai tersebut daripada kontena. Tambahkan *.env dan .env pada .gitignore, kemudian commit fail app.env.example yang mengandungi nama kunci dengan nilai kosong sebagai ganti. Kata laluan yang telah di-commit perlu ditukar.

Menukar nilai bermakna memulakan semula perkhidmatan. Pemboleh ubah persekitaran dibaca sekali apabila proses kontena bermula, jadi mengedit fail tidak mengubah apa-apa sehingga anda menjalankan docker compose up -d --force-recreate db. Ini ialah corak yang sama seperti dalam panduan n8n di belakang HTTPS pada VPS, yang menyimpan kunci penyulitan di luar fail compose.

Mengasingkan konfigurasi mengikut persekitaran

Compose membaca .env daripada direktori projek secara lalai. Arahkan Compose ke lokasi lain dengan --env-file.

docker compose --env-file .env.staging config

Beberapa fail dibaca mengikut susunan, dan fail yang dibaca kemudian mengatasi fail terdahulu. Simpan nilai lalai yang bukan rahsia dalam fail yang disimpan dalam repositori, dan simpan rahsia dalam fail yang tidak pernah meninggalkan pelayan. Perkara yang sama terpakai pada env_file:, iaitu fail terakhir yang disenaraikan akan digunakan jika terdapat kunci pendua.

FAQ

Mengapakah fail .env saya diabaikan di dalam kontena?

Fail itu tidak diabaikan. Fail .env hanya menggantikan ruang letak ${NAME} dalam fail compose. Fail itu tidak pernah menetapkan pemboleh ubah di dalam kontena. Untuk memasukkan nilai ke dalam kontena, rujuknya: environment: { KEY: "${NAME}" }, atau gunakan env_file: ./that-file.env.

Adakah environment mengatasi env_file, atau sebaliknya?

environment: mempunyai keutamaan. Susunan yang didokumenkan oleh Docker meletakkan atribut environment di atas atribut env_file, dan kedua-duanya berada di bawah docker compose run -e pada baris perintah. Jika kunci ditetapkan di kedua-dua tempat, nilai dalam env_file tidak digunakan secara senyap.

Bagaimanakah saya boleh melihat nilai akhir yang akan digunakan oleh Compose?

Jalankan docker compose config untuk mencetak fail compose yang telah diselesaikan sepenuhnya dengan semua interpolasi digunakan. Untuk kontena yang sedang berjalan, docker inspect <container> --format '{{json .Config.Env}}' memaparkan dengan tepat perkara yang diterima oleh prosesnya.

Adakah rahsia Compose disulitkan?

Tidak. Rahsia berasaskan fail dipasang ke dalam kontena sebagai fail teks biasa di /run/secrets/<name>, manakala fail sumber disimpan pada cakera hos tanpa penyulitan. Manfaatnya ialah skop, bukan penyulitan: nilai itu tidak berada dalam persekitaran kontena, tidak dipaparkan dalam output docker inspect, dan tidak terdapat dalam dump ranap yang mencetak persekitaran.

Bolehkah saya menggunakan tanda petikan dan ruang dalam fail env?

Gunakan KEY=value with spaces dan jangan letakkan tanda petikan. Compose menganggap seluruh baki baris sebagai nilai, jadi tanda petikan biasanya menjadi aksara literal dalam nilai tersebut. Jangan letakkan ruang di sekeliling = kerana kunci itu akan mempunyai ruang hujung dan tiada padanan akan ditemui.