Docker เป็น Container Technology ที่มาแรงมาก ปัจจุบัน บริษัททั้งในต่างประเทศ และในประเทศไทยเอง ได้มีการนำมาใช้งานกันค่อนข้างเยอะแล้ว ด้วยการออกแบบมาให้ใช้งานง่าย และเป็นมิตรกับทั้งฝั่ง Developer และ Operation อย่างมาก
สำหรับ Docker เป็นเครื่องมือที่ต้องการ Environment ที่เป็น Linux และในช่วงแรก ๆ นั้น ทีมงานได้ออกเครื่องมือมาให้ใช้ในชื่อของ Docker Toolbox เพื่อให้สามารถใช้งานบน Windows และ macOS ได้ ซึ่งในปัจจุบันได้มี Docker Native ออกมาให้ใช้งาน ซึ่งจะมีความเหมือนกับ Docker บน Linux มากกว่า และมีความสะดวกกว่า Docker Toolbox เป็นอย่างมาก แต่ก็มีข้อจำกัดในฝั่งของ Windows ซึ่งต้องใช้ Windows 10 รุ่น 64 bits และเป็น Pro, Enterprise หรือ Education Edition เท่านั้น (Build 10586 หรือใหม่กว่า)
สำหรับมือใหม่ Docker ที่ได้ลองใช้งาน Docker Toolbox มาแล้วนั้น เชื่อว่าเกือบทุกคน (รวมถึงผมเอง) ใช้เวลาทำความเข้าใจกับเรื่องของการจัดการไฟล์ และ Port ที่ต้องการเปิด เป็นอย่างมาก กว่าจะทำให้สามารถ Map path/file และ Map port ได้ บางคนอาจถึงกับท้อ และเข้าใจว่า Docker ยุ่งยาก ก็เป็นได้
ยาวไปไม่อ่าน…
บทความในตอนนี้ จะแนะนำสิ่งที่แตกต่างกันระหว่าง Docker Toolbox และ Docker บน Linux ซึ่งความแตกต่าง ทำให้การใช้งานยุ่งยากใน 2 เรื่อง คือ
- การกำหนด Port แก้ปัญหาโดยการกำหนด Port Forward
- การ Mount ไฟล์ แก้ปัญหาโดยการกำหนด Shared Folders
Docker Toolbox vs Docker Native
ก่อนอื่น เรามาทำความเข้าใจกับ Docker Toolbox กันซักหน่อยว่า มีความแตกต่างจาก Docker Native หรือ Docker บน Linux อย่างไร ลองดูรูปต่อไปนี้ครับ

รูปจาก https://www.synbioz.com/blog/premiers_pas_avec_docker
จากรูปด้านบน ฝั่งซ้ายนั้นก็คือการใช้งาน Docker บน Linux ส่วนฝั่งขวาคือการใช้งาน Docker Toolbox บน Windows หรือ macOS
สังเกตุว่า Docker Toolbox นั้น จะมีส่วนของ VM (Oracle VM VirtualBox) เพิ่มเข้ามา มี OS ที่รันอยู่ภายในนั่นก็คือ Boot2Docker ซึ่งก็เป็น Linux ขนาดเล็ก ๆ เพื่อให้สภาพแวดล้อมของการใช้งาน Docker นั้น เหมือนกับการใช้งานบน Linux และนำ Docker client ออกมาอยู่ที่ OS ของเรา
สำหรับ Docker client นั้น จะเป็นส่วนที่ไว้ติดต่อกับผู้ใช้งาน นั่นก็คือส่วนที่ไว้ให้เราออกคำสั่งต่าง ๆ ผ่านคำสั่ง docker
เมื่อการออกคำสั่งบน Docker client แล้ว ตัว Docker client จะส่งคำสั่งไปยัง Docker daemon (หรือเรียกว่า Docker server ก็ได้) ซึ่งตัว Docker daemon จะเป็นผู้ที่รับคำสั่งเพื่อไปประมวลผลต่อไป
ถ้าเราป้อนคำสั่ง docker version
ดู ก็จะเห็นเป็น 2 ส่วน นั่นคือส่วนของ Client และ Server (Daemon) นั่นเอง

สมมติว่า เราต้องการรัน Web Server ขึ้นมาซักตัวนึง (เอา NGINX ละกันเน๊าะ) แน่นอนว่า Web Server เรา จะ Listen อยู่ที่ Port 80 ด้วยคำสั่งดังนี้
1 |
$ docker run -d --name web -p 81:80 nginx:alpine |
คำสั่งด้านบน เป็นการสร้าง Docker Container จาก Docker Image ชื่อ nginx:alpine
รันในโหมด Background (-d
) โดยให้ชื่อ Container ว่า web
(--name web
) และทำการ Publish container port 80
ภายใน container ออกมายัง port 81
ข้างนอก (-p 81:80
) และใช้ Default command ที่ประกาศไว้ใน Docker Image (ไม่ระบุคำสั่งตามหลังชื่อ Docker Image)
หลังจากรันคำสั่งแล้ว ก็จะได้ Web Server พร้อมให้บริการที่ port 81
ซึ่งถ้าเราเปิด Web Browser ดู ที่ http://localhost:81
หรือ http://127.0.0.1:81
ก็ควรจะเห็น Landing page หรือหน้าแรกของ NGINX Web Server แล้ว

ถ้าใช้ Docker Toolbox จะยังไม่สามารถเปิดได้~!! ก็เพราะเรื่องของประตูมิตินี่ล่ะ ลองดูภาพด้านล่างกัน

สังเกตุว่า สำหรับ Docker บน Linux นั้น เราสามารถเข้าถึง Port 81 ได้เลย แต่สำหรับ Docker Toolbox นั้น จะไม่สามารถเข้าผ่าน localhost หรือ 127.0.0.1 ได้ เพราะว่า Client ร้องขอไปที่เครื่องตัวเอง ซึ่ง Port 81 นั้น เปิดอยู่ใน VM (ท่อสีน้ำเงินต่อไม่ถึงท่อสีส้ม)
ลองกลับไปหา IP ของ Boot2Docker ดู (ดูจากที่ Docker Terminal แจ้งไว้ตอน Start ก็ได้) อย่างในรูปด้านล่าง จะเป็น IP 192.168.99.100
ก็ลองเปิด Web Browser ไปที่ http://192.168.99.100:81
ดู ถึงจะเห็น Landing page



จากรูปด้านบน เมื่อเราใช้ IP ของ VM ในการติดต่อไป จะเป็นการเชื่อมต่อตามท่อสีเขียวที่ต่อตรงถึงท่อสีส้ม
เกิดความแตกต่างกันละ ระหว่าง Docker บน Linux และ Docker Toolbox เพื่อไม่เป็นการสับสน เราสามารถกำหนดให้สามารถเข้าถึงได้ด้วย localhost หรือ 127.0.0.1 ด้วยประตูมิติบานที่ 1
ประตูมิติบานที่ 1 Port Forward
ให้ทำการเปิด VirtualBox ขึ้นมา จะเห็นว่ามีเครื่อง ที่ชื่อว่า default รันอยู่ ให้คลิกขวา เลือก Settings… แล้วไปที่เมนู Network เลือก Adapter 1 คลิกที่ Advanced แล้วคลิกที่ปุ่ม Port Forwarding


ในหน้า Port Forwarding Rules ให้ระบุ Port ที่ต้องการเปิดประตูมิติบานที่ 1 โดยการเพิ่ม Rule ใหม่ ตั้งชื่อ Rule ได้ตามใจชอบ กำหนด Protocol เป็น TCP
แล้วลองระบุ Host Port เป็น 82
และ Guest Port เป็น 81
ตามในรูปดู เซฟให้เรียบร้อย ส่วน Host IP และ Guest IP ให้เว้นว่างไว้ เป็นการกำหนดว่า Host IP และ Guest IP เป็น IP อะไรก็ได้นั่นเอง

ลองเปิด Web Browser ดู ที่ http://localhost:82
หรือ http://127.0.0.1:82
ดู จะพบหน้า Landing page แล้ว…

เพื่อความเข้าใจมากขึ้น ขออธิบายสิ่งที่ได้ทำไปดังรูปด้านล่าง

ท่อสีแดงนั่นก็คือสิ่งที่เราไปกำหนด Port Forwarding ใน VirtualBox นั่นแหล่ะครับ
ในตัวอย่าง ที่กำหนด Port เป็นเลขที่ไม่เหมือนกัน เพื่อให้ได้ทดลอง และเข้าใจมากยิ่งขึ้น ในทางปฏิบัติ แนะนำให้กำหนด Port Forwarding ใน VirtualBox ให้เป็นเลขเดียวกัน ก็จะทำให้การใช้งานเสมือน Docker บน Linux แล้ว
ประตูมิติบานที่ 2 Share Folder
สำหรับประตูมิติบานที่ 2 นั้น เป็นเรื่องของการนำไฟล์เข้าไปใช้ยัง Container มาลองดูคำสั่งต่อไปนี้
1 |
$ docker run -d --name web2 -p 80:80 -v "$(pwd)"/web:/usr/share/nginx/html nginx:alpine |
คำสั่งด้านบน เพิ่มเติมจากคำสั่งก่อนหน้ามานิดนึง คือการ Mount volume (-v
) หรือการนำไฟล์จากเครื่องเรา เข้าไปให้ภายใน Container เห็น
โดยที่ root web path ของ NGINX ที่ /usr/share/nginx/html
เป็นการอ้างถึง path /web
ที่อยู่ใต้ path ปัจจุบัน "$(pwd)"
บนเครื่องเรา ซึ่งในตัวอย่างด้านบน จะวาง Folder web ไว้บน Desktop
และผมเปลี่ยน Port ที่ Map เข้าไปยัง Container เป็น port 80
แล้ว สำหรับใครที่ทำตาม อย่าลืมไปเปลี่ยน/เพิ่ม Rule สำหรับประตูมิติบานที่ 1 ให้มี Guest Port เป็น 80
ด้วยนะ
ใน path web บน Desktop ผมได้วางไฟล์ index.html ไว้ มีหน้าตาแบบนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Docker Toolbox : share folder</title> </head> <body> <div>Docker Toolbox share folder example by Ethan</div> <div><a href="http://www.artit-k.com">artit-k.com</a></div> </body> </html> |
ลองทดสอบ โดยการเปิด Web Browser ไปที่ http://localhost
หรือ http://127.0.0.1
ดู จะพบหน้า Landing page กลายเป็น Web page ของเราแล้ว

ประตูมิติบานที่ 2 อยู่ไหน!?
ไม่ต้องแปลกใจนะครับ ว่าทำไมเปิดได้ เพราะบน Windows นั้นโดย Default config จะมีการเปิดประตูมิติไว้ที่ c:\Users อยู่แล้ว (สำหรับ macOS จะเปิดที่ /Users ไว้) ลองเข้าไปดูใน VirtualBox แล้วคลิกขวาที่เครื่อง default เลือก Settings… แล้วไปที่เมนู Shared Folders ก็จะเห็นว่า มีการกำหนดไว้ให้แล้ว

ก่อนจะไปต่อ อยากให้ดูรูปด้านล่างนี้ก่อนครับ…

จากที่เราทำการ Mount volume ด้วยคำสั่ง -v "$(pwd)"/web:/usr/share/nginx/html
ไว้นั้น ถ้าดูจากรูปด้านบน คือการให้ Path ในกล่องสีฟ้า Mount เข้าไปเป็น Path ที่อยู่ในกล่องสีเขียว ถ้าสังเกตุฝั่ง Docker บน Linux จะเห็นว่า ไฟล์จริง ๆ ที่วางบนเครื่องเรา จะอยู่ในกล่องสีฟ้าอยู่แล้ว จึง Mount เข้าไปตรง ๆ ได้เลย
ส่วนฝั่งขวา ที่เราออกคำสั่งไปนั้น ก็คือการ Mount จากกล่องสีฟ้า ไปยังกล่องสีเขียว เช่นกัน แต่ไฟล์จริง ๆ อยู่บน OS ของเรา ก็คือกล่องสีแดง
Shared Folders ที่ถูกกำหนดไว้ใน VirtualBox นั้น คือการ Mount ให้กล่องสีแดง เข้าไปเป็นกล่องสีฟ้า นั่นเอง

จากรูปด้านบน
- ในกรอบสีแดง คือไฟล์ใน Path ที่อยู่บน OS ของเรา
- ในกรอบสีน้ำเงิน คือไฟล์ใน Path ที่อยู่บน Boot2Docker มาจากการ Shared Folders บน VirtualBox
- ในกรอบสีเขียว คือไฟล์ใน Path ที่อยู่ใน Container มาจากการ Mount volume ด้วยคำสั่ง
-v
Tip! ตรงเบอร์ 1 คือคำสั่งที่เราสามารถ ssh เข้าไปยัง Boot2Docker ได้ซึ่งต้องสั่งผ่านคำสั่ง docker-machine
โดยมีรูปแบบดังนี้
1 |
$ docker-machine ssh <machine-name> <command> |
ซึ่งในรูป ไม่ได้มีการสั่ง command ใด ๆ จึงเป็นการ ssh เข้าไปยัง Machine ที่ชื่อ default และเราสามารถที่จะไม่กำหนดชื่อ Machine ได้ด้วย ก็สามารถ ssh เข้าไปยัง Machine ได้เหมือนกัน คำสั่งจึงเหลือแค่…
1 |
$ docker-machine ssh |
กลับมาเข้าเรื่องของประตูมิติบานที่ 2 กันต่อ…
ในการทำงานจริง ๆ คงไม่ค่อยมีใครวางไฟล์ไว้ที่ Desktop ใช่มั๊ยล่ะครับ ยิ่งถ้าเป็น Windows เรามักจะมี Partition อื่น เพื่อแยกออกไปเก็บไฟล์งานกัน เช่น Drive D:
พอจะเดาออกแล้วใช่มั๊ยครับ นั่นล่ะครับ ถ้าไฟล์อยู่ที่ Drive D: จะพบปัญหาว่า เราไม่สามารถนำไฟล์ Mount เข้าไปถึง Container ได้ เพราะเรื่องของการ Shared Folders นั่นเอง
เพื่อป้อนกันความสับสน (เช่นเดียวกับเรื่อง Port ในประตูมิติบานที่ 1) ผมแนะนำให้ทำการกำหนด Shared Folders แบบนี้

คือการกำหนดให้ Shared Folders กำหนด Path c:\
ใน Windows ไปเป็น /c/
ใน Boot2Docker และ Path d:\
ไปเป็น /d/
ใน Boot2Docker
ซึ่งการกำหนดแบบนี้ เป็นการทำให้ทุกไฟล์บนเครื่องของเรา Mount ไปอยู่บน Boot2Docker ทั้งหมด และชื่อ Path ก็ตรงกันกับเมื่อเราสั่ง Mount volume เข้าสู่ Container ก็จะลดความสับสนไปได้มาก แต่ควรจะ Mount แบบ Read-only นะครับ เผื่อเราสั่งอะไรผิดพลาดไป จะได้ไม่มีผลกับไฟล์บนเครื่องของเรา
แต่หากต้องการใช้ภายใน Container เขียนไฟล์กลับออกมาได้ ก็ค่อยกำหนด Shared Folder เป็นกรณี ๆ ไป
ณ ตอนนี้ Docker Toolbox 17.05 + VirtualBox 5.1.20 หลังจากกำหนด Shared Folders แล้ว จำเป็นต้อง Restart Boot2Docker ครั้งนึง ถึงจะมีผลนะครับ ด้านล่างเป็นตัวอย่างคำสั่งสำหรับ Restart Boot2Docker
1 |
$ docker-machine restart <machine-name> |
ถ้าใครใน Version ที่ใหม่กว่า แล้วไม่ต้อง Restart Boot2Docker ช่วยแจ้งผมนิดนึง
ใน Docker Toolbox เวอร์ชั่นเก่า ๆ ซักประมาณปีที่แล้ว ต้อง ssh เข้าไป Boot2Docker แล้วพิมพ์คำสั่งเพื่อ Mount volume เองอีกทอดนึง
นี่ล่ะครับ ประตูมิติบานที่ 2 ที่ผมว่า ^_^
หวังว่าผู้อ่าน จะได้รู้จักประตูมิติบน Docker Toolbox มากขึ้น และได้ประโยชน์จากเทคนิคเล็ก ๆ น้อย ๆ สำหรับประตูมิติทั้ง 2 บานนะครับ
ตอนต่อไป สำหรับเรื่องของ Docker ผมจะมาแนะนำเทคนิคอื่น ๆ กันอีก โปรดติดตามกันนะคร๊าบบบบบบบบ
Permalink
ขอบคุณมากครับ อธิบายเข้าใจง่ายดีครับ
Permalink
ขอบคุณครับ มีประโยชน์มาก ตัว toolbox ที่ยังต่างจากตัวหลัก