🖼️ Container Image

ลองสร้าง Image ตัวแรกของเรากัน 😉

🤠 จาก บทความที่ 5 เราได้รู้ว่า 🐳Docker มีที่เก็บ 🖼️ Container Images ขนาดใหญ่อยู่ที่ 🌎 Docker Hub ดังนั้นในบทความนี้เราจะมาลองสร้าง 🖼️ Container Image ของเราเองกันดูบ้างดีกั่ว

แนะนำให้อ่าน บทความนี้เป็นส่วนหนึ่งของคอร์ส 🐳 Docker ที่จะสอนตั้งแต่เรื่องพื้นฐานยันระดับ master กันไปเลย ซึ่งเนื้อหาทั้งหมดจะทำให้เพื่อนๆเข้าใจและใช้งาน Docker โดยใช้ Kubernetes เป็น และสามารถสร้าง Cluster เพื่อนำไปใช้งานบน Cloud Providers ต่างๆได้ และทั้งหมดที่พูดมานั้นอ่านได้ฟรีเลย ดังนั้นหากสนใจก็สามารถกดเจ้าวาฬสีน้ำเงินเพื่อไปอ่านตั้งแต่เริ่มต้นได้ครัช 🤠

🚨 Prerequisites

ในบทความนี้ ดช.แมวน้ำ จะสร้างโปรเจคโดยใช้ .NET Core และ Visual Studio Code เป็นตัวอย่าง ดังนั้นถ้าเพื่อนๆคนไหนที่จะทำตามก็อย่าลืมตั้งตั้ง .NET Core 3.1 SDK เอาไว้ด้วยนะครับ หากใครไม่มีก็กดที่ลิงค์สีฟ้าๆไปดาวโหลดได้เลย ส่วนคนที่มีแล้วลองเปิด Command Prompt ขึ้นมาแล้วเช็คเวอร์ชั่นได้จากคำสั่งด้านล่างครับ

dotnet --version

3.1.403 (ขอให้มันขึ้นเป็น 3.1.xxx ก็ใช้ได้ละ xxx จะเป็นเลขอะไรก็ช่างมัน แต่ถ้าใครไม่ขึ้นแบบนี้ขอไปให้ติดตั้งโดยด่วนเบย)

🆕 Create .NET Core app

เมื่อติดตั้ง .NET Core 3.1 SDK เสร็จละ ถัดมาเราก็จะสร้าง Console Application ที่เป็นโปรเจคพื้นฐานเลยก็ว่าได้ ด้วยคำสั่งด้านล่างนี้

dotnet new console -o App -n Saladpuk

ใครอยากเปลี่ยนชื่อโปรเจคก็แก้คำว่า Saladpuk เป็นชื่ออื่นเอานะ แต่ถ้าแก้ก็อย่าลืมว่าทุกขั้นตอนด้านล่างก็จะต้องใช้เป็นชื่อใหม่ของเราด้วย (แนะนำว่าให้ทำตามไปก่อนอย่าพึ่งแก้ชื่อ)

เมื่อเสร็จเราก็จะได้โฟเดอร์ชื่อ App ที่มีไฟล์ต่างๆอยู่ข้างในตามรูปด้านล่างนี้ครับ

ให้เราเปิดโปรแกรม Visual Studio Code ขึ้นมา แล้วเลือกทำงานกับโฟเดอร์ App ของเรา โดยการคลิกที่เมนู File > Open Folder ... ตามรูปด้านล่าง

ถัดมาให้เราเลือกไฟล์ Program.cs ที่อยู่เมนูด้านซ้ายมือ แล้วเอาโค้ดด้านล่างไปใส่แทน (อย่าลืมกดเซฟด้วยนะ)

using System;
using System.Threading.Tasks;

namespace Saladpuk
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var counter = 0;
            while (true)
            {
                Console.WriteLine($"Counter: {++counter}");
                await Task.Delay(1000);
            }
        }
    }
}

เมื่อเราลอง Run โดยการกด CTRL + F5 (ในครั้งแรกมันจะถามให้เราเลือก .NET Core) แล้วเราก็จะเห็นโปรแกรมทำการนับเลขออกมาเรื่อยๆทุกๆ 1 วินาที ตามผลลัพท์ด้านล่าง

Counter: 1 Counter: 2 Counter: 3 ...

🛠️ Publish .NET Core app

ตอนนี้เราก็จะมีโปรเจคนับเลขง่ายๆที่พร้อมเอาไปสร้างเป็น 🖼️ Container Image กันละ ดังนั้นขั้นตอนถัดไปเราก็จะเอาโปรเจคตัวนี้ไปสร้างเป็น binary ไฟล์ โดยใช้คำสั่ง publish เพื่อให้ได้ไฟล์ที่เหมาะสมจะเอาไปใช้งานต่อนั่นเอง

เกร็ดความรู้ ปรกติเวลาที่เรา Run โปรแกรมเราก็จะได้ binary ไฟล์ที่อยู่ในโฟเดอร์ bin อยู่แล้วล่ะ แต่ไฟล์พวกนั้นมันยังมีข้อมูลหลายอย่างที่ไม่เหมาะสมในการนำไปใช้งานจริง เช่นเรื่อง performance ต่างๆ ดังนั้นเวลาที่เราต้องการจะเอาโปรเจคนี้ไปใช้งาน เราควรที่จะทำการ publish เป็น Release mode ก่อนเสมอนั่นเองครัช

ในโปรแกรม Visual Studio Code ให้เปิด Terminal ขึ้นมา โดยสามารถกดได้ที่ที่เมนูด้านบนสุด Terminal > New Terminal แล้วเขาจะเปิดหน้าต่างใหม่ขึ้นมา ให้เราใช้คำสั่ง publish ตามด้านล่างได้เลยครับ

dotnet publish -c Release

จากผลกรรมที่เราได้ทำลงไป ก็จะทำให้เราได้ binary ไฟล์ขึ้นมา ซึ่งมันจะอยู่ในโฟเดอร์ตามรูปด้านล่างเลย

เพียงเท่านี้ก็เป็นอันเสร็จสิ้นพิธีกรรมในการเตรียมโปรเจคของเราละ ดังนั้นถัดไปก็มาเตรียมในส่วนของฝั่งพี่วาฬบ้าง

🐳 Create the Dockerfile

ในการสร้าง 🖼️ Container Image เราจะต้องมีไฟล์ตัวหนึ่ง ที่เอาไว้บอกพี่วาฬว่าจะสร้าง Image นั้นๆขึ้นมาได้ยังไง ซึ่งเจ้าไฟล์ที่ว่าเราเรียกมันว่า 📃 Dockerfile ไฟล์นั่นเอง โดยความพิเศษของเจ้าตัวนี้คือ มันไม่มีนามสกุล และ ต้องอยู่บน Root โฟเดอร์ ดังนั้นใน Visual Studio Code เราก็จะกดปุ่มสร้างไฟล์ใหม่ขึ้นมาแล้วตั้งชื่อเป็น Dockerfile ตามรูปด้านล่าง

คราวนี้ให้เราเอาโค้ดด้านล่างไปวางไว้ในไฟล์ 📃 Dockerfile เลย (อย่าลืมกดเซฟด้วยนะ)

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
COPY bin/Release/netcoreapp3.1/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "Saladpuk.dll"]

เพียงเท่านี้เราก็จะได้ไฟล์ Dockerfile ที่พร้อมจะเอาไปสร้างเป็น 🖼️ Container Image กันละ

🤠 ก่อนที่เราจะไปต่อ ดช.แมวน้ำ อยากจะอธิบายโค้ดด้านบนต่ออีกนิสนุง เพื่อนๆจะได้เข้าใจกลไกการทำงานของมัน เวลาไปทำของตัวเองจะได้ไม่ งง นั่นเอง

🔎 Dockerfile

เมื่อไหร่ก็ตามที่เราสั่งให้พี่วาฬไปสร้าง 🖼️ Container Image ขึ้นมาซักตัว พี่วาฬจะถามหาไฟล์ 📃 Dockerfile เสมอ เพราะ พี่วาฬไม่รู้ว่าจะกำหนด Environments ต่างๆให้มีค่าเป็นอะไรบ้าง ดังนั้นเราเลยต้องใช้ Dockerfile เพื่อบอกพี่วาฬให้รู้ว่า Environments ต่างๆเป็นยังไงนั่นเอง

🤠 จากตรงนี้เราก็จะมาทำความเข้าใจโค้ด Dockerfile ที่อยู่ด้านบนแบบบรรทัดต่อบรรทัดกันดีกว่า

1️⃣ FROM

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1

คำสั่ง FROM เป็นการ บอกให้ Docker รู้ว่าเราจะใช้ Image ตัวอื่นด้วยนะ ซึ่งในตัวอย่างนี้เราใช้ asp.net core เวอร์ชั่น 3.1 ของบริษัท Microsoft ซึ่งดูได้จาก 🌎 Docker Hub ตามลิงค์นี้ ASP.NET Core 2.1/3.1 Runtime ดังนั้นเมื่อ Docker เห็นคำสั่งนี้ Environment ของเราก็จะมีหน้าตาประมาณนี้

2️⃣ COPY

COPY bin/Release/netcoreapp3.1/publish/ App/

คำสั่ง COPY เป็นการ สั่งให้ Docker คัดลอกไฟล์จากในเครื่องเราไปเก็บใน Image ที่กำลังจะสร้าง ซึ่งในตัวอย่างนี้เราจะคัดลอกทุกไฟล์ในโฟเดอร์ bin/Release/netcoreapp3.1/publish จากเครื่องเรา ไปวางไว้ใน โฟเดอร์ App ที่อยู่ใน Image ตามรูปด้านล่าง

ไฟล์ที่คัดลอกไปก็คือ binary ไฟล์ต่างๆที่เราทำไว้ในขั้นตอน 🛠️ Publish .NET Core app งุย

3️⃣ WORKDIR

WORKDIR /App

คำสั่ง WORKDIR เป็นการ บอกให้เจ้า Image รู้ว่าตัวมันเองจะต้องเริ่มทำงานที่โฟเดอร์ไหน ซึ่งในตัวอย่างนี้เราจะสั่งให้มันเริ่มทำงานที่โฟเดอร์ App นั่นเองตามรูปด้านล่าง

4️⃣ ENTRYPOINT

ENTRYPOINT ["dotnet", "Saladpuk.dll"]

คำสั่ง ENTRYPOINT เป็นการ สั่งว่าเมื่อ Container ถูกสร้างขึ้นมามันจะทำงานกับไฟล์ไหน ซึ่งในตัวอย่างนี้เราจะสั่งให้มันทำงานกับไฟล์ Saladpuk.dll โดยใช้คำสั่ง dotnet ตามรูปด้านล่างนั่นเอง

🤠 จากคำสั่งทั้งหมดที่เขียนไว้ใน Dockerfile จะทำให้เจ้าตัว Image ของเรามีไฟล์ทุกอย่างครบถ้วน + อยู่ในโฟเดอร์ที่พร้อมทำงาน และรู้ว่าเมื่อถูกสร้างขึ้นมามันจะต้องทำงานอะไรกับไฟล์ไหนเรียบร้อยเลย ดังนั้นสุดท้ายเราก็จะมาดูคำสั่งในการสร้าง 🖼️ Container Image กันต่อครัช

🐳 Create a container image

เมื่อของทุกอย่างของเราครบหมดละ ถัดไปเราก็จะใช้คำสั่งสุดท้ายเพื่อให้พี่วาฬของเราทำการสร้าง 🖼️ Container Image ออกมาด้วยคำสั่ง docker build ตามตัวอย่างด้านล่างนี้

docker build -t demo01 -f Dockerfile .

จากคำสั่งด้านบนเป็นการบอกให้พี่วาฬทำการสร้าง 🖼️ Container Image ขึ้นมา โดยกำหนดให้มีชื่อว่า demo01 และบอกให้พี่วาฬหาไฟล์ Dockerfile จากโฟเดอร์ . ซึ่งตัว จุด มีความหมายว่าให้หาจากโฟเดอร์ปัจจุบันที่ทำงานอยู่

หมายเหตุ หากใครทำไม่ผ่านให้ลองเช็คดูโฟเดอร์ที่กำลังเปิด Command Prompt ว่ามันมีไฟล์ Dockerfile อยู่หรือเปล่า? และไฟล์ Dockerfile เขียนถูกและเซฟหรือยังนะจ๊ะ

เมื่อมันทำงานเสร็จเราก็จะได้ 🖼️ Container Image ตัวแรกของเรามาละ ดังนั้นลองใช้คำสั่ง docker images เพื่อแสดงรายการ Container Images ทั้งหมดในเครื่องเราออกมาดูกัน

docker images

ซึ่งผลลัพท์ที่เราได้มาคือ มันมี 🖼️ Container Image 2 ตัวอยู่ในเครื่องตามรูปด้านล่าง ส่วนสาเหตุที่เป็นแบบนั้นก็เพราะว่า Image ของเราไปใช้งาน Image ของคนอื่นด้วยยังไงล่ะ (จำได้ป่ะเราใช้ของ Microsoft ที่ชื่อว่า mcr.microsoft.com/dotnet/core/aspnet งุย)

📦 Container

🆕 Create a container

ในเมื่อเรามี Image เรียบร้อยละ ถัดไปเราก็จะลองเอามันไปสร้างเป็น 📦 Container โดยใช้คำสั่ง docker create ตามด้วย Image ID หรือ Repository แบบคำสั่งด้านล่างกัน

docker create demo01

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

จากนั้นให้เราลองใช้คำสั่ง docker ps -a เพื่อเข้าไปดูสถานะของมันหน่อย ตามโค้ดด้านล่าง

docker ps -a

เราก็จะเห็นว่า ถ้ามันเริ่มทำงานมันจะใช้คำสั่ง dotnet Saladpuk.dll ตามที่เรากำหนดไว้ใน 📃 Dockerfile และสถานะของมันคือยัง Created ซึ่งหมายถึงถูกสร้างเฉยๆนะยังไม่ได้เริ่มทำงานใดๆทั้งสิ้น

✅ Start a container

ถ้าเราต้องการให้ 📦 Container เริ่มทำงาน ก็จะใช้คำสั่ง docker start ตามด้วย Container ID ตามตัวอย่างโค้ดด้านล่าง

docker start e85

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

🔁 Attach

เมื่อเราต้องการเข้าไปดูว่า 📦 Container ของเราตอนนี้มันมี input & output อะไรออกมาบ้าง เราก็สามารถใช้คำสั่ง docker attach แล้วตามด้วย Container ID ที่ต้องการเข้าไปดู แต่ในรอบนี้เราจะเพิ่ม option 1 ตัวเข้าไปคือ --sig-proxy=false เพื่อให้ Container ทำงานต่อได้เรื่อยๆแม้ว่าเราจะปิด Command Prompt ไปแล้วก็ตาม ดังนั้นก็ใช้คำสั่งด้านล่างเพื่อเข้าไปดูการทำงานของมันได้เลย

โดยปรกติถ้าเราใช้คำสั่ง docker attach มันจะกำหนดค่า --sig-proxy ให้เป็น true โดย default นั่นหมายความว่าเมื่อเราปิด Command Prompt ไปเมื่อไหร่ ตัว Container ของเราก็จะหยุดการทำงานลงทันที

docker attach --sig-proxy=false e85

เราก็จะเห็นว่ามันจะนับเลขไปเรื่อยๆ ซึ่งถ้าดูจนเบื่อละก็สามารถกด CTRL + C เพื่อออกมาจาก attach mode ได้ แต่ถ้าเมื่อไหร่อยากดูการทำงานมันต่อก็สามารถใช้คำสั่งด้านบนอีกครั้ง เราก็จะเห็นว่ามันทำงานไปเรื่อยๆโดยไม่ได้สนใจว่าเราเปิดดูมันหรือเปล่านั่นเอง

🐳 Docker Run

ถ้าเราต้องการที่จะสร้าง Container ขึ้นมาทำงานเพียงครั้งเดียวแล้วจบกันไป เราก็สามารถใช้คำสั่ง docker run แล้วตามด้วย Image ID หรือ Repository ได้ โดยเราจะเพิ่ม options เข้าไป 2 ตัวคือ -it ซึ่งจะทำให้ Command Promt ของเราเชื่อมต่อกับ input & output ที่อยู่ใน Container และ --rm เพื่อสั่งให้ลบ Container นี้ทิ้งทันทีที่ทำงานเสร็จ แบบคำสั่งด้านล่าง

docker run -it --rm demo01

Counter: 1 Counter: 2 Counter: 3 ... (ถ้าดูจนเบื่อละก็สามารถกด CTRL + C เพื่อออกได้)

🎯 Summary

จากทั้งหมดเราก็น่าจะสร้าง 🖼️ Container Image ด้วย .NET Core กันเป็นเรียบร้อยแล้ว และรู้ว่าไฟล์ 📃 Dockerfile มีหน้าที่กำหนดว่าตัว Environments ของ Container Image จะต้องประกอบไปด้วยอะไรบ้างกันละ

ถัดมาเราก็ได้รู้ว่าเราสามารถสร้างและสั่งให้ 📦 Container เริ่มทำงานได้ตามใจชอบ (สั่งให้มันหยุด docker stop อยู่ในบทความก่อนหน้านี้แล้ว) และสุดท้ายเราสามารถจัดการ Input & Output ได้ที่อยู่ใน Container ได้จาก Command Prompt ของเครื่องเราเลย ด้วยคำสั่ง docker attach นั่นเอง

แม้บทความนี้จะยาวหน่อย แต่อย่างน้อยเราก็ได้เข้าใจความรู้ขั้นพื้นฐานในการสร้าง 🖼️ Container Image ไปเรียบร้อยละ บทความถัดไปเราจะลองเอา 🖼️ Container Image ของเราไปฝากไว้ที่ 🌎 Docker Hub เพื่อแชร์ให้ทุกคนบนโลกได้ลองเล่นกันบ้างนะครัช

📢pageDocker Push

อ่านแล้วชอบป๋มก็ขอฝากแชร์ หรือกดติดตามเพื่อจะได้ไม่พลาดบทความอื่นๆจาก ดช.แมวน้ำ ได้จากลิงค์นี้เบยครัช Saladpuk Fanclub 😍

Last updated