สร้าง Docker Image ลีนๆ ด้วย Multi-stage Builds
Tags: docker, devops, thai
Published: 2019-05-01 06:51:07

---
title: สร้าง Docker Image ลีนๆ ด้วย Multi-stage Builds
published: true
description: -ขนาดไม่ใช่เรื่องสำคัญ- คงไม่จริงแน่ๆ สำหรับการใช้งาน Docker เพราะเมื่อขนาดใหญ่ขึ้น เราก็เสียค่า storage สำหรับเก็บ image ใน registry มากขึ้น ตอนรัน container ก็ต้องใช้ disk ของเครื่อง host มากขึ้นอีก
tags: docker, devops, thai
cover_image: https://thepracticaldev.s3.amazonaws.com/i/6twxrqxy2o5clg7kb7mp.jpeg
---

> Firstly published on 2018-01-18 in [Medium](https://medium.com/zarewoft/%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-docker-image-%E0%B8%A5%E0%B8%B5%E0%B8%99%E0%B9%86-%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-multi-stage-builds-e786ba6d5102).

สวัสดีครับ 😀
บล็อกนี้เป็นบล็อกแรกสำหรับเรื่อง Docker เลยครับ โดยผมตั้งใจว่าจะมาเล่าผลลัพธ์จากประสบการณ์การฝึกใช้งาน Docker ทั้งเรื่องง่ายๆ เรื่องที่เสียเวลา เรื่องที่เจ็บมาเยอะๆ ให้ทุกท่านอ่านกันครับ

---

"ขนาดไม่ใช่เรื่องสำคัญ" คงไม่จริงแน่ๆ สำหรับการใช้งาน Docker เพราะเมื่อขนาดใหญ่ขึ้น เราก็เสียค่า storage สำหรับเก็บ image ใน registry มากขึ้น ตอนรัน container ก็ต้องใช้ disk ของเครื่อง host มากขึ้นอีก

การลดขนาดของ docker image มีหลากหลาย practice ที่เราควรทำครับ เช่น การไม่พยายามสร้าง layer ใหม่ที่ไม่จำเป็นด้วย `RUN`, การจัดวาง sequence ของ command ใน Dockerfile
วันนี้ผมจะพาท่านๆมารู้จักกับ multi-stage builds ซึ่งผมได้ความรู้มาจากการลองผิดลองถูก อ่านบทความต่างๆ แล้วทดลองใช้กับงานจริงครับ

# Multi-stage Builds
ผมมักชอบที่จะรัน test และ build บน docker เลย เพื่อการันตีว่าแอพผ่านการ test ก่อนจะ build บน environment ที่เหมือนกันครับ แต่ในบางครั้งการ build บน docker ก็ทำให้มี file ที่ไม่จำเป็นมากมายเกิดขึ้นใน image เรา ถ้าเราเอาตัวนี้ไปใช้จริงก็คงจะเป็น image ที่หนาเกินไป

ยกตัวอย่างเช่น build gulp สำหรับ frontend แอพ ถ้าเอาแบบเอี่ยมๆเลย เราก็ต้องใช้ `FROM node` แล้วมา `npm install` แล้วค่อยใช้ gulp อีกที

ซึ่งมันไม่จำเป็นมากๆเลยที่จะเอาทั้งหมดนี้ไปไว้ใน image ใช่ไหมครับ เพราะสุดท้ายแล้วเราแค่จะ serve static file เอง มันคงจะดีไม่น้อย ถ้าเราใช้ image หนึ่งอันมารันทั้งหมดนี้ แล้วเอาผลลัพธ์ไปใส่อีก image ใช่มะ?

Multi-stage builds คือ concept แบบที่เราว่าเลยครับ กล่าวคือ การสร้าง stage นึง แล้วใช้เป็นแค่ทางผ่านแล้วเอาไฟล์ไปใช้อีก stage นึงครับ

![](https://thepracticaldev.s3.amazonaws.com/i/jslgy2rh0bdoep1mpcji.png)

# วิธีการใช้งาน
ระบุ name ให้กับ image ที่เราสร้างในกระบวนการในบรรทัด FROM

```
FROM <IMAGE> AS <NAME>
```

เวลาเราจะ `COPY` file จาก stage เดิม ให้ใส่ parameter ชื่อ from เพิ่มเข้าไป

```
COPY --from=<NAME> <ORIGIN_PATH> <DEST_PATH>
```

{% gist https://gist.github.com/mixth/f4b8aa74461a21e6839e0b4d26278645 %}
<figcaption>ตัวอย่าง multi-stages builds โดยการ npm install, run build แอพ ก่อนจะสร้าง image nginx สำหรับ serve</figcaption>

ในตัวอย่างข้างต้นคือเราใช้ image node มา build app เสร็จแล้ว serve ด้วย nginx ครับ ถ้าอยาก validate ดูว่าถูกต้องไหม ลองสั่ง `docker history <IMAGE_HASH>` ดูได้ครับ
แต่หากเราไม่อยากตั้งชื่อให้มันจริงๆ ก็ใส่เป็น index ก็ได้นะ (0, 1, 2, …) โดยเรียงจาก `FROM` ด้านบนสุดมาเรื่อยๆครับ (แต่… มันตั้งชื่อได้ก็ตั้งให้มันเถิด)

{% gist https://gist.github.com/mixth/eade83319771bb3a264a6d3567f6de57 %}

ลองดูนะครับว่าเราสามารถใช้เทคนิคนี้ในการทำให้ image ของเราเล็กลง หรือใช้งานได้สะดวกขึ้นอย่างไงบ้าง

หากมีส่วนใดผิดพลาด ไม่ถูกต้อง แจ้งได้เลยครับ :)