แก้ error “could not select device driver with capabilities gpu” ใน Docker

รัน container ที่ต้องใช้ GPU ด้วยคำสั่งประมาณ docker run --gpus all ... แล้วเจอข้อความนี้แทน

docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].

error could not select device driver with capabilities gpu นี้แปลตรงตัวว่า Docker ไม่รู้จัก “GPU device driver” ที่ต้องใช้ในการส่งต่อ GPU เข้าไปให้ container เห็น สาเหตุเกือบทั้งหมดมาจากขาดส่วนประกอบบางอย่างที่ทำให้ Docker คุยกับการ์ดจอไม่ได้ ไม่ใช่ GPU เสียหรือ Docker พัง บทความนี้จะไล่แก้ทีละขั้นตอนทั้งบน Windows (WSL2) และ Linux

พบบ่อยที่สุดตอนรัน workload ที่ต้องใช้พลังการประมวลผลของการ์ดจอ เช่น เทรนโมเดล machine learning, รัน inference ของโมเดล AI ขนาดใหญ่ หรือ render กราฟิก 3D ภายใน container เพราะงานเหล่านี้ต้องการ GPU โดยตรง จะรันด้วย CPU อย่างเดียวช้าเกินจะใช้งานจริงได้

สาเหตุที่แท้จริง

ปกติ Docker container จะแยกตัวออกจากเครื่องจริงโดยสมบูรณ์ รวมถึงไม่เห็นฮาร์ดแวร์อย่าง GPU ด้วย การจะให้ container “มองเห็น” และใช้ GPU ได้ต้องอาศัยส่วนเชื่อมพิเศษที่เรียกว่า NVIDIA Container Toolkit (ชื่อเดิมคือ nvidia-docker2) ทำหน้าที่บอก Docker daemon ว่าจะส่งต่อการเข้าถึง GPU เข้าไปใน container ยังไง

error นี้เกิดขึ้นเมื่อ Docker daemon ไม่รู้จัก device driver ที่ชื่อ nvidia เลย ซึ่งมีสาเหตุหลักอยู่ 3 แบบ

  • ยังไม่ได้ติดตั้ง NVIDIA Container Toolkit บนเครื่อง (หรือ WSL distro ที่ Docker ใช้งานอยู่)
  • ติดตั้งแล้วแต่ยังไม่ได้ restart Docker daemon/Docker Desktop ให้โหลดค่าใหม่
  • ไดรเวอร์การ์ดจอ (NVIDIA driver) บนเครื่องจริงเก่าเกินไป ไม่รองรับการส่งต่อ GPU ผ่าน container

เช็คก่อนว่าเครื่องพร้อมใช้ GPU ผ่าน Docker หรือยัง

เช็คว่ามีการ์ดจอ NVIDIA และไดรเวอร์ทำงานอยู่ไหม เปิด terminal (บน Windows ใช้ PowerShell ปกติ ไม่ใช่ใน WSL) แล้วพิมพ์

nvidia-smi

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

วิธีแก้บน Windows (Docker Desktop + WSL2)

Docker Desktop บน Windows จัดการ GPU passthrough ผ่าน WSL2 ให้เกือบทั้งหมดโดยอัตโนมัติ ไม่ต้องติดตั้ง NVIDIA Container Toolkit เองภายใน WSL ขอแค่ทำ 3 ขั้นตอนนี้ให้ครบ

ขั้นที่ 1: อัปเดต NVIDIA driver บนเครื่อง Windows (ไม่ใช่ในเครื่อง WSL) เป็นเวอร์ชันที่รองรับ WSL2 CUDA driver ไดรเวอร์รุ่นใหม่ๆ จาก NVIDIA รองรับอยู่แล้ว แค่ต้องอัปเดตให้เป็นเวอร์ชันล่าสุด

ขั้นที่ 2: เปิด GPU support ใน Docker Desktop ไปที่ไอคอนรูปเฟือง (Settings) → Resources → WSL Integration ตรวจสอบว่า distro ที่ใช้งานอยู่ถูกเปิดใช้งานอยู่ (toggle เป็นสีเขียว) จากนั้นไปที่ Settings → General ตรวจว่าเลือก “Use the WSL 2 based engine” อยู่

ขั้นที่ 3: restart Docker Desktop ทั้งหมด ปิดโปรแกรมแล้วรัน wsl --shutdown ใน PowerShell ก่อนเปิด Docker Desktop ขึ้นมาใหม่ เพื่อให้การตั้งค่าทั้งหมดมีผลจริง

วิธีแก้บน Linux (Docker Engine ตรงๆ)

ถ้าใช้ Docker Engine บน Linux โดยตรง (ไม่ผ่าน Docker Desktop) ต้องติดตั้ง NVIDIA Container Toolkit ด้วยตัวเอง ขั้นตอนคร่าวๆ บน Ubuntu/Debian

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

บรรทัดสุดท้าย systemctl restart docker สำคัญมาก เพราะขั้นตอน nvidia-ctk runtime configure แค่เขียนค่าลงไฟล์ /etc/docker/daemon.json แต่ Docker daemon ที่กำลังรันอยู่จะยังไม่รู้จักค่าใหม่จนกว่าจะ restart หลายคนติดตั้งครบทุกขั้นตอนแล้วยังเจอ error เดิมอยู่ เพราะลืม restart daemon ตัวนี้เอง

เช็คเวอร์ชัน WSL kernel ว่ารองรับ GPU หรือยัง

อีกจุดที่มักถูกมองข้ามคือ WSL kernel เวอร์ชันเก่าเกินไปก็ทำให้ GPU passthrough ใช้งานไม่ได้เหมือนกัน แม้ไดรเวอร์และ Docker Desktop จะตั้งค่าครบถ้วนแล้วก็ตาม เปิด PowerShell แล้วเช็คเวอร์ชันปัจจุบันด้วย

wsl --version

ถ้าเวอร์ชัน WSL หรือ kernel เก่ากว่าที่ Microsoft แนะนำสำหรับ GPU compute ให้อัปเดตด้วยคำสั่งเดียว

wsl --update

จากนั้น wsl --shutdown แล้วเปิด Docker Desktop ใหม่อีกครั้ง ขั้นตอนนี้ง่ายมากแต่แก้ปัญหาได้บ่อยกว่าที่คิด เพราะ Windows ไม่ได้บังคับอัปเดต WSL kernel ให้อัตโนมัติเสมอไป

ทดสอบว่าใช้งานได้จริง

หลังทำครบทุกขั้นตอนแล้ว ทดสอบด้วยคำสั่งนี้ (ทั้งบน Windows และ Linux)

docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi

ถ้าเห็นตาราง nvidia-smi แสดงขึ้นมาจากภายใน container (ไม่ใช่แค่จากเครื่องจริง) แปลว่า GPU passthrough ทำงานสมบูรณ์แล้ว container มองเห็นการ์ดจอได้จริง

แก้ error ที่เกี่ยวข้อง “unknown or invalid runtime name nvidia”

error นี้มักเจอคู่กันบน Linux เกิดจาก Docker daemon ยังไม่รู้จัก runtime ชื่อ nvidia เลย ทั้งที่ติดตั้ง NVIDIA Container Toolkit ไปแล้ว สาเหตุมักเป็นเพราะรัน nvidia-ctk runtime configure ไม่สำเร็จ หรือแก้ไฟล์ /etc/docker/daemon.json เองแล้วพิมพ์ผิด เช็คเนื้อหาไฟล์ด้วย

cat /etc/docker/daemon.json

ต้องเห็นบรรทัด "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } อยู่ในส่วน "runtimes" ถ้าไม่มีให้รัน sudo nvidia-ctk runtime configure --runtime=docker ใหม่อีกครั้งแล้ว restart daemon ตามขั้นตอนด้านบน

ปัญหาอื่นที่เจอบ่อย

GPU เห็นบนเครื่องจริงแต่ container ยังมองไม่เห็น — ลองเช็คว่ารันคำสั่งด้วย flag --gpus all จริงหรือไม่ เป็น flag ที่ลืมใส่บ่อยที่สุด ถ้าไม่ใส่ Docker จะรัน container แบบไม่มี GPU ให้เลยโดยไม่ error อะไร แค่ container จะมองไม่เห็นการ์ดจอเฉยๆ เหมือนรันแบบปกติทุกอย่าง เพียงแต่ workload ที่ต้องใช้ GPU จะช้าผิดปกติหรือ error คนละแบบแทน เพราะไปพยายามใช้ CPU แทน GPU โดยไม่รู้ตัว

ใช้ Docker Compose แล้วต้องเปิด GPU ยังไง — เพิ่ม deploy.resources.reservations.devices ในไฟล์ docker-compose.yml แทนการใส่ flag เพราะ Compose ไม่มี --gpus ให้ใช้ตรงๆ ต้องกำหนดผ่าน syntax เฉพาะของ Compose

การ์ดจอ AMD หรือ Intel ใช้วิธีเดียวกันได้ไหม — ไม่ได้ วิธีในบทความนี้ใช้ได้เฉพาะการ์ดจอ NVIDIA เท่านั้น เพราะ NVIDIA Container Toolkit เป็นเครื่องมือเฉพาะของ NVIDIA การใช้ GPU ค่ายอื่นผ่าน Docker ต้องการเครื่องมือคนละชุด และยังมีการรองรับที่จำกัดกว่ามาก

Docker Desktop เวอร์ชันเก่าเกินไปก็เป็นสาเหตุได้เหมือนกัน — GPU support ผ่าน WSL2 เป็นฟีเจอร์ที่เพิ่มเข้ามาทีหลัง ถ้าใช้ Docker Desktop เวอร์ชันเก่ามากอาจไม่รองรับเลยไม่ว่าจะตั้งค่าถูกแค่ไหน เช็คเวอร์ชันได้ที่ไอคอนรูปเฟือง → About Docker Desktop ถ้าเก่ากว่า 1-2 ปีแนะนำให้อัปเดตเป็นเวอร์ชันล่าสุดก่อนไล่แก้ปัญหาอื่น

คำถามที่พบบ่อย

ทำไมต้องอัปเดต driver บน Windows แทนที่จะติดตั้งใน WSL เพราะสถาปัตยกรรมของ WSL2 ใช้ไดรเวอร์ GPU ของ Windows โดยตรง (ผ่านเทคโนโลยีที่เรียกว่า GPU paravirtualization) ไม่ต้องมีไดรเวอร์แยกอีกชุดในฝั่ง Linux เลย การติดตั้งไดรเวอร์ NVIDIA ซ้ำภายใน WSL อาจทำให้ระบบสับสนและเป็นสาเหตุของปัญหาอื่นตามมาได้

ต้องติดตั้ง CUDA Toolkit เต็มรูปแบบด้วยไหม ไม่จำเป็นสำหรับแค่การรัน container ที่ใช้ GPU ปกติ image อย่าง nvidia/cuda ที่ดาวน์โหลดมาจะรวม CUDA runtime ที่จำเป็นไว้ให้แล้ว ติดตั้ง CUDA Toolkit เต็มชุดจำเป็นเฉพาะตอนต้องการ compile โค้ด CUDA เองภายใน container เท่านั้น

เช็คเวอร์ชัน NVIDIA Container Toolkit ที่ติดตั้งไว้ยังไง บน Linux ใช้คำสั่ง nvidia-ctk --version ส่วนบน Windows ที่ใช้ผ่าน Docker Desktop ไม่ต้องเช็คเวอร์ชันนี้เอง เพราะ Docker Desktop จัดการส่วนนี้ให้ทั้งหมดผ่าน WSL2 integration อยู่แล้ว

รันได้ GPU เดียวหรือใช้หลายใบพร้อมกันได้ไหม ใช้ได้ทั้งสองแบบ ค่า --gpus all ที่ใช้ในบทความนี้จะส่งต่อ GPU ทุกใบที่เครื่องมีให้ container มองเห็นทั้งหมด ถ้าต้องการจำกัดให้เห็นเฉพาะบางใบ ระบุเลข index แทนได้ เช่น --gpus '"device=0"' เพื่อส่งต่อเฉพาะ GPU ใบแรกเท่านั้น มีประโยชน์เวลารัน container หลายตัวพร้อมกันแล้วต้องการแบ่ง GPU ให้แต่ละตัวไม่ชนกัน เหมาะกับเซิร์ฟเวอร์ที่มีการ์ดจอหลายใบและต้องแชร์ทรัพยากรระหว่างทีมหรือหลาย workload พร้อมกัน

ใช้ WSL2 กับ Hyper-V backend ต่างกันเรื่อง GPU ไหม ต่างกันมาก WSL2 backend รองรับ GPU passthrough แบบเต็มรูปแบบและเป็นวิธีที่ Docker แนะนำสำหรับ Windows ส่วน Hyper-V backend (แบบเก่า) มีข้อจำกัดเรื่อง GPU มากกว่า และบางฟีเจอร์อาจใช้ไม่ได้เลย ถ้ายังใช้ Hyper-V backend อยู่ แนะนำให้เปลี่ยนมาใช้ WSL2 backend ก่อนไล่แก้ปัญหา GPU เพราะปัญหาหลายอย่างที่ดูเหมือนแก้ยากจะหายไปทันทีแค่เปลี่ยน backend

สรุป

error could not select device driver with capabilities gpu เกิดจาก Docker ไม่รู้จัก GPU device driver ที่ต้องใช้ แก้ตามเครื่องที่ใช้งาน

  • Windows (Docker Desktop): อัปเดต NVIDIA driver → เปิด WSL Integration ใน Settings → restart ด้วย wsl --shutdown
  • Linux (Docker Engine): ติดตั้ง NVIDIA Container Toolkit → รัน nvidia-ctk runtime configure → restart daemon ด้วย systemctl restart docker

ทดสอบให้ชัวร์ด้วย docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi ถ้าเห็นข้อมูลการ์ดจอแสดงจากภายใน container แปลว่าตั้งค่าสำเร็จเรียบร้อยแล้ว พร้อมรัน workload ที่ต้องใช้ GPU จริงจังได้ทันที ไม่ว่าจะเป็นงาน machine learning หรือ workload ประมวลผลหนักอื่นๆ

Leave a Comment