Env Vars, Volumes และ Networks
Environment variables ใน Compose
หัวข้อที่มีชื่อว่า “Environment variables ใน Compose”มีสองวิธีในการส่ง environment variables เข้า service
Inline environment
หัวข้อที่มีชื่อว่า “Inline environment”กำหนด variables โดยตรงใน compose.yaml:
services: app: image: myapp:latest environment: - NODE_ENV=production - PORT=3000env_file
หัวข้อที่มีชื่อว่า “env_file”อ้างอิงไฟล์ภายนอก Compose อ่านแต่ละบรรทัด KEY=VALUE จากไฟล์และฉีดเข้า container:
services: app: image: myapp:latest env_file: - .envไฟล์ .env:
NODE_ENV=productionPORT=3000DATABASE_URL=postgres://db:5432/mydbเก็บ .env ออกจาก version control — มักมี secrets อยู่
Variable interpolation ด้วย ${VAR}
หัวข้อที่มีชื่อว่า “Variable interpolation ด้วย ${VAR}”Compose อ่านไฟล์ .env ใน directory เดียวกับ compose.yaml แล้วเอาค่าจากไฟล์นั้นไปแทนที่ placeholder ${VAR} ภายใน compose.yaml เอง:
services: db: image: postgres:17-alpine environment: - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=${DB_NAME}ด้วยไฟล์ .env ที่มี:
DB_PASSWORD=supersecretDB_NAME=mydbCompose แทนที่ค่าก่อนสตาร์ท container นี่ทำให้ secrets ไม่ต้องอยู่ใน compose.yaml และให้นักพัฒนาแต่ละคนใช้ไฟล์ .env ของตนเองได้
Named volumes
หัวข้อที่มีชื่อว่า “Named volumes”container เป็น ephemeral — ข้อมูลที่เขียนภายใน container จะหายเมื่อ container ถูกลบ Named volumes เก็บข้อมูลบน host และอยู่รอดได้แม้ container จะ restart หรือถูก recreate
ประกาศ named volume ที่ระดับบนสุดและ mount ต่อ service:
services: db: image: postgres:17-alpine volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=secret
volumes: pgdata:key volumes: ระดับบนสุด register volume กับ Compose ส่วนรายการ volumes: ระดับ service เป็นตัว mount volume นั้นเข้าไป คุณสามารถ mount named volume เดียวกันในหลาย service ได้
Custom networks
หัวข้อที่มีชื่อว่า “Custom networks”Compose สร้าง default network อัตโนมัติ สำหรับการควบคุมมากขึ้น — แยก services หรือเชื่อมต่อ services ข้าม Compose files — กำหนด custom networks:
services: frontend: image: nginx:alpine networks: - public
backend: image: myapp:latest networks: - public - private
db: image: postgres:17-alpine networks: - private
networks: public: private:ที่นี่ frontend เข้าถึง backend ได้ แต่ frontend ไม่สามารถเข้าถึง db โดยตรง backend เชื่อม network ทั้งสอง
ลองปฏิบัติจริง
หัวข้อที่มีชื่อว่า “ลองปฏิบัติจริง”snippet ด้านล่างเชื่อมต่อ service กับ env file และ named volume เพื่อให้ข้อมูลอยู่รอดได้หลัง restart
# Create .env file
cat > .env <<'EOF'
APP_MSG=Hello from .env interpolation!
VOLUME_DATA_DIR=/data
EOF
# Create compose.yaml with env interpolation and a named volume
cat > compose.yaml <<'EOF'
services:
writer:
image: alpine
env_file:
- .env
volumes:
- mydata:${VOLUME_DATA_DIR}
command: >
sh -c "
echo ${APP_MSG} &&
echo 'Writing to named volume...' &&
echo 'persistent data' > ${VOLUME_DATA_DIR}/file.txt &&
echo 'Wrote file to volume.'
"
reader:
image: alpine
volumes:
- mydata:/data
command: >
sh -c "
sleep 2 &&
echo 'Reading from volume:' &&
cat /data/file.txt
"
depends_on:
- writer
volumes:
mydata:
EOF
# Run both services
docker compose up
# Verify the volume still exists after containers stop
docker volume ls | grep mydata
# Clean up (keeps the volume)
docker compose down
# Clean up including the volume
docker compose down -vข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
.env + interpolation | secrets ไม่ต้อง hardcode ใน compose.yaml นักพัฒนาแต่ละคนใช้ค่าตัวเองได้ | ต้องดูแลไฟล์ .env เองนอก git และ sync key ให้ตรงกับที่ compose.yaml อ้างอิง |
| named volume + custom network | ข้อมูลอยู่รอดข้าม restart และแยก traffic ตาม network ได้ชัดเจน | volume/network ผูกกับชื่อ project — ถ้าตั้งชื่อโปรเจกต์ชนกัน อาจ mount ข้อมูลผิดตัว |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- commit ไฟล์
.envที่มี secret จริง (เช่นDB_PASSWORD) เข้า git โดยไม่ได้ตั้งใจ ควรใส่.envใน.gitignoreเสมอและ commit แค่.env.example - ลืมว่า named volume และ network ที่ Compose สร้างให้เป็นแบบ project-scoped (ตั้งชื่อจาก directory) โปรเจกต์ที่ชื่อคล้ายกันอาจสร้าง volume ซ้ำซ้อนโดยไม่รู้ตัว
- สับสนระหว่าง
environment:กับenv_file:แล้วคาดหวังว่าไฟล์.envจะถูกอ่านเข้า container เองโดยไม่ต้องประกาศenv_file:ทั้งที่ interpolation กับ env_file เป็นคนละกลไกกัน
💡 ตัวอย่างจากของจริง
ทีมที่ทำ CI/CD มักแยก
.env.example(commit เข้า git เพื่อ document ว่า key ไหนต้องตั้งค่า) ออกจาก.envจริงที่เก็บ secret และฉีดเข้าเครื่องผ่าน secret manager หรือ CI variable แทน — pattern เดียวกับที่ทีม dev ใช้ Compose local แล้วส่ง secret จริงผ่าน Kubernetes Secret ตอน deploy production