การเขียน Password และ Secret ตรงๆ ใน docker-compose.yml เป็น Bad Practice ที่ต้องหลีกเลี่ยง โดยเฉพาะเมื่อต้องการ Commit โค้ดขึ้น Git เพราะ Credential จะถูกเปิดเผย วิธีที่ถูกต้องคือการใช้ Environment Variables และ .env File ซึ่งแยก Configuration ออกจากโค้ด และเป็น Best Practice ของ 12-Factor App ที่ DevOps ทุกคนควรรู้
Environment Variables คืออะไร?
Environment Variables คือตัวแปรที่กำหนดค่าให้ Process (Container) สามารถอ่านได้ขณะรัน ใน Docker Compose มี 3 วิธีหลักในการกำหนด Environment Variables:
- Inline — เขียนตรงๆ ใน docker-compose.yml
- env_file — อ่านจากไฟล์ .env แยกต่างหาก
- Shell Environment — รับค่าจาก Environment ของ Host Machine
วิธีที่ 1: Inline (ไม่แนะนำสำหรับ Secret)
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword # ❌ ไม่ควรทำ
MYSQL_DATABASE: mydb
MYSQL_USER: user
MYSQL_PASSWORD: secret123 # ❌ ไม่ควรทำ
แม้จะง่าย แต่ไม่ควรใช้สำหรับ Password เพราะหากนำโค้ดขึ้น Git จะเปิดเผย Credential ทันที
วิธีที่ 2: .env File (แนะนำ)
สร้างไฟล์ .env ในโฟลเดอร์เดียวกับ docker-compose.yml:
# .env
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wppassword
WP_PORT=8080
จากนั้นใช้ตัวแปรใน docker-compose.yml ด้วย Syntax ${VARIABLE_NAME}:
version: '3.8'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
networks:
- wp_network
wordpress:
image: wordpress:latest
depends_on:
- db
ports:
- "${WP_PORT}:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
networks:
- wp_network
volumes:
db_data:
networks:
wp_network:
Docker Compose จะอ่านไฟล์ .env โดยอัตโนมัติ ไม่ต้องระบุอะไรเพิ่มเติม
วิธีที่ 3: env_file (กำหนด Path เอง)
หากต้องการใช้ไฟล์ชื่ออื่น หรือหลายไฟล์ ใช้ env_file:
services:
db:
image: mysql:8.0
env_file:
- ./config/database.env # ไฟล์ .env ที่กำหนดเอง
- ./config/common.env # รวมหลายไฟล์ได้
ตัวอย่าง database.env:
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wppassword
ต้องเพิ่ม .env ใน .gitignore เสมอ
สิ่งสำคัญมากคือต้องป้องกันไม่ให้ไฟล์ .env ถูก Commit ขึ้น Git:
# .gitignore
.env
*.env
!.env.example # ยกเว้น Template ไฟล์
แนะนำให้สร้าง .env.example เพื่อเป็น Template สำหรับ Developer คนอื่น:
# .env.example (commit ไฟล์นี้ขึ้น Git ได้)
MYSQL_ROOT_PASSWORD=your_root_password_here
MYSQL_DATABASE=wordpress
MYSQL_USER=your_db_user_here
MYSQL_PASSWORD=your_db_password_here
WP_PORT=8080
Default Values และ Required Variables
Docker Compose รองรับ Syntax พิเศษสำหรับจัดการกรณีที่ตัวแปรไม่ถูกกำหนด:
services:
app:
environment:
# ใช้ค่า Default ถ้า APP_PORT ไม่ถูกกำหนด
PORT: ${APP_PORT:-3000}
# Error ถ้า DB_HOST ไม่ถูกกำหนด (Required)
DATABASE_URL: ${DB_HOST:?DB_HOST is required}
# ใช้ค่าว่างถ้าไม่ถูกกำหนด (ไม่แนะนำสำหรับ Password)
OPTIONAL_VAR: ${OPTIONAL_VAR:-}
| Syntax | ความหมาย |
|---|---|
${VAR:-default} |
ใช้ค่า default ถ้า VAR ว่างหรือไม่กำหนด |
${VAR-default} |
ใช้ค่า default ถ้า VAR ไม่กำหนด (แต่ยอมรับค่าว่าง) |
${VAR:?error msg} |
หยุดทำงานพร้อม Error ถ้า VAR ว่างหรือไม่กำหนด |
${VAR?error msg} |
หยุดทำงานพร้อม Error ถ้า VAR ไม่กำหนด |
ตรวจสอบ Variables ก่อนรัน
ใช้คำสั่ง docker compose config เพื่อดูว่าตัวแปรถูกแทนค่าถูกต้องหรือไม่:
# แสดง Config ที่ถูก Interpolate แล้ว
docker compose config
# ตรวจสอบเฉพาะ Environment Variables
docker compose config | grep -A 20 environment
ลำดับความสำคัญของ Environment Variables
เมื่อมีการกำหนดตัวแปรหลายแหล่ง Docker Compose จะใช้ลำดับนี้ (สูงสุดก่อน):
- Shell Environment Variables ของ Host (ลำดับสูงสุด)
- ตัวแปรที่กำหนดใน docker-compose.yml โดยตรง
- ไฟล์ .env ในโฟลเดอร์โปรเจกต์
- ค่า Default ที่กำหนดใน Image (Dockerfile)
ตัวอย่าง: ถ้า Set WP_PORT=9090 ใน Shell แล้วรัน docker compose ขึ้นมา ค่าที่ใช้จะเป็น 9090 แทนที่ค่าใน .env
ตัวอย่างสมบูรณ์: WordPress Stack ด้วย .env
โครงสร้างไฟล์:
wordpress-stack/
├── docker-compose.yml
├── .env # ← ไม่ Commit ขึ้น Git
├── .env.example # ← Commit ขึ้น Git ได้
└── .gitignore
ไฟล์ .env:
MYSQL_ROOT_PASSWORD=SuperSecret123!
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=WpPass456!
WP_PORT=8080
MYSQL_PORT=3306
ไฟล์ docker-compose.yml:
version: '3.8'
services:
db:
image: mysql:8.0
container_name: wordpress_db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD required}
MYSQL_DATABASE: ${MYSQL_DATABASE:-wordpress}
MYSQL_USER: ${MYSQL_USER:?MYSQL_USER required}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD required}
volumes:
- db_data:/var/lib/mysql
networks:
- wp_network
wordpress:
image: wordpress:latest
container_name: wordpress_app
restart: unless-stopped
depends_on:
- db
ports:
- "${WP_PORT:-8080}:80"
environment:
WORDPRESS_DB_HOST: db:${MYSQL_PORT:-3306}
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
volumes:
- wp_data:/var/www/html
networks:
- wp_network
volumes:
db_data:
wp_data:
networks:
wp_network:
สรุป Best Practices
| Best Practice | เหตุผล |
|---|---|
| ใช้ .env แทนการ Hardcode | แยก Config ออกจากโค้ด |
| เพิ่ม .env ใน .gitignore | ป้องกัน Credential รั่วไหล |
| สร้าง .env.example | ช่วย Developer คนอื่นตั้งค่า |
| ใช้ 😕 สำหรับ Required Vars | Fail-Fast แทนที่จะรันด้วยค่าผิด |
| ใช้ :- สำหรับ Optional Vars | มี Default ที่ปลอดภัย |
| รัน docker compose config | ตรวจสอบก่อน Deploy |
ขอแสดงความยินดี! คุณได้เรียนรู้ครบทุกบทความในชุด Docker Compose แล้ว ตั้งแต่พื้นฐานจนถึงการ Deploy Stack จริง บทความชุดถัดไปจะเป็นเรื่อง Reverse Proxy & SSL ซึ่งจะสอนให้คุณรัน Container บน Domain จริง พร้อม HTTPS โดยใช้ Nginx Proxy Manager และ Let’s Encrypt

