Jaynarol Blog

Docker : ติดตั้งและเริ่มใช้งาน (อย่างเข้าใจ)

         จากบทความที่แล้ว Docker : ฉบับปูพื้น ผมคิดว่าน่าจะช่วยให้ผู้อ่านเข้าใจภาพทางทฤษฎีและพื้นฐานต่างๆเกี่ยวกับ Docker ขึ้นมาบ้างแล้ว แต่สำหรับในทางปฎิบัตินั้น การจะพูดได้อย่างเต็มปากว่า เข้าใจ นั่นหมายถึงว่าต้องเคยลองใช้งานจริงๆเท่านั้น เพราะมันคือประสบการณ์ที่ต้องผ่านการลองผิดลองถูก ผ่านการเจอปัญหา ผ่านการงมและแก้ไข จนเจอแนวทางของตัวเอง ซึ่งประตูแรกของภาคปฏิบัติก็ไม่พ้นเรื่องเบสิคๆอย่าง การติดตั้งและฮัลโลเวิลด์ และนั่นคือจุดประสงค์ของบทความนี้ครับผม

 

เข้าใจการทำงาน

         ณ ตอนนี้ Docker เป็น Engine ที่ทำงานบน OS Linux เท่านั้น แต่ไม่ต้องตกใจครับ เราสามารถติดตั้ง Docker ลงบน OS อื่นๆเพื่อใช้งาน Docker ได้เช่นกัน แล้วทำไมผมต้องย้ำว่า Docker ทำงานบน OS Linux เท่านั้น สาเหตุก็เพราะว่ากระบวนการทำงานมันแตกต่างกัน ซึ่งเราควรจะเข้าใจพื้นฐานตรงนี้ก่อนครับ เพราะเมื่อลงลึกไปแล้วจะได้ไม่งงกับการทำงานของมัน

 

Linux Architecture Diagram

         ภาพทางด้านซ้ายเป็นสภาพแวดล้อมของ Docker ขณะที่เราใช้งานมันบน OS Linux ครับ ไม่ว่าจะเป็นการเรียกใช้งานผ่าน Command Line โดยตรงหรือผ่าน SSH ก็ตาม

Docker Host หมายถึง OS ที่ติดตั้ง Docker พูดง่ายๆก็คือ OS หลักของเครื่องที่เป็น Linux นั่นเอง

Docker client หมายถึง ตัวที่รับคำสั่งจาก Command Line ของเราเพื่อสั่งให้ Docker deamon ทำงานอีกทอดนึง

Docker deamon หมายถึง ตัวที่ควบคุม Container ทั้งหมด ซึ่งรับคำสั่งจาก Docker client นั่นเอง โดยปกติเราจะไม่ค่อยลงมายุ่งในระดับนี้โดยตรงนอกจากต้องการอะไรที่มัน Hardcore จริงๆ

 

 

 

Windows Architecture Diagram

         ภาพที่สองนี้คือสภาพแวดล้อมที่ Docker ทำงานบน OS อื่นๆที่ไม่ใช่ Linux เราจะสังเกตได้ว่าในท้ายที่สุดเราก็ต้องจำลอง Linux ขึ้นมาเพื่อรัน Docker อยู่ดี แต่ขอบอกว่า “It’s not a bug, it’s a feature” 555+ เพราะนี่คือหลักการที่ทำให้ Docker คง Environment ของ Container ไว้เหมือนเดิมได้ไม่ว่าเราจะสั่งการมันจาก OS ไหน และเป็นเหตุผลที่ว่าทำไม Docker images ถึงมีแต่ Application บน Linux เท่านั้น

กลับมาที่ภาพ เราจะเห็นว่าการทำงาน Docker บน OS อื่นๆคอนเซปไม่ต่างไปจากเดิมเลย สิ่งที่แตกต่างมีเพียงจุดเดียวคือ Docker client ที่เปลี่ยนไปตาม OS เช่นเมื่อมันอยู่บน Windows ก็จะเป็นไฟล์ Docker.exe เป็นต้นครับ การทำงานที่เหลือก็คือ Docker client รับคำสั่งจาก Command Line ของเราและส่งต่อไปยัง Docker deamon เพื่อให้ควบคุม Container ต่อไป ภาพนี้ยังให้เราเห็นถึงวัตถุประสงค์และเหตุผลที่ Docker deamon ต้องมากั้นระหว่าง Docker client กับ Container ด้วย นั่นก็เพื่อแปลง API ที่ได้รับจาก OS ที่หลากหลายไปเป็น Command บน Linux นั่นเอง

 

 

การติดตั้งฉบับวิถีชาวโลก

         เกริ่นมายาวมากเพิ่งจะเข้าเรื่องการติดตั้ง 555+ ในการติดตั้ง Docker ตามวิถีชาวโลกนั้น เป็นอะไรที่ง่ายมาก ง่ายจนอาจทำให้เราไม่เข้าใจการทำงานของมัน ผลคือแอบไปนั่งงงอีก 2-3 ตลบว่าทำไมมันเกิดปัญหาแบบนั้นแบบนี้ แต่ ณ จุดนี้เราเข้าใจการทำงานของมันแล้ว ฉะนั้นเพื่อไม่เป็นการเสียเวลา เราสามารถ ดาวน์โหลด Docker จากเว็บหลักและติดตั้งตามขั้นตอนได้เลย ไม่มีอะไรซับซ้อนครับ (OS X, Windows) หรือหากไม่เก่งอังกฤษก็มีบทความในไทยที่เขียนวิธีติดตั้งไว้แล้วมากมายเช่น http://www.siamhtml.com/getting-started-with-docker/ (ผมไม่อยากทำงานซ้ำซ้อนและต้นทางเขาอธิบายไว้ดีมากอยู่แล้วเลยขอข้ามจุดนี้ไปนะครับ)

         การทำงาน: หลังจากติดตั้งเสร็จเราจะได้ Docker Toolbox terminal พร้อมทั้ง Kitematic อยู่บน Desktop (และมี VirtualBox + Git แถมให้ด้วยสำหรับคนที่ยังไม่เคยติดตั้ง) เมื่อเราเปิด “Docker Toolbox terminal” ขึ้นมามันจะไปเรียก Bash Script ตัวนึงเพื่อสั่งให้ VirtualBox เริ่มจำลอง Linux OS ที่ชื่อว่า boot2docker ครับ (boot2docker  เป็น OS Linux ที่เล็กมากเหมาะสำหรับไว้ใช้งาน Docker ในเครื่อง Dev โดยเฉพาะ) เมื่อเรารอสักพักจนมันติดตั้งอะไรเสร็จก็จะขึ้นรูปปลาวาฬ (ชื่อของมันคือ MobyDock) นั่นหมายถึง Docker ในเครื่องเราพร้อมใช้งานแล้วครับ

 

การติดตั้งฉบับนอกตำรา

         จริงๆแล้วหากใครอยากติดตั้งฉบับนอกตำราซึ่งหมายถึงมีแนวทางเป็นของตัวเองก็ทำได้เช่นกันครับ เพราะเราเข้าใจการทำงานของมันแล้ว อย่างที่ผมใช้อยู่ในเครื่อง Dev คือจำลอง Xubuntu ขึ้นมาเองใน VirtualBox และเรียกใช้งาน Docker ผ่าน Xubuntu โดยตรงใน Seamless Mode ครับ

 

จากภาพด้านบนจะเห็นว่า Desktop ผมเป็น Windows แต่ Terminal และ File Manage เป็นของ Xubuntu นี่คือคุณสมบัติของ Seamless Mode ใน VirtualBox ครับ เสมือนการ Merge 2 OS เข้าด้วยกันเลยทีเดียว ผมสามารถเปิด Xubuntu Terminal แล้วสลับหน้าต่างไปมากับ Application อื่นๆของ Windows ได้เสมือนมันอยู่ใน OS เดียวกันเลยครับ

เนื่องจากผมเติบโตมาในยุค GUI ดังนั้นผมจะอุ่นใจมากหากอะไรๆมันจับต้องได้ครับ 555+ ซึ่งการติดตั้งแบบนี้เราสามารถทำทุกอย่างผ่าน GUI ของ Linux ได้เลยไม่ว่าจะอ่าน แก้ไข ลบไฟล์ ดาวน์โหลด คอนฟิก หรือแม้กระทั้งเปิดบราวเซอร์ในเครื่องโดยตรงเพื่อมาทดสอบเว็บ เป็นต้นครับ ชีวิตสะดวกขึ้นเยอะมาก และอีกอย่างคือผมเป็นคนชอบจูนอะไรเองหมด ซึ่งเป็นนิสัยที่เสียมาก เหมือนซื้อของเล่นมาแล้วต้องรื้อเพื่อดูการทำงานของมัน การที่ผมติดตั้งฉบับนอกตำราทำให้ผมเข้าใจ Docker อย่างลึกซึ้งครับ (แต่เสียเวลาในการทำความเข้าใจมากเช่นกัน)

 

จุดประสงค์ของหัวข้อนี้แค่อยากให้เห็นภาพและแนวทางการติดตั้งนะครับ ว่าเป็นไปได้หลากหลายและไม่ควรยึดติด เราควรค้นพบทางที่ดีที่สุดของเราเองเพื่อความสุขในการทำงานครับ

 

ลองใช้งาน Docker กันดีกว่า

 

         เพื่อเป็นการเริ่มต้นแบบง่ายๆผมจะพาเริ่มใช้งาน Docker แบบเบสิค เป้าหมายคือ เปิดเว็บด้วย IP ของ Linux  (ที่อยู่ใน VirtualBox ) แล้วแสดงผลได้ตามภาพครับ โดยหัวข้อนี้จะเน้นความเข้าใจในเชิงภาพรวมก่อนนะครับจะได้ไม่ง่วง 555+ ส่วนเรื่องเชิงลึกเอาไว้บทความต่อๆไปครับ

 

1. เตรียมความพร้อม

         เปิด “Docker Toolbox terminal” ขึ้นมาเราจะพบกับเจ้า MobyDock และรายละเอียดต่างๆได้แก่ ชื่อ Machine default และ IP 192.168.99.100 โดย IP ที่แสดงตอนนี้ให้เราทดเก็บไว้ในใจเป็น #1 ก่อนนะครับ (แต่ละคนอาจได้ไม่เหมือนกัน) เพราะจะได้เอาไปใช้ในขั้นตอนหลังๆ

 

2. เตรียมไฟล์เว็บไซต์

ก่อนอื่นเราจะสร้างไฟล์เว็บไซต์ของเราไว้ที่ ~/web โดยจะใช้วิธี pull ไฟล์ลงมาจาก git เลยนะครับ จะได้ไม่เสียเวลา

 

 

หลังจากพิมพ์คำสั่งไปแล้ว ให้เราลองพิมพ์คำสั่ง ls จะพบว่าในโฟลเดอร์ ~/web ของเรามีไฟล์ index.html และ mobydock.png เข้ามาแล้วครับ เสร็จขั้นตอนที่ 2

 

3. ดาวน์โหลด Docker image

ในขั้นตอนนี้เราจะดาวน์โหลด web server และทำความรู้จักกับ Docker image ครับ ผมเลือกใช้ Docker image ที่ชื่อว่า Nginx ซึ่งมันก็คือ Application Nginx ที่ถูกปรับแต่ง จูน ยำๆ จนมาอยู่ในรูปแบบ Docker image นั่นเอง ใน Docker เราสามารถโหลดมันมาเก็บไว้ในเครื่องด้วยคำสั่ง

 

หลังจากเรารันคำสั่ง ผลคือ Docker จะไปค้นหา Docker image ที่ชื่อว่า nginx ที่ Docker Hub และโหลดลงมาให้เราครับ เราสามารถเลือกเวอร์ชั่นที่ต้องการด้วยการกำกับ tag ลงไปกับชื่อ เช่น nginx:1.9 หมายถึง nginx เวอร์ชั่น 1.9 และหากเราไม่กำหนด tag หรือ กำหนดว่า nginx:latest นั่นหมายถึงให้เอาเวอร์ชั่นล่าสุดครับ

 

4. รัน Container

ในขั้นตอนนี้เราจะติดตั้ง web server เพื่อให้มันเริ่มทำงานและทำความรู้จักกับ Docker container ครับ

 

หลังจากเรารันคำสั่ง ผลคือ Docker จะสร้างสภาพแวดล้อมเสมือนการจำลอง OS Linux ขึ้นมาใหม่ สำหรับรัน Application นี้โดยเฉพาะ เราเรียกมันว่า Container ซึ่ง Container จะอยู่ในเครื่อง Linux ตามที่ผมได้อธิบายไปเมื่อต้นบทความครับ จากนั้น Docker ก็จะติดตั้งไฟล์และทำงานตามคำสั่งที่คนสร้าง Docker image ได้กำหนดไว้ครับ โดยเพื่อความง่ายในการเข้าใจผมจะแยก Command ออกเป็นชุดๆและอธิบายดังนี้

 

  • docker run เป็นคำสั่งที่สั่งให้ docker สร้าง Container
  • --name hellomobydock เป็นการกำหนดให้ Container นี้ชื่อว่า hellomobydock การตั้งชื่อเป็นทางเลือกจะตั้งหรือไม่ก็ได้ครับ ถ้ามีชื่อเราก็อ้างอิงได้ง่ายขึ้นแต่ถ้าไม่มีก็ใช้ CONTAINER ID แทนได้
  • -v ~/web:/usr/share/nginx/html:ro เป็นการสร้างประตูมิติ (Volume) ให้กับ Container (ข้อมูลจะถูกแบ่งด้วย colon: ) โดยด้านซ้ายคือ path ในเครื่องของเรา และด้านขวาคือ path ใน Container ครับ ตัวอย่างเช่น Container ของ nginx จะอ่านไฟล์เว็บที่ /usr/share/nginx/html (ซึ่งโฟลเดอร์นี้อยู่ใน Container อีกชั้นนึง) แต่ไฟล์เว็บของเราอยู่ข้างนอก Container เราจึงต้องผูก ~/web เข้ากับ /usr/share/nginx/html ครับ จากนี้เมื่อ nginx อ่าน/เขียนไฟล์ที่ /usr/share/nginx/html ก็จะเป็นการทำงานที่ ~/web แทนครับ เหมือนประตูมิติ ส่วนตรง :ro เป็น optional ใช้ระบุว่าให้ อ่านเท่านั้น (read only)
  • -p 80:80 เป็นการผูก Port ที่เชื่อมกันระหว่าง Linux และ Container ด้านซ้ายคือ port ใน Linux และ ด้านขวาคือ port ใน Container เนื่องจากใน Container แต่ละตัวจะเหมือน OS ที่มีสภาพแวดล้อมแยกออกมาต่างหากเพราะฉะนั้นเขาจะมี Port เป็นของตัวเอง การที่เราผูก Port  80:80 นั่นหมายถึงถ้าใช้งาน port 80 บน Linux เมื่อไหร่ให้ทะลุไปทำงานยัง Container นี้ที่ port 80 โดยอัตโนมัติ (port 80 บน Container nginx คือ web server)
  • -d เป็นการบอกให้ Container ทำงานในเบื่องหลัง ถ้าไม่มีคำสั่งนี้ เราจะเห็นการทำงานของ Container ผ่าน Console ทันที ซึ่งเมื่อปิด Console จึงหมายถึงการหยุด Container เช่นกันครับ การสั่งให้มันทำงานเบื่องหลังทำให้ไม่ส่งผลกระทบเมื่อเราปิด Console ลงไป
  • nginx:1.9 เป็นการบอกชื่อ image และ tag ที่ต้องการสร้างเป็น Container

 

เราสามารถตรวจสอบ Container ทั้งหมดที่กำลังทำงานอยู่ด้วยคำสั่ง docker ps ครับ จากภาพจะเห็นว่า มี Container 1 ตัวทำงานอยู่ ซึ่งก็คือ hellomobydock ที่เราสั่งรันไปเมื่อสักครู่นั่นเองครับ

 

แถมอีกนิดกับคำสั่งของ Container ที่ใช้บ่อยๆ

  • docker ps ดู Container ทั้งหมดเฉพาะที่กำลังทำงานอยู่ เอาไว้ใช้ดู CONTAINER_ID ได้ด้วยครับ
  • docker ps -a ดู Container ทั้งหมดรวมถึงตัวที่ stop pause หรือทำงานเสร็จแล้ว
  • docker stop CONTAINER_ID หยุดการทำงาน Container
  • docker start CONTAINER_ID เริ่มการทำงาน Container
  • docker rm CONTAINER_ID ลบ Container  (ต้อง stop หรือ kill ก่อน)
  • docker inspect CONTAINER_ID ดูข้อมูล Container อย่างละเอียด
  • docker logs CONTAINER_ID ดูข้อมูลการทำงานของ Container
  • docker exec -it CONTAINER_ID bash เข้าไปที่เครื่อง Container (เหมือน SSH เข้าไป)

 

ขอย้ำตรงนี้อีกครั้งนะครับ เราจะไม่สามารถเข้าใจภาคปฎิบัติได้เลยหากไม่ได้ลงมือทำ ดังนั้น ใครที่งงตรงไหนขอให้ลองเล่นดูแล้วจะเข้าใจเองครับ 🙂

 

5. แสดงผล

 

docker80

 

         มาถึงขั้นตอนนี้ให้เอา #1 ที่ทดไว้ในตั้งแต่ขั้นตอนที่ 1 ออกมาใช้ครับ อย่างของผมจะเป็น 192.168.99.100 ก็ให้เอา IP นี้ไปเปิดบน Browser จะพบว่าสามารถเข้าเว็บได้แล้ว สาเหตุที่เราเปิดเว็บได้เพราะว่า 192.168.99.100 คือ IP เครื่อง Linux ของเรา เมื่อเราเรียกผ่าน http จะเป็นการเรียกใช้งาน port 80 โดยอัตโนมัติ จากนั้นเมื่อ Linux ได้รับข้อมูลว่ามีการเรียกใช้งาน port 80 เจ้า Docker ก็จะไปตรวจสอบว่า port นี้ได้ผูกกับ Container ไหนไว้หรือไม่ ซึ่งก็จะพบ Container hellomobydock ของเราที่ผูก port 80 ไว้จึงส่งต่อข้อมูลเข้าไปยัง port 80 ของ Container ตัวนั้น ส่งผลให้ nginx ที่รออยู่ทำงาน และแสดงผลออกมาเป็น html นั้นเอง

 

6. ทำความสะอาด

         หลังจากเราเล่นจนพอใจแล้วขั้นตอนสุดท้ายคือการทำความสะอาดให้เสมือนไม่มีอะไรเกิดขึ้น ซึ่งในทางเทคนิคเรียกว่าการย้อนกระบวนการ จุดนี้ก็สำคัญมากอาจช่วยให้เราเข้าใจมันมากขึ้นได้ครับ

 

ขั้นตอนแรกเราจะสั่งให้ Container หยุดทำงานก่อนด้วยคำสั่ง

 

ถึงขั้นตอนนี้เมื่อเราใช้คำสั่ง docker ps จะไม่เห็น Container ทำงานอยู่แล้ว และเมื่อเปิดเว็บก็จะเข้าไม่ได้แล้วด้วยเพราะมันหยุดทำงานแล้วนั่นเอง แต่มันยังไม่หายไปไหนครับถ้าเราใช้คำสั่ง docker ps -a จะพบว่ามันยังมีชีวิตอยู่ (แค่ไม่ได้กำลังทำงาน) ดังนั้น ณ จุดนี้เราสามารถสั่งให้มันกลับมาทำงานอีกครั้งได้ด้วยคำสั่ง docker start hellomobydock ครับ

เมื่อเราเปิด-ปิดและเล่นมันจนพอใจ ถ้าเราอยากจะลบมันจริงๆแบบถาวร เราสามารถใช้คำสั่ง (ต้อง stop container ก่อนเท่านั้นถึงจะลบได้)

 

ถึงตอนนี้หากเราลองใช้คำสั่ง docker ps -a จะไม่พบมันอีกแล้ว

 

ตอนนี้ Container เราสะอาดแล้วครับ ต่อไปเราจะทำความสะอาด Docker image บ้าง ก่อนอื่นให้เราใช้คำสั่ง docker images เพื่อดูว่าในเครื่องเราตอนนี้มี images อะไรอยู่แล้วบ้าง และเพื่อเอา IMAGE ID สำหรับมาใช้ในคำสั่งลบ นั่นเอง

 

จากภาพจะเห็นว่า IMAGE ID ของ nginx:1.9 ในเครื่องผมคือ eb4a127a1188 ดังนั้นผมสามารถลบมันได้ด้วยคำสั่งนี้

มี trick เล็กน้อยคือเราสามารถใช้ IMAGE ID เพียง 2 ตัวหรือ 4 ตัวก็ได้ไม่จำเป็นต้องพิมพ์หมด แต่ระวังมันจะไปซ้ำกับตัวอื่นครับ อีกทางคือเราสามารถใช้ชื่อ repo:tag เพื่อสั่งลบก็ได้เช่นกัน เช่น docker rmi nginx:1.9 ครับ

 

มาถึงตอนนี้เครื่อง Linux ที่อยู่ใน VM เราสะอาดเหมือนใหม่แล้วครับ แต่ในเครื่องหลักของเรายังไม่เสร็จเพราะยังมีไฟล์ค้างอยู่ที่ ~/web เราสามารถใช้คำสั่ง rm -rf ~/web เพื่อสั่งลบได้เลย หรือใครอยากชัวก็ใช้คำสั่ง cd ~/web ครับ แล้วสังเกตตรง title bar ของ Console นั่นคือที่อยู่ของไฟล์ที่มันอยู่ในเครื่องเรานั่นเอง

 

 

อย่างของผม /c/Users/Jaynarol/web ก็คือ C:/Users/Jaynarol/web ครับ สามารถเข้าไปลบล้างบางมันได้ตามสบาย

 

เสร็จสิ้นขั้นตอนทั้งหมดครับ ตอนนี้เครื่องเราสะอาดเหมือนลง Docker ใหม่ๆ เราสามารถวนกลับไปทำขั้นตอนที่ 1 ใหม่ได้เรื่อยๆ จนกว่าจะพอใจครับ

 

ปิดท้าย

ตอนแรกตั้งใจเขียนบทความนี้สั้นๆ กระชับๆ แต่เขียนไปเขียนมากลับเพลิน รู้สึกว่าตรงนี้ก็อยากบอก ตรงนั้นก็อยากเพิ่ม จนกระทั่งบานปลายออกมาเยอะขนาดนี้ได้ 555+ ถึงบรรทัดนี้ดูนาฬิกาเพิ่งรู้ตัวว่าใช้เวลาซัดไป 3 ชั่วโมงข้าวเย็นยังไม่ได้ทานเลย หิวมาก -0-

บทความนี้ผมหวังว่าคงช่วยให้ผู้อ่านได้สาระและแนวทางต่างๆไปไม่มากก็น้อยนะครับ ใจจริงอยากให้ลองหาเวลาเล่นและทำความเข้าใจมันดูครับ เผื่อเจอเทคนิคอะไรดีๆมาบอกผมบ้าง 😀

หากตรงไหนผิดพลาด ตกหล่น รบกวนแนะนำกันได้เลยครับ ผมก็ไม่ได้เก่งอะไรเลย แค่รู้ก่อนเฉยๆครับ

เจอกันใหม่บทความหน้า เนื้อหาคงจะลงลึกมากกว่านี้อีกนิด

ขอบคุณครับ