[PHP x Container] ทบทวนการย้าย PHP Web Application มาทำงานบน Container
เมื่อเราต้องย้ายบ้าน จาก Host มาเป็น Container แต่ PHP บน Container มันก็เรื่องเยอะเหลือเกิน ยังดีที่หลายอย่างทำได้ง่ายกว่าทำ Host เองนะ
ใน Blog นี้ จะเป็นเรื่องการทบทวน การย้าย PHP Web Application จาก Host มาเป็น Container ว่ามีอะไรบ้างที่ควรรู้ สิ่งที่ต้องทำ และเกร็ดเล็กเกร็ดน้อย ที่ได้มาจากการลงมือทำครับ
LAMP/LEMP Stack (Linux, Apache/Nginx, MySQL, PHP)
[https://www.nipa.cloud/blog/lemp-program-dev]
สรุปง่าย ๆ LAMP/LEMP ก็คือเช็ตของ Open Source ที่ใช้ประกอบกันเพื่อสร้าง Web Application ขึ้นมานั่นเอง
- L (Linux) คือ OS
- A/E (Apache httpd/Nginx) คือ Web Server ถ้าเป็นภาษาในสมัยนี้ จะมี Web Server มาในตัวเลย ไม่จำเป็นต้องใช้ตัวแยกแบบเมื่อก่อนแล้ว
- M (MySQL) คือ Database ในสมัยนี้ก็ไม่จำเป็นแล้ว ว่าต้องเป็น MySQL เนื่องจากเรามีทางเลือกมากขึ้น ควรเน้นใช้ให้เหมาะกับงาน จะดีที่สุด
- P (PHP) คือ Runtime ที่เราใช้งาน
LAMP Stack on Container
เนื่องจากผมชอบที่จะให้ Stack Linux, Apache, PHP ทำงานได้บน Image ตัวเดียว ดังนั้นจึงเลือกใช้ Image php:apache
เป็นหลัก
สำหรับสาย PHP คงเข้าใจดีกว่า นอกจากตัว Web Server แล้ว PHP Extension และ Configuration ก็สำคัญไม่แพ้กันครับ
Extension
เรื่อง Extension นี่แหละที่จะน่าปวดหัวหน่อย เพราะเราต้องปรับนุ่นปรับนี่ ปรับทีนึงก็จะต้องลอง Build Image ใหม่ทีนึง ตรงนี้ถึงแม้ว่า Docker Build จะช่วย Cache Layer ไว้ใช้ แต่สิ่งที่เราเปลี่ยนมันอยู่ใน Layer เดียวกัน ฉะนั้น Cache จึงไม่ได้ช่วยอะไรเรา
เข้าเรื่องกันดีกว่า
ถ้าใช้ PHP Official Image ทางทีมได้เตรียม คำสั่งสำเร็จมาให้แล้วครับ ใช้งานได้สะดวกมาก มีตัวอย่างการใช้งานมาให้เสร็จ ใช้เวลาศึกษาไม่นานก็เข้าใจได้ครับ
Configuration
ถ้าใช้ PHP Official Image ทางทีมได้เตรียมไฟล์ php.ini มาให้ 2 แบบ คือ php.ini-development และ php.ini-productionโดยค่าเริ่มต้น จะเป็นแบบที่เหมาะกับ Development แต่เราสามารถเปลี่ยนเป็นแบบ Production ได้ รวมถึงจะใช้แบบที่เรา Config เองก็ได้เช่นกันครับ
ลงมือกันดีกว่า
Basic Image and Container
สร้าง Image อย่างง่าย เริ่มกันที่ สร้างไฟล์ Dockerfile ก่อนครับ
อธิบาย
บรรทัดที่ 1 เราเลือก Base Image มาจาก php:apache
ตัวนี้จะมี Apache มาในตัวแล้ว พร้อมใช้งานได้เลยครับ
บรรทัดที่ 3 Copy ไฟล์ทั้งหมด จาก Folder src ไปไว้ที่ /var/www/html/ ใน Image
ใน Folder src เราทำไว้แค่ไฟล์เดียวก่อนครับ คือ index.php หน้าตาแบบนี้
จากนั้น เราจะลอง Build Image และ Run container ขึ้นมา จาก Image ที่เราสร้างไว้ครับ ด้วยคำสั่ง
docker build -t php-blog .
docker run -d --name php-blog -p 80:80 php-blog
ถ้าไม่มีปัญหาอะไร เราควรจะได้ Container ที่ทำงานได้แล้ว ใน Container จะมี Apache httpd ทำงานอยู่ ลองเปิด Browser ดู ควรจะเห็นลักษณะนี้ครับ
เปิดใช้งาน MySQL Extension
จากขั้นตอนที่ผ่านมา โดยพื้นฐานแล้ว MySQL Extension จะยังไม่ได้ถูกเปิดการใช้งานไว้ เราต้องเปิดเอง ด้วยการปรับไฟล์ Dockerfile นิดหน่อยครับ
อธิบาย
บรรทัดที่ 3 จะใช้คำสั่ง docker-php-ext-install
ที่ทางผู้พัฒนา Image ตัวนี้ได้เตรียมไว้ให้ เพื่อติดตั้งและเปิดใช้งาน Extension mysqli และ pdo_mysql เพิ่มเติมครับ
จากนั้น เราจะลอง Build Image และ Run container ขึ้นมา จาก Image ที่เราสร้างไว้ครับ (อย่าลืมลบ Container ตัวเก่าก่อน)
จาก phpinfo() ตอนนี้เราจะเห็น Extension mysqli และ pdo_mysql แสดงขึ้นมาแล้ว
ปรับแต่ง Configuration ให้เหมาะกับ Production
ทางผู้พัฒนา Image ตัวนี้ได้เตรียม php.ini มาให้แล้วครับ โดยพื้นฐานจะใช้ php.ini-development แต่เราสามารถเลือกใช้ php.ini-production แทนได้ด้วย
จุดต่างที่จะเห็นได้ชัดที่สุด ระหว่าง php.ini-development กับ php.ini-production จะเป็นเรื่องการแสดง Error ครับ ใน Blog นี้ เราจะใช้จุดนี้เป็นตัวชี้วัดการสลับไฟล์ php.ini-development กับ php.ini-production ว่าเราทำได้ถูกต้องหรือไม่ครับ
แน่นอนว่าเราจะต้องปรับแต่งตัวไฟล์ Dockerfile กันนะครับ
อธิบาย
บรรทัดที่ 3 จะใช้คำสั่ง ARG
เพื่อรับค่าตอนที่สั่ง docker build
และยังกำหนดค่าเริ่มต้นดักไว้ด้วย
บรรทัดที่ 7 จะเลือกไฟล์ php.ini มาใช้ ระหว่าง php.ini-development กับ php.ini-production จะขึ้นอยู่กับค่า ARG
ที่ส่งเข้ามาครับ
ปล. ใครเอาตรงนี้ไปใช้แบบไม่ระวัง ต้องระวังชีวิตเปลี่ยนนะครับ
และเพื่อให้เห็นความแตกต่างอย่างชัดเจน เราจะสร้างไฟล์ที่ตั้งใจให้เกิด Error ขึ้นมาครับ
จากนั้น เราจะลอง Build Image และ Run container ขึ้นมา จาก Image ที่เราสร้างไว้ครับ (อย่าลืมลบ Container ตัวเก่าก่อน)
คำสั่ง Build Image ตอนนี้จะมี 2 ทางเลือก คือ การ Build Image สำหรับ non-production กับ production ครับ
non-production
docker build -t php-blog .
production
docker build -t php-blog --build-arg env=production .
จะเห็นได้ว่าการแสดง Error จะต่างกันอย่างชัดเจนระหว่าง php.ini-development กับ php.ini-production นะครับ
พร้อมใช้งานในระดับเบื้องต้นแล้ว
มาถึงจุดที่ก็ถือว่าพร้อมใช้งานในระดับเบื้องต้นแล้วครับ สามารถใช้งานทดแทน LAMP/LEMP Stack ได้แน่นอน