แก้ปัญหาเวลา start docker ไม่ขึ้น เพราะ port ถูกจอง

เจอปัญหาเวลาจะ start docker โดยเฉพาะเวลาที่จะ start พวก MySQL services.

ซึ่ง Error นี้มันมาจากการที่ port ที่เราต้องการ ถูกจอง โดยที่ยังไม่มีใครใช้จริงๆซะด้วย

เท่าที่ check เป็นเพราะ hyper-V ของ Windows อยู่ๆก็อยากสำรองไว้ ไม่รู้ทำไม

ทั้งๆที่เพิ่ง restart เครื่องไม่นานด้วย

วิธีแก้ปัญหาแบบง่ายๆก็คือปิด network ของ hyper-V ทิ้งไป บังคับให้มันคาย port ที่จองไว้ออกมา

โดยเราต้องใช้ cmd ที่เป็น Administrator mode แล้วสั่ง

net stop winnat

จากนั้นค่อย start MySQL services

จากนั้นค่อย

net start winnat


ข้อมูลจาก Gemini

ซึ่งหลักๆแล้วที่จะมีปัญหานี้ก็น่าจะมีแค่ OS Windows เท่านั้น


สาเหตุส่วนใหญ่มักเกิดจาก Windows Hyper-V หรือ WSL2 ทำการจองช่วงพอร์ต (Port Exclusion Range) เอาไว้เพื่อใช้งานภายใน ทำให้แอปพลิเคชันอื่น (รวมถึง Docker) เข้าไปใช้งานพอร์ตในช่วงนั้นไม่ได้ แม้ว่าพอร์ตนั้นจะดูเหมือน “ว่าง” อยู่ก็ตามครับ

วิธีแก้ไขและตรวจสอบ มีขั้นตอนดังนี้ครับ:


1. ตรวจสอบว่าพอร์ต 3306 ถูกจองโดยระบบหรือไม่

เปิด PowerShell (Run as Administrator) แล้วใช้คำสั่งนี้เพื่อดูว่าพอร์ตที่ต้องการอยู่ใน “ช่วงที่ถูกจอง” หรือไม่:

PowerShell

netsh int ipv4 show excludedportrange protocol=tcp

หากพอร์ต 3306 อยู่ในช่วงพอร์ตที่แสดงขึ้นมา แสดงว่าคุณโดน Windows จองไปแบบ “กั๊ก” ไว้ครับ


2. วิธีการ Release พอร์ต (Quick Fix)

วิธีที่ง่ายที่สุดและมักได้ผลคือการ Restart บริการเครือข่าย เพื่อคืนค่าพอร์ตที่ถูกจองแบบสุ่ม (Dynamic ports) ครับ:

  1. ปิด Docker Desktop
  2. เปิด PowerShell (Admin) แล้วรันคำสั่ง:PowerShellnet stop winnat net start winnat
  3. ลองรัน docker-compose up -d อีกครั้ง

3. การแก้ปัญหาในระยะยาว (Permanent Fix)

ถ้าคุณไม่อยากเจอปัญหานี้ซ้ำซาก คุณควรกันพอร์ตที่ต้องใช้บ่อยๆ (เช่น 3306, 8080, 5432) ออกจากช่วงที่ Windows จะจองไปใช้เอง:

  1. ปิดการใช้งาน Hyper-V ชั่วคราว (อาจต้อง Restart เครื่อง)
  2. จองพอร์ตไว้ให้ตัวเอง:PowerShellnetsh int ipv4 add excludedportrange protocol=tcp startport=3306 numberofports=1 store=persistent
  3. หลังจากนั้น Windows จะไม่เอาพอร์ต 3306 ไปใช้ในระบบสุ่มของมันอีกครับ

4. ตรวจสอบว่ามีโปรแกรมอื่นใช้พอร์ต 3306 อยู่หรือไม่

บางทีคุณอาจจะมี MySQL Server ที่ติดตั้งแบบ Installer ปกติ (Native) รันค้างอยู่ในเครื่อง:

  • ใช้คำสั่งตรวจสอบว่าใครกำลังคาพอร์ตนี้อยู่:PowerShellnetstat -ano | findstr :3306
  • ถ้าเจอเลข PID (ตัวเลขขวาสุด) ให้ไปเช็คใน Task Manager แล้วปิด Process นั้นทิ้งก่อนครับ

PowerShell

# รันใน PowerShell (Admin)
net stop winnat
docker-compose up -d
net start winnat

การสั่ง net stop winnat มีผลกระทบโดยตรงต่อระบบ Network ของ Windows ครับ เพราะมันคือการหยุดการทำงานของ Windows Native Address Translation (WinNAT)

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


1. บริการที่ “จะใช้งานไม่ได้” ชั่วคราว (ขณะที่ Stop อยู่)

  • Docker & WSL2: คอนเทนเนอร์ที่กำลังรันอยู่จะสูญเสียการเชื่อมต่อกับเครือข่ายภายนอก (Internet) และเครื่อง Host จะเข้าถึง Service ภายใน Container ไม่ได้ชั่วคราว
  • Virtual Machines (Hyper-V): VM ที่ตั้งค่า Network แบบ Internal หรือ Default Switch จะออกอินเทอร์เน็ตไม่ได้
  • Windows Sandbox: จะใช้งานอินเทอร์เน็ตภายใน Sandbox ไม่ได้
  • Mobile Hotspot: หากคุณแชร์เน็ตจากคอมพิวเตอร์ให้เครื่องอื่นผ่าน Wi-Fi ฟีเจอร์นี้จะหยุดทำงาน

2. บริการที่ “ไม่ได้รับผลกระทบ”

  • แอปพลิเคชันทั่วไป: Chrome, Line, Zoom หรือ Browser ต่างๆ ที่รันบน Windows โดยตรง (Native) ยังคงใช้งานอินเทอร์เน็ตได้ตามปกติ
  • File Sharing (SMB): การแชร์ไฟล์ภายในวง LAN เดียวกันมักจะไม่ได้รับผลกระทบ

แนะนำขั้นตอนที่ปลอดภัย (Best Practice)

เนื่องจากคุณกำลังเจอปัญหาพอร์ตถูกจองโดย Windows การทำ net stop winnat ควรทำเป็น “จังหวะสั้นๆ” เท่านั้นครับ:

  1. สั่ง Stop: net stop winnat (เพื่อคลายการจองพอร์ตของ Windows)
  2. รัน Docker: docker-compose up -d (เพื่อให้ Docker แย่งชิงพอร์ต 3306 มาจองไว้ก่อน)
  3. สั่ง Start ทันที: net start winnat (เพื่อให้ระบบ Network อื่นๆ กลับมาทำงานปกติ)

ข้อควรระวัง: หากคุณรันคำสั่งเหล่านี้ผ่าน Remote Desktop (RDP) หรือกำลังดาวน์โหลดไฟล์สำคัญใน WSL2 ควรทำในช่วงที่ไม่มีการรับส่งข้อมูลหนักๆ เพราะการตัดต่อ Service นี้อาจทำให้การเชื่อมต่อในส่วนของ Virtual Layer หลุดได้ครับ

โดยรวมแล้ว “ไม่อันตราย” ต่อตัวระบบปฏิบัติการครับ เป็นวิธีที่ Developer สาย Windows นิยมใช้แก้ปัญหา Port Conflict กันเป็นปกติครับ