> For the complete documentation index, see [llms.txt](https://www.saladpuk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.saladpuk.com/basic/docker-1/exercise01.md).

# Docker Exercise 01

🤠 จาก [**บทความที่ 2**](https://www.saladpuk.com/basic/docker-1/containers) เราน่าคันมืออย่าลองของจริงละ ดังนั้นบทความนี้เราจะลองใช้เจ้าวาฬน้ำเงิน 🐳 ว่ามันดีสมกับที่ 2 บทความโม้มาจิงป่ะ ?

{% hint style="success" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของคอร์ส [🐳 **Docker**](https://www.saladpuk.com/basic/docker-1) ที่จะสอนตั้งแต่เรื่องพื้นฐานยันระดับ master กันไปเลย ซึ่งเนื้อหาทั้งหมดจะทำให้เพื่อนๆเข้าใจและใช้งาน **Docker** โดยใช้ **Kubernetes** เป็น และสามารถสร้าง **Cluster** เพื่อนำไปใช้งานบน **Cloud Providers** ต่างๆได้ และทั้งหมดที่พูดมานั้นอ่านได้ฟรีเลย ดังนั้นหากสนใจก็สามารถกดเจ้าวาฬสีน้ำเงินเพื่อไปอ่านตั้งแต่เริ่มต้นได้ครัช 🤠
{% endhint %}

## 🚨 Installation

ก่อนที่เราจะเล่น Docker ได้นั้นเราก็ต้องติดตั้งโปรแกรมเขาก่อน โดยดาวโหลดได้จากลิงค์นี้ [**Docker.com**](https://www.docker.com/get-started) โดยเครื่องเราใช้ Windows อะไรก็เลือกติดตั้งให้ถูกตัว ส่วนขั้นตอนติดตั้งไม่มีไรมาก Next เรื่อยๆได้เบย

![](/files/-MKQYNLu1eFBBc5QPtXo)

ถ้าติดตั้งทุกอย่าง + **รีสตาร์ทเครื่อง** เสร็จหมดละ ที่มุมหน้าจอเราก็จะเห็น Icon ปลาวาฬโผล่ขึ้นมา ซึ่งเราต้องให้เวลาเขาเตรียมตัวซักครู่ จนกว่า Icon จะหยุดนิ่งๆเหมือนในรูปด้านล่าง ก็จะเป็นอันพร้อมใช้งาน

![](/files/-MKQZRXcgEToS7xMc6Ca)

คราวนี้เราลองมาเช็คให้มั่นใจรอบสุดท้ายว่าเครื่องเราพร้อมใช้งานหรือเปล่า โดยการเปิด **`Command Prompt`** / **`PowerShell`** หรือ **`Terminal`**&#xE02;ึ้นมา (เลือกเปิดซักตัวนะไม่ต้องเปิดหมด 🤣) แล้วในหน้าจอดำๆให้เราลองใช้คำสั่งเช็คเวอร์ชั่นของ Docker ที่เราพึ่งลงไป ด้วยคำสั่งด้านล่าง

{% hint style="info" %}
**Command Prompt**\
คนที่ใช้ Microsoft Windows สามารถกดปุ่ม Windows ด้านล่างซ้าย แล้วพิมพ์คำว่า cmd แล้วกดปุ่ม Enter ได้เลย แล้วหน้าจอ Command Prompt ก็จะโผล่ขึ้นมาครัช
{% endhint %}

```bash
docker --version
```

> **ผลลัพท์**\
> Docker version 19.03.13, build 4484c46d9d

ถ้ามันขึ้นมาประมาณนี้ก็ถือว่าพร้อมใช้งานละ (เลขเวอร์ชั่นอาจไม่เหมือนของผมก็ไม่เป็นไรนะ) แต่ถ้าใครไม่ขึ้นแบบนี้ก็แสดงว่าการติดตั้งอาจจะมีปัญหาอะไรซักอย่างลองกลับไปตรวจดู

{% hint style="warning" %}
**Emulators**\
หากใครที่ติดตั้งโปรแกรม Emulators ที่มันใช้พวก Hyper-V อาจจะมีปัญหากับ Docker ได้ เช่นโปรแกรมจำลอง Android อย่าง BlueStacks ไรงี้ อาจจะต้องลบของพวกนั้นทิ้งก่อน
{% endhint %}

## 🐳 Docker Pull

จากการติดตั้งด้านบนจะทำให้เครื่องคอมของเรามีปลาวาฬทำงานเป็นเบื้องหลังเรียบร้อยตามรูปด้านล่างละ

![](/files/-MKQhX0VHyfCtD7UR6oY)

คราวนี้เราก็จะลองเอา [**`🖼️ Container Image`**](https://www.saladpuk.com/basic/docker-1/containers#container-image) ตัวฝึกหัดมาลองเล่นดู โดยให้เราเปิด Command Prompt หรือ Terminal ขึ้นมา (ต่อไปจะบอกว่า Command Prompt อย่างเดียวนะ) แล้วเรียกใช้คำสั่งด้านล่าง

```bash
docker pull docker/getting-started
```

เราจะเห็นว่า Docker จะไปดาวโหลดไฟล์บางอย่างมานั่นเพราะ **คำสั่งด้านบนเป็นการสั่งให้ Docker ไปเอา Container Image มาเตรียมไว้ในเครื่อง** ซึ่งหากมันหา Container Image นั้นๆไม่เจอ มันก็จะไปดาวโหลดมาจากส่วนกลางที่ชื่อว่า **`🗃️ Docker Registry`** นั่นเอง โดยกระบวนการทั้งหมดนั่นก็จะออกมาเป็นตามรูปด้านล่าง

![](/files/-MKQtil4ikKLoirNSy0Y)

{% hint style="success" %}
[**docker pull**](https://docs.docker.com/engine/reference/commandline/pull/) - เป็นการสั่งให้ docker ไปเตรียมเอา Container Image มาเตรียมไว้ในเครื่อง ซึ่งถ้ามันไม่เคยมีอยู่ในเครื่องล่ะก็ เจ้าวาฬก็จะไปดาวโหลดมาให้เรา แต่ถ้าเคยมีอยู่แล้วมันก็จะไม่โหลดใหม่ ไม่เชื่อลองใช้คำสั่งด้านบนซ้ำอีกรอบจิ
{% endhint %}

{% hint style="info" %}
รายละเอียดของ **`🗃️ Docker Registry`** เดี๋ยวเราค่อยกลับมาทำความเข้าใจมันอีกทีนะจ๊ะ 😋
{% endhint %}

## 🐳 Docker Images

หลังจากที่เราได้ Container Image ที่ชื่อว่า **`docker/getting-started`** มาอยู่ในเครื่องละ คราวนี้เราลองใช้คำสั่งเรียกดู Container Images ทั้งหมดที่มีอยู่ในเครื่องดูหน่อยดิ๊ ด้วยคำสั่งด้านล่าง

```
docker images
```

รายการ Container Images ทั้งหมดก็จะโชว์ออกมาพร้อมกับรายละเอียดต่างๆ ตามรูปด้านล่าง (หากใครเคยแอบเล่น docker มาก่อนแล้วรายการที่โชว์มันเยอะกว่าในรูปก็ไม่ต้องตกใจไปเด้อ)

![](/files/-MKRKlPUOm_5_ePoqu99)

เดี๋ยวค่อยกลับมาลงรายละเอียดของมันต่ออีกที ตอนนี้แค่จำง่ายๆว่า **Container Image** ที่เราดาวโหลดมาจากคำสั่ง **`docker pull`** นั้นมันมีหน้าตาราวๆนี้ละกัน

![](/files/-MKRQYNaIyjoAAQvIQCl)

## 🐳 Docker Run

ภายใน Docker Image ตัวนั้นจะมี **เว็บไซต์** ที่เขียนด้วยภาษา **python** และทำงานอยู่บน **nginx** อยู่ข้างใน ซึ่งเราจะลองเอามันมาทำงานในเครื่องเราดูดิ๊ ด้วยคำสั่งด้านล่าง

```
docker run -d -p 80:80 docker/getting-started
```

เมื่อใช้คำสั่งด้านบนไปเราจะได้ข้อความมั่วๆมา 1 บรรทัดและก็ไม่เกิดอะไรขึ้นชิมิ? คราวนี้เราลองเปิด **Web Browser** แล้วเข้าไปที่ [http://localhost](http://localhost/) เราก็จะเจอกับเว็บหน้าตาประมาณนี้เบย

![](/files/-MKRUL2RMc7BU_4wFRq_)

> หน้าตาเว็บอาจจะไม่เหมือนกันก็ไม่เป็นไร เพราะตอนที่เพื่อนๆลองทำ เขาอาจจะอัพเดทหน้าตาไปแล้วก็ได้

🤠 **ตัวเว็บที่เราเห็นมันคือเว็บที่อยู่ใน Container Image** ที่ถูกเขียนด้วยภาษา python และทำงานอยู่บน nginx ตามที่บอกไป **ซึ่งเราจะเห็นว่าเว็บทำงานได้ปรกติ แม้คอมเราจะไม่ได้ลง nginx ก็ตาม** (ใครลง nginx ลองลบออกดูดิ) เพราะเจ้า 🐳 Docker มันไปสร้าง Environment ให้เราเรียบร้อยแล้วยังไงล่ะ . . . เพื่อให้เห็นภาพเราแมวน้ำจะขอฉายภาพแบบช้าๆให้ดูว่ามันเกิดอะไรขึ้นบ้างนะ

## 🐌 Step By Step

1️⃣ เราใช้คำสั่ง **`docker run docker/getting-started`** เป็นการสั่งให้เจ้าปลาวาฬนำ Image ชื่อ `docker/getting-started` ไปสร้างเป็น Container

![](/files/-MKRcqYjSr9RaEQ-n5lt)

2️⃣ อย่างที่เคยบอกไปใน [**บทความที่ 2**](https://www.saladpuk.com/basic/docker-1/containers) ว่า **Container มันคือ Environments ที่ถูกสร้างตามที่ Image กำหนดไว้** ดังนั้นถ้าเราซูมเข้าไปในตู้คอนเทนเนอร์ เราก็จะเห็นว่ามันมีเว็บ python ที่ทำงานอยู่ใน nginx นั่นเอง

![](/files/-MKRieKFtNxkKiOmZNhb)

3️⃣ โดยปรกติ **เราจะเข้าถึงของที่อยู่ภายใน Container ไม่ได้** แม้ว่าเราจะรู้ว่า nginx มันเปิด port 80 ไว้อยู่ก็ตาม

![](/files/-MKRmYklQADmxlIzekCX)

4️⃣ แต่ถ้าดูคำสั่งของเราดีๆจะเห็นว่ามันมี **`-p`** อยู่ด้วย ซึ่งมันคือการ **map port ของที่อยู่ในโลก Container ให้ออกมาสู่โลกภายนอก** โดยตัวคำสั่งเราเขียนว่า `-p 80:80` หมายถึง เรากำหนดให้ port 80 ของโลกภายนอก (ซ้าย) เชื่อมกับ port 80 ที่อยู่ในโลก Container (ขวา) ซึ่งเมื่อเราทำแบบนี้ก็จะทำให้เราสามารถเข้าสู่โลกของ Container ได้จาก port 80 นั่นเอง ตามรูปเบย

![](/files/-MKRpxHhDAII0IkMiXx8)

5️⃣ สุดท้ายในคำสั่งของเราจะมี **`-d`** อยู่ด้วย ซึ่งมันคือการ **detach** หรือแปลให้เข้าใจง่ายๆคือ **สั่งให้ docker ทำงานเป็น background ไป โดยถ้าทำงานเสร็จก็รบกวนบอกรหัสของ Container ตัวที่พึ่งสร้างให้ด้วยนะ** ซึ่งพอพี่วาฬสร้าง Container นั้นๆเสร็จเราก็จะเห็น **`Container ID`** เป็นเหมือนข้อความมั่วๆนั่นเอง

![](/files/-MKRuxPnIEKncpxwUEsd)

{% hint style="info" %}
**Detach mode**\
**คำสั่ง detach จะทำให้ตัว Command Prompt ของเรา ไม่สนใจรายละเอียดของ process ที่เราสั่ง run ไป**  แต่ถ้าเราอยากดูรายละเอียดว่าตัว Container นั้นมัน run ขึ้นมาแล้วเป็นยังไง มี event อะไรเกิดขึ้นบ้าง เราก็แค่ไม่ต้องใส่ -d ลงไปเท่านั้นเองครับ (ลองสั่ง docker run ใหม่โดยไม่ใส่ -d เข้าไปดูนะ)
{% endhint %}

🤠 จากตรงนี้จะทำให้เราเห็นว่าตัว **Container มันคือ Environments ที่แยกตัวออกไม่ยุ่งกับใครเลย** ซึ่งข้างในของมันจะมีแอพคอยทำงานตามที่เรากำหนดไว้อยู่ ดังนั้นต่อให้เราลงโปรแกรมอะไรในเครื่องเราไปมันก็ไม่มีผลกับของที่อยู่ใน Container นั่นเอง

## 🐳 Docker PS

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

```
docker ps
```

ซึ่งเราก็จะเห็นรายการ process ทั้งหมดที่กำลังทำงานอยู่ ตามรูปด้านล่าง (บางอย่างจะเห็นไม่เหมือนของผมนะ)

![มันยาวมากขอตัดแบบย่อๆนะ](/files/-MKS2Ce9aCoF3LmhVVQI)

จากตรงนี้จะทำให้เรารู้ว่าเจ้าตัว Container มันจะมีรายละเอียดของมันอยู่ หน้าตาราวๆนี้

![](/files/-MKS3p9qy78rDbIvDRgx)

🤠 คราวนี้เราลองปิดเจ้า **`❌ Command Prompt`** ของเราทิ้งไป แล้วลองเข้าเว็บตัวเดิมดู [http://localhost](http://localhost/) ก็จะพบว่าเว็บของเรายังใช้งานได้ปรกติสุขอยู่ เพราะเราสั่งให้มัน run เป็น background นั่นเอง (สำหรับคนที่ไม่ได้ run ด้วย detach mode เมื่อปิด Command Prompt ลงจะพบว่าเว็บเข้าบ่ได้ แต่ก็ไม่ต้องตกใจอ่านต่อโลด)

## 🐳 Docker Stop

คราวนี้ถ้าเราอยากจะ **สั่งให้ Container ที่กำลังทำงานอยู่มันหยุดการทำงาน** เราก็จะใช้คำสั่ง **`docker stop`** แล้วตามด้วย **Container ID** ที่อยากจะให้มันหยุดนั่นเอง (หากจำรหัสไม่ได้ก็ใช้คำสั่ง docker ps ด้านบนเรียกขึ้นมาดู)

![](/files/-MKS2Ce9aCoF3LmhVVQI)

ในการระบุ Container ID ไม่จำเป็นต้องพิมพ์จนครบทุกตัวก็ได้นะ เช่น จากรูปด้านผมก็จะพิมพ์แค่ตามโค้ดด้านล่าง (จะพิมพ์กี่ตัวก็ได้ขอแค่มัน unique พอที่จะระบุ container ที่อยากลบได้ก็พอ)

```
docker stop 3d4
```

อาวล่ะ คราวนี้เราลองเข้าไปดูตัวเว็บของเราอีกครั้งดิ๊ [http://localhost](http://localhost/) .... กลายเป็นโกโก้ครั้นช์เรียบร้อย

![](/files/-MKS7tiUvdXy1EWwYmWw)

{% hint style="info" %}
หาก stop มันแล้วแต่ยังเข้าได้อยู่ อาจเป็นเพราะมันเป็น cache ของตัว browser ก็ได้ แนะนำให้เปิด Incognito mode หรือ private mode ของตัว browser ดูนะ
{% endhint %}

เพราะเราสั่งให้ Container ตัวนั้นมันหยุดยังไง เลยทำให้เราเข้าเว็บไม่ได้ และเมื่อเราใช้คำสั่ง `docker ps` อีกครั้ง เราก็จะไม่เห็น process ไหนเลยที่ทำงานอยู่ ตามรูปด้านล่าง

![](/files/-MKS9oeM7SCjVdqevnIK)

![](/files/-MKSACk2D30VvvAJoHi-)

แต่จริงๆ Container นั้นก็ยังอยู่นะ เพียงแค่มันไม่โชว์ให้เราเห็นเฉยๆ ซึ่งถ้าเราอยากเห็นว่าตอนนี้ในเครื่องเรามี Containers อะไรอยู่บ้าง เราก็แค่เติม `-a` เพื่อให้โชว์ทั้งหมดนั่นเอง (**All**)

```
docker ps -a
```

เราก็จะได้ผลลัพท์ตามรูปด้านล่าง ซึ่งจะเห็นว่า `Status` มันเปลี่ยนเป็น **Exited** แล้วนั่นเอง

![ขอตัดมาสั้นๆนะ](/files/-MKSBceeT3hk0C9g7ihK)

## 🐳 Docker Start

แน่นอนในเมื่อเราสั่งหยุดมันได้ เราก็ย่อมสั่งให้มันทำงานต่อได้เช่นกันด้วยคำสั่ง **`docker start`** แล้วตามด้วย **Container ID** ที่อยากจะให้มันทำงานต่อนั่นเอง ซึ่งก็ไม่จำเป็นต้องใส่รหัสเต็มๆเช่นเคย ตามตัวอย่างนี้ แล้วก็ลองเข้าเว็บตัวเดิมอีกครั้ง [http://localhost](http://localhost/) ก็จะพบว่ามันกลับมาทำงานได้แบ๊ว 😙

```
docker start 3d
```

![](/files/-MKRUL2RMc7BU_4wFRq_)

แล้วเมื่อเราใช้คำสั่ง **`docker ps`** ธรรมดาๆ ก็จะเห็น Container ตัวนั้นกลับมาเป็นสถานะ **Up** ละ

![](/files/-MKSHfT-TdHa26X3NieC)

## 🐳 Docker RM

คราวนี้ถ้าเราไม่อยากจะใช้ Container แล้วล่ะ? เราจะให้พี่วาฬแบกหนักหัวเขาต่อมุ๊ย? (เช่น Container ในตัวอย่างนี้เราก็คงจะไม่ใช้ต่อละจิงป่าว) ซึ่งเมื่อเกิดเหตการณ์แบบนี้ขึ้น เราก็สามารถลบ Container ด้วยคำสั่ง **`docker rm`** แล้วตามด้วย **Container ID** ที่อยากจะลบมันทิ้งนั่นเอง 😢 ตามตัวอย่างด้านล่างเบย

```
docker rm 3d
```

> Error response from daemon: **You cannot remove a running container** 3d4f30d3631032798f929cd21940041687b60787ad8329795ec92b1f065d46be. Stop the container before attempting removal or force remove

ลบไม่ด๊ายยยย!! 🤪 ไม่ต้องตกใจไป เพราะ Docker บอกว่า Container ตัวนั้นมันกำลังทำงานอยู่ ซึ่งเราจะเจอบ่อยมาก ซึ่งเราก็สามารถขืนใจมันได้โดยใช้คำสั่ง `-f` ย่อจาก **force** เพื่อเป็นการบังคับให้มันทำคำสั่งนั้นๆ ตามโค้ดด้านล่าง

```
docker rm -f 3d
```

จบข่าว ไม่หนักกบาลพี่วาฬล่ะ และใช้คำสั่ง `docker ps -a` ก็ไม่อยู่ให้กวนใจอีกต่อไป

![](/files/-MKSJcDnSyfpi_JHvTUb)

## 🐳 Docker RMI

จะลบทั้งทีก็ต้องถอนรากถอนโคนทิ้ง 😈 !! เพราะรากเหง้าของ Container มันก็คือ Image ยังไงล่าาา ไหนๆก็จะจบบทความแล้วจะเก็บ Image มันไว้ทำไม!! ดังนั้นเราก็แค่ใช้คำสั่ง `docker rmi` แล้วตามด้วย **Image ID** ที่อยากจะลบมันทิ้งนั่นเอง 😈 ซึ่งหากใครลืมไปแล้วว่ารหัสของ Image คืออะไรก็ใช้คำสั่ง `docker images` เปิดดู แล้วลบทิ้งซ๊าาา

![](/files/-MKRKlPUOm_5_ePoqu99)

```
docker rmi 1f3
```

> หากใครทำไม่ได้อีกก็ขืนใจมันด้วย **-f** เช่นเคย 😈

ก็เป็นอันปิดฉาก Container Image ที่ใช้ในการลองวิชาตัวแรกกั๊ฟป๋ม 😇

## 🎯 Summary

จนถึงตอนนี้เราน่าจะเข้าใจละว่า **`🖼️ Container Image`** มันเป็นต้นแบบในการเอาไปสร้าง Environment นั่นเอง ส่วนเจ้า **`📦 Container`** มันก็คือ Environment ที่เอาไว้ทำงานจริงๆ โดยมันจะถูกตั้งค่าทุกอย่างตามที่ตัว image กำหนดไว้เป๊ะๆเลย ส่วนเมื่อเราจะสั่งงาน **`🐳 Docker`** เราก็จะใช้คำสั่งผ่าน **`CLI`** ที่ย่อมาจาก **Command Line Interface** อีกที โดยคำสั่งก็จะมีการแยกเป็นเรื่องๆของมันโดยเฉพาะ และสุดท้ายโลกของ Container มันถูกตัดขาดจากโลกภายนอก ดังนั้นเราต้องมีการเชื่อม PORT ระหว่าง 2 โลกก่อน ถึงจะทำให้โลกข้างนอกใช้งานโลก Container ได้

![](/files/-MKSTSFc4ppHR-jVScsr)

> ในบทความนี้มีหลายจุดที่อยากอธิบายต่ออยู่ แต่ดูความยาวของมันแล้วคิดว่าค่อยๆไปลงรายละเอียดอีกทีละกันนะ

ในบทความถัดไปเราจะได้ลองใช้ **🐳 Docker** แบบไม่ต้องมานั่งพิมพ์คำสั่งดูบ้าง และเริ่มลงรายละเอียดในส่วนของ **🖼️ Container Image** กับ **`🗃️ Docker Registry`** กันต่อกั๊ฟป๋ม

{% content-ref url="/pages/-MKYMhtUYgbVeL2rpZh4" %}
[🛠️ Docker Tools](/basic/docker-1/tools.md)
{% endcontent-ref %}

{% hint style="success" %}
อ่านแล้วชอบป๋มก็ขอฝากแชร์ หรือกดติดตามเพื่อจะได้ไม่พลาดบทความอื่นๆจาก **ดช.แมวน้ำ** ได้จากลิงค์นี้เบยครัช [**Saladpuk Fanclub**](https://www.facebook.com/mr.saladpuk/?modal=admin_todo_tour) **😍**
{% endhint %}

![ช่องทางสนับสนุนค่าอาหารแมวน้ำกั๊ฟ 😘](/files/-MKNmp9HEqzREDsXrZ0H)
