Run docker ใน docker ห๊ะ!?
เรื่องมันเริ่มจาก ผม run Jekins ใน docker แล้วพอจะให้ Jenkins compile go ผม ก็ไม่อยากลง go ใน Jenkins container เพราะอยากให้แต่ละ container ทำอย่างละเรื่องน่าจะดีกว่า
คิดได้ดังนี้ก็เริ่มหาวิธี run docker ใน docker เริ่มจาก
ลง docker ใน Jenkins ก่อน
ลองเช็คดูจะเห็นว่าใน container ของ Jenkins มีคำสั่ง docker ละ
/var/run/docker.sock
จาก implementation ของ Docker การ runคำสั่ง docker
ข้างใน docker container จะเจอปัญหา low level technical เยอะมาก ซึ่งสามารถอ่านรายละเอียดเพิ่มเติมได้จากบล็อก ~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.
วิธีที่ดีกว่าคือการให้ข้างใน container มีแต่คำสั่ง docker
แต่ไม่มี docker daemon run อยู่ เราจะใช้ docker daemon จาก host นี่แหละ ซึ่งเราสามารถทำสิ่งนั้นได้โดยการ mount /var/run/docker.sock
เข้าไปใน container แค่นี้ เวลาเราสั่ง docker run
จากใน container ก็จะเหมือนเราสั่ง docker run
จากเครื่อง host เลย
ทำไมต้องใช้ root?
เนื่องจาก user jenkins
ไม่มีสิทธิ์ access /var/run/docker.sock
ทางออกก็จะมี 1. run ด้วย root
หรือไม่ก็ 2. add user jenkins
ใส่ group docker
และใช้ option--privileged
ตอน run ผมเลือกไปท่า 1 เพราะความมักง่าย :P
เท่านี้เราก็สามารถ run docker ข้างใน docker ได้แล้ว
จากรูป จะเห็นว่า docker ps
ที่เครื่อง host จะเห็น container ที่เรา run จากใน Jenkins ราวกับว่าเรา run คำสั่ง docker
ที่เครื่อง host เลย เป็นเพราะเราใช้ daemon ของเครื่อง host นั่นเอง
มาดูสรุปใน docker-compose file กัน
เท่านี้ใน Jenkins เราก็สามารถสั่งคำสั่ง docker ได้เลย ไม่ต้องไปลงพวก node หรือ go ใน Jenkins ได้แล้ว
คำเตือน: เวลา mount path ต้อง mount จาก path ของเครื่อง host นะ
เนื่องจากจริง ๆ แล้วเราใช้ docker daemon จากเครื่อง host เวลาเราใช้ option -v
เพื่อ mount path ใน Jenkins (ที่อยู่ใน docker) เราต้องใช้ path ของเครื่อง host แทนนะ เพราะจริง ๆ ตัว daemon อยู่ที่เครื่อง host