Environment Variables
Environment variables คือกุญแจสำคัญในการตั้งค่าแอปภายใน container ให้ยืดหยุ่นและปลอดภัย เรียนรู้วิธีส่งค่าด้วย -e และ --env-file รวมถึงข้อควรระวังเรื่อง secret
ภาพจำสำคัญบทนี้
Environment variable คือค่าที่ตั้งจากภายนอก container | ส่งด้วย -e KEY=VALUE หรือ --env-file .env | แอปอ่านค่าผ่าน process.env | ห้าม hardcode secret ใน Dockerfile เด็ดขาด
ภาพที่ 1 — host ส่งค่า environment variables เข้า container ตอน run
ภาพที่ 1: ตอน docker run คุณส่งค่า environment variables เข้า container ได้ 2 วิธีหลัก คือ -e สำหรับค่าเดี่ยว และ --env-file สำหรับค่าจากไฟล์ ค่าเหล่านี้จะอยู่ในตาราง env ของ container และแอปภายในอ่านได้ผ่าน process.env
ส่วนที่ 1
Environment Variables คืออะไร
ก่อนจะพูดถึง Docker ลองนึกภาพง่าย ๆ ก่อน เวลาที่คุณตั้งค่าแอปสักตัว เช่น กำหนดว่า "แอปนี้จะรันที่พอร์ตไหน" หรือ "ใช้ฐานข้อมูลอะไร" คุณมีสองทางเลือก: 1. เขียนค่าเหล่านั้นตรง ๆ ลงในโค้ด เช่น const port = 3000 2. ให้โค้ดอ่านค่าจากตัวแปรสภาพแวดล้อม (environment variable) ที่ตั้งไว้จากภายนอกแทน Environment variable คือ ตัวแปรที่ถูกกำหนดไว้ "ระดับระบบปฏิบัติการ" ไม่ใช่ในโค้ด แอปสามารถอ่านค่าเหล่านี้ได้ตอน runtime ในบริบทของ Docker เมื่อเรา run container เราสามารถ "ฉีด" ค่าตัวแปรเหล่านี้เข้าไปได้ ทำให้แอปใน container รับรู้การตั้งค่าโดยไม่ต้องแก้โค้ดหรือ build image ใหม่
ประเด็นที่ 1
ตัวแปรสภาพแวดล้อม (environment variable) — ค่าที่ตั้งไว้ภายนอกโค้ด ระบบปฏิบัติการหรือ Docker จัดการให้
ประเด็นที่ 2
Runtime configuration — แอปอ่านค่าตอนทำงาน ไม่ใช่ตอน compile หรือ build
ประเด็นที่ 3
ตัวอย่างในชีวิตจริง — เหมือนการตั้งนาฬิกาปลุกบนโทรศัพท์ โทรศัพท์เครื่องเดิม แต่เปลี่ยนเวลาตีกี่โมงก็ได้โดยไม่ต้องซื้อเครื่องใหม่
ส่วนที่ 2
ทำไมแอปใน Container จึงควรรับค่าผ่าน Environment Variables
หลายคนอาจสงสัยว่า "แค่เขียน config ลงในโค้ดหรือใน Dockerfile ก็ได้นี่?" คำตอบคือ ได้ แต่จะเกิดปัญหาตามมา ลองนึกภาพว่าคุณมี image เดียว แต่ต้องการ deploy ไปหลาย environment เช่น development, staging, production แต่ละที่มีค่า config ต่างกัน ถ้า hardcode ค่าลงใน image คุณต้อง build image ใหม่ทุกครั้งที่เปลี่ยน environment ซึ่งเป็นสิ่งที่ไม่ดีเลย Environment variables แก้ปัญหานี้ด้วยการแยก config ออกจาก image:
- สร้าง image ครั้งเดียว ใช้ได้หลาย environment — build once, run anywhere เป็น image เดียวกัน แต่ส่งค่า config ต่างกันตอน run
- ไม่ต้อง hardcode ข้อมูลสำคัญลงใน image — รหัสผ่าน, API key, database URL ไม่ติดอยู่ใน image ที่อาจถูกแชร์ public
- เปลี่ยนค่าได้โดยไม่ต้อง rebuild — แก้ PORT หรือ DATABASE_URL แล้ว run container ใหม่ ไม่ต้องรอ build
- ทำงานร่วมกับ CI/CD pipeline ได้ดี — ระบบ deploy สามารถฉีดค่าที่เหมาะสมเข้า container ได้อัตโนมัติ
- ตรงตามหลัก 12-Factor App — แนวปฏิบัติที่ยอมรับกันในอุตสาหกรรมสำหรับ app บน cloud
ส่วนที่ 3
ตัวอย่าง Environment Variables ที่ใช้บ่อยใน Docker
มีค่าตัวแปรหลายอย่างที่แอปทั่วไปมักต้องการตั้งค่า ด้านล่างคือตัวอย่างที่พบบ่อยที่สุด เข้าใจไว้เพื่อจะได้ใช้ได้ทันทีเมื่อเจอในงานจริง:
| ชื่อตัวแปร | ความหมาย | ตัวอย่างค่า |
|---|---|---|
| PORT | พอร์ตที่ server จะรับ request เข้ามา | 3000, 8080, 4000 |
| NODE_ENV | บอกแอปว่ากำลังรันใน environment ไหน | development, production, test |
| DATABASE_URL | connection string สำหรับเชื่อมต่อฐานข้อมูล | postgresql://user:pass@db:5432/mydb |
| SECRET_KEY | key ลับสำหรับ sign token หรือเข้ารหัสข้อมูล | s3cr3t-k3y-here |
| API_URL | URL ของ external API ที่แอปจะเรียกใช้ | https://api.example.com |
| LOG_LEVEL | ระดับความละเอียดของ log ที่ต้องการแสดง | debug, info, warn, error |
ภาพที่ 2 — flow การส่งค่า env จาก host สู่การใช้งานในแอป
ภาพที่ 2: flow การทำงาน — (1) คุณส่ง env ตอน docker run → (2) Docker เก็บค่าไว้ในตาราง env ของ container → (3) แอปอ่านค่าผ่าน process.env ตอน runtime → (4) แอปนำค่าไปใช้จริง เช่น เลือก port หรือ config ตาม environment
ส่วนที่ 4
วิธีส่ง Environment Variable เข้า Container ด้วย Flag -e
วิธีพื้นฐานที่สุดในการส่ง env เข้า container คือการใช้ flag -e (หรือ --env ซึ่งเขียนแบบยาวก็ได้) ต่อท้ายคำสั่ง docker run รูปแบบคือ: docker run -e VARIABLE_NAME=value image-name ตัวอย่างด้านล่างส่ง NODE_ENV=production เข้าไปใน container ที่ run จาก image nginx ซึ่งหมายความว่าเมื่อแอปใน container อ่านค่า NODE_ENV จะได้ค่า "production"
flag -e ตามด้วย KEY=VALUE จะตั้งค่า environment variable ชื่อ NODE_ENV ให้มีค่าเป็น "production" ภายใน container นั้น
ส่วนที่ 5
ส่ง Environment Variables หลายตัวพร้อมกัน
ในชีวิตจริง แอปมักต้องการหลายค่าพร้อมกัน เช่น ต้องรู้ทั้ง PORT, NODE_ENV, และ DATABASE_URL สามารถใส่ -e ซ้ำได้หลาย flag ในคำสั่งเดียว แต่ละ -e ตั้งค่าตัวแปรหนึ่งตัว:
ใส่ -e ได้กี่ตัวก็ได้ต่อคำสั่งเดียว แต่ถ้ามี env เยอะ ๆ วิธีนี้จะยาวและจัดการยาก ให้ใช้ --env-file แทน (ดูหัวข้อถัดไป)
ส่วนที่ 6
วิธีส่ง Environment Variables ผ่านไฟล์ด้วย --env-file
เมื่อ env มีหลายตัว การพิมพ์ -e ซ้ำ ๆ ทำให้คำสั่งยาวมาก อ่านยาก และเกิดข้อผิดพลาดได้ง่าย วิธีที่ดีกว่าคือเก็บค่าทั้งหมดไว้ในไฟล์ .env แล้วใช้ flag --env-file ชี้ไปที่ไฟล์นั้น Docker จะอ่านไฟล์และตั้งค่าทุก env ให้อัตโนมัติ รูปแบบ: docker run --env-file .env image-name ข้อดีสำคัญ: ไฟล์ .env เก็บแยกจากคำสั่ง สามารถมีหลายไฟล์สำหรับแต่ละ environment ได้ เช่น .env.dev, .env.prod
Docker จะอ่านไฟล์ .env ในไดเรกทอรีปัจจุบัน และตั้งค่า environment variable ทุกบรรทัดเข้าไปใน container โดยอัตโนมัติ
ส่วนที่ 7
ตัวอย่างไฟล์ .env
ไฟล์ .env เป็นไฟล์ plain text ธรรมดา แต่ละบรรทัดมีรูปแบบ KEY=VALUE บรรทัดที่ขึ้นต้นด้วย # คือ comment ข้อควรระวัง: ไม่ควรใส่ช่องว่างรอบเครื่องหมาย = และค่าที่มีช่องว่างควรใส่เครื่องหมาย quote ล้อมรอบ
ไฟล์นี้ควรถูก ignore ด้วย .gitignore เสมอ เพื่อไม่ให้ค่าสำคัญถูก commit ขึ้น repository
ส่วนที่ 8
แอปอ่านค่า Environment Variables ภายใน Container อย่างไร
เมื่อ Docker ตั้งค่า env เข้าไปใน container แล้ว แอปที่รันอยู่จะอ่านค่าผ่าน API ของภาษาที่ใช้งาน สำหรับ Node.js ใช้ object ชื่อ process.env ซึ่งเป็น object ที่มี property เป็นชื่อ env ทุกตัวที่ถูกตั้งไว้ ตัวอย่างด้านล่างแสดงแอป Express ที่อ่านค่า PORT จาก environment variable ถ้าไม่มีค่าจะใช้ค่า default 3000:
process.env.VARIABLE_NAME จะได้ค่าเป็น string เสมอ ถ้า env นั้นไม่ถูกตั้งค่าไว้ จะได้ undefined — ควรตรวจสอบก่อนใช้งานเสมอ
ส่วนที่ 9
ข้อดีของการใช้ Environment Variables
สรุปข้อดีหลักที่ทำให้ environment variables เป็นวิธีมาตรฐานสำหรับการตั้งค่าแอปใน container:
ส่วนที่ 10
ข้อควรระวังเรื่อง Secret และข้อมูลสำคัญ
แม้ environment variables จะดีกว่า hardcode แต่ยังมีข้อควรระวังสำคัญ โดยเฉพาะเมื่อค่าเหล่านั้นเป็น secret เช่น รหัสผ่านหรือ API key:
- ห้าม commit ไฟล์ .env ขึ้น Git repository — เพิ่ม .env ลงใน .gitignore เสมอ ถ้า secret รั่วไปใน Git history จะถอนคืนได้ยากมาก
- อย่า log ค่า env ที่เป็น secret — การ console.log(process.env) ทั้งหมดอาจเปิดเผยรหัสผ่านใน log ที่คนอื่นเห็นได้
- env ที่ส่งด้วย -e สามารถมองเห็นได้ด้วย docker inspect — ใครที่เข้าถึง Docker daemon ได้จะเห็นค่าเหล่านี้
- สำหรับ secret จริง ๆ ควรใช้ Docker Secrets หรือ Vault — เครื่องมือเหล่านี้ออกแบบมาเพื่อจัดการ secret โดยเฉพาะ ปลอดภัยกว่า env ธรรมดา
- สร้างไฟล์ .env.example ไว้ใน repo — เก็บชื่อตัวแปรและค่าตัวอย่าง (ไม่ใช่ค่าจริง) เพื่อให้ developer คนอื่นรู้ว่าต้องตั้งค่าอะไรบ้าง
ภาพที่ 3 — เปรียบเทียบ hardcode config กับ environment variables
ภาพที่ 3: เปรียบเทียบโดยตรง — ฝั่งซ้าย hardcode config ลงใน Dockerfile ทำให้ secret ติดอยู่ใน image และต้อง rebuild ทุกครั้ง ฝั่งขวาใช้ environment variables ทำให้ image สะอาด ยืดหยุ่น และปลอดภัยกว่า
ส่วนที่ 11
สิ่งที่ไม่ควรทำ — อย่า Hardcode ค่าสำคัญใน Dockerfile
ตัวอย่างด้านล่างแสดงสิ่งที่ไม่ควรทำ: การใช้คำสั่ง ENV ใน Dockerfile เพื่อฝังค่า secret ลงในตัว image โดยตรง ปัญหาคือ image ที่ build ออกมาจะมีค่าเหล่านี้อยู่ทุก layer ถึงแม้จะ build ทับก็ยังสามารถ extract ออกมาได้ด้วย docker history หรือ dive
ค่าที่ตั้งด้วย ENV ใน Dockerfile จะถูก bake เข้าไปใน image ทุกคน ที่ pull image ไปจะเห็นค่าเหล่านี้ได้ ควรส่งผ่าน -e หรือ --env-file ตอน run แทน
ส่วนที่ 12
เปรียบเทียบ: Hardcode Config กับ Environment Variables
ตารางด้านล่างเปรียบเทียบสองแนวทางเพื่อให้เห็นภาพชัดว่าทำไม environment variables จึงเป็นวิธีที่แนะนำ:
| วิธีการ | ข้อดี | ข้อเสีย |
|---|---|---|
| Hardcode ใน Dockerfile / โค้ด | ง่าย ไม่ต้องตั้งค่าเพิ่ม | ต้อง rebuild ทุกครั้งที่เปลี่ยนค่า, secret ติดอยู่ใน image, ใช้ข้ามสิ่งแวดล้อมไม่ได้ |
| Environment Variables (-e / --env-file) | ยืดหยุ่น, image เดียวใช้ได้ทุก environment, config แยกออกจาก code | ต้องจัดการไฟล์ .env อย่างระมัดระวัง, env ธรรมดาไม่เหมาะสำหรับ secret ระดับ production จริง ๆ |
| Docker Secrets / Vault | ปลอดภัยสูงสุด, เหมาะสำหรับ production จริง ๆ | ซับซ้อนกว่า ต้องตั้งค่าเพิ่มเติม เหมาะสำหรับระบบขนาดกลาง-ใหญ่ |
ส่วนที่ 13
สถานการณ์จริงในการ Deploy แอป
ลองดูตัวอย่างการใช้ environment variables ใน workflow จริง ที่ deploy แอปเดียวไปหลาย environment โดยใช้ image เดียวกัน:
ส่วนที่ 14
สรุปบทนี้
บทนี้ครอบคลุมทุกสิ่งที่จำเป็นในการใช้ environment variables กับ Docker container ด้านล่างคือสิ่งสำคัญที่ควรจำ:
ประเด็นที่ 1
Flag -e KEY=VALUE — ใช้ส่ง env ทีละตัวตอน docker run เหมาะสำหรับ env ไม่กี่ตัวหรือการทดสอบเร็ว ๆ
ประเด็นที่ 2
Flag --env-file .env — ใช้ส่ง env จากไฟล์ เหมาะสำหรับ env หลายตัว อ่านง่ายกว่า และจัดการได้สะดวก
ประเด็นที่ 3
process.env.VARIABLE_NAME — วิธีที่ Node.js อ่านค่า env แต่ละภาษามี API ของตัวเอง เช่น Python ใช้ os.environ
แบบฝึกหัด
ทดสอบความเข้าใจ
ลองตอบคำถามต่อไปนี้ด้วยตัวเอง แล้วกดดูแนวเฉลยเพื่อเปรียบเทียบ