ปัญหา
หลังเปลี่ยน /etc/docker/daemon.json แล้ว:
sudo systemctl restart docker
แต่บาง config ไม่ apply / container ค้าง / socket ใช้ไม่ได้
ทำไม? เพราะ Docker ไม่ใช่ unit เดียว — มี 2 unit ที่ทำงานคู่กัน
docker.service vs docker.socket
systemctl list-units --type=service,socket | grep docker
ผลลัพธ์:
docker.service loaded active running Docker Application Container Engine
docker.socket loaded active running Docker Socket for the API
docker.socket = systemd socket activation
- listen
/var/run/docker.sockตลอดเวลา - ทำหน้าที่ "เปิด socket" รอการเชื่อมต่อ
- ถ้ามีคน connect — start
docker.service
docker.service = ตัว Docker daemon (dockerd) จริง
- รัน container
- จัดการ image / network / volume
ความสัมพันธ์: docker.socket start ก่อน — รับ connection — กระตุ้น docker.service ขึ้นมา
ทำไมถึงสำคัญ
Case 1: restart docker.service อย่างเดียว
sudo systemctl restart docker.service
docker.serviceหยุด → start ใหม่docker.socketยังทำงานอยู่ — เก็บ pending connection- container restart ตาม restart policy
ใช้ได้ในกรณีปกติ
Case 2: ต้อง restart docker.socket ด้วย
ถ้าเปลี่ยน path ของ socket หรือ permission:
{
"hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
}
แค่ restart docker.service ไม่พอ — docker.socket ยัง bind path เดิม
ต้อง restart ทั้งคู่:
sudo systemctl restart docker.socket docker.service
Case 3: docker.service start ไม่ขึ้น
$ sudo systemctl start docker.service
Job for docker.service failed
ดู error:
sudo journalctl -u docker.service -n 50
อาจเห็น:
listen unix /var/run/docker.sock: bind: address already in use
→ socket ที่ docker.socket ถืออยู่ยังไม่ release — stop socket ก่อน:
sudo systemctl stop docker.service docker.socket
sudo systemctl start docker.socket docker.service
ลำดับสำคัญ — socket ก่อน service
คำสั่งที่ใช้บ่อย
Restart ทั้งคู่ (แนะนำเมื่อสงสัย)
sudo systemctl restart docker.socket docker.service
ดู status
sudo systemctl status docker.service
sudo systemctl status docker.socket
ดู log แต่ละ unit
sudo journalctl -u docker.service -f # daemon log
sudo journalctl -u docker.socket -f # socket log
Disable / Enable
# enable ตอน boot
sudo systemctl enable docker.service docker.socket
# disable
sudo systemctl disable docker.service docker.socket
เปลี่ยน Daemon Config — ขั้นตอนที่ปลอดภัย
# 1. แก้ไฟล์
sudo nano /etc/docker/daemon.json
# 2. ตรวจ JSON syntax
sudo dockerd --validate-config
# หรือ
cat /etc/docker/daemon.json | jq .
# 3. restart
sudo systemctl restart docker.service
# 4. ตรวจว่า apply
docker info | grep -E "Storage|Logging|Cgroup"
ถ้า config ผิด syntax — docker.service start ไม่ขึ้น
- ดู error:
sudo journalctl -u docker.service -n 30 - แก้ใน daemon.json — restart ใหม่
Container Restart Policy
ตอน Docker daemon restart — container จะ:
| Policy | พฤติกรรม |
|---|---|
| no (default) | ตายไปเลย ไม่ start อัตโนมัติ |
| on-failure | start ถ้า exit code != 0 |
| always | start ทุกครั้งที่ daemon up |
| unless-stopped | start ยกเว้น stop ด้วยมือก่อน |
production แนะนำ unless-stopped — บอก daemon ว่า "ครั้งหน้า up อะ start ตัวฉันด้วย"
ใน compose:
services:
app:
image: myapp
restart: unless-stopped
ปัญหา socket ที่เจอบ่อย
Permission denied
$ docker ps
permission denied while trying to connect to the Docker daemon socket
user ไม่อยู่ใน group docker:
sudo usermod -aG docker $USER
# logout-login ใหม่
หรือใช้ sudo:
sudo docker ps
Socket ไม่อยู่
$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
ตรวจ:
# socket ทำงานอยู่มั้ย
sudo systemctl status docker.socket
# ไฟล์ socket อยู่จริงมั้ย
ls -la /var/run/docker.sock
ถ้าไม่มี — start:
sudo systemctl start docker.socket docker.service
Hang ตอน restart
ถ้า container เยอะ — restart นานเพราะ daemon รอ container shutdown ทีละตัว
ดู progress:
sudo journalctl -u docker.service -f
ถ้า hang นานเกิน — force kill (ระวัง! ข้อมูล container ปัจจุบันอาจหาย):
sudo systemctl kill -s SIGKILL docker.service
sudo systemctl restart docker.service
เคสพิเศษ: เปลี่ยน data-root
ตอนย้าย Docker directory (อ่านเพิ่ม):
sudo systemctl stop docker.service docker.socket
# ย้ายข้อมูล + แก้ daemon.json
sudo systemctl start docker.socket docker.service
ถ้า restart docker.service อย่างเดียว — daemon ยังใช้ socket ที่ socket unit ถือ ไม่กระทบ — แต่ data-root อาจ apply ถูก
ที่ดีคือ restart ทั้งคู่ให้ clean
Rootless Docker
ถ้าใช้ rootless Docker — unit อยู่ใน user systemd:
systemctl --user status docker.service
systemctl --user restart docker.service
ไม่ต้องใช้ sudo
Containerd / Snap
ระบบที่ใช้ snap install Docker หรือใช้ containerd ตรงๆ — unit name ต่างไป:
# snap
sudo systemctl restart snap.docker.dockerd
# containerd
sudo systemctl restart containerd
ตรวจชื่อ unit ที่มีจริง:
systemctl list-units | grep -i docker
Cheat Sheet
# restart ปลอดภัย (ทุก scenario)
sudo systemctl restart docker.socket docker.service
# stop / start ตามลำดับ
sudo systemctl stop docker.service docker.socket
sudo systemctl start docker.socket docker.service
# enable ตอน boot
sudo systemctl enable docker.service docker.socket
# status
sudo systemctl status docker.service docker.socket
# log
sudo journalctl -u docker.service -n 50
sudo journalctl -u docker.socket -n 50
TLDR
docker.service= daemon รัน containerdocker.socket= listener ของ/var/run/docker.sock- ปกติ restart
docker.serviceพอ - เปลี่ยน path/permission ของ socket → restart ทั้งคู่
- สงสัยเมื่อไหร่ → restart ทั้งคู่ ปลอดภัยกว่า
สรุป
Docker บน Linux ใช้ systemd socket activation — มี 2 unit ที่ต้องรู้จัก
Pattern ที่จำง่าย: socket ก่อน service เวลา start และ service ก่อน socket เวลา stop (แต่จริงๆ systemctl handle ลำดับให้)
ถ้า restart แล้วยังพัง — ดู journalctl -u docker.service เกือบทุกครั้งบอก root cause ตรงๆ