+2

Series Phỏng vấn Jenkins Thực chiến #2: Cạm bẫy "Cá mập nuốt cá mập" (DinD vs DooD)

1. Câu hỏi từ Nhà tuyển dụng

"Tôi thấy hệ thống CI/CD của dự án đang chạy Jenkins dưới dạng một Docker Container. Tuy nhiên, trong Jenkinsfile, bạn lại dùng lệnh docker build để đóng gói các service Golang. Bạn hãy giải thích cơ chế để một container Jenkins có thể gọi được lệnh Docker? Sự khác biệt giữa DinD (Docker-in-Docker) và DooD (Docker-out-of-Docker) là gì, và tại sao bạn lại chọn DooD?"

2. Phân tích tâm lý Nhà tuyển dụng

Câu hỏi này dùng để loại bỏ những ứng viên "copy-paste". Rất nhiều người lên mạng copy đoạn code docker-compose.yml về chạy thấy thành công nhưng không hiểu bản chất bên dưới. Nhà tuyển dụng muốn kiểm tra:

  • Sự am hiểu về kiến trúc Linux Socket.
  • Tư duy tối ưu hóa hiệu năng (Caching) khi build các ngôn ngữ biên dịch.
  • Nhận thức về rủi ro bảo mật hệ thống (Security vulnerabilities).

3. Cách trả lời ghi điểm tuyệt đối (Mẫu tham khảo)

Hãy chia câu trả lời thành 3 lớp phân tích để chứng minh sự hiểu biết tường tận của một kỹ sư hệ thống:

Cấp độ 1: Giải thích cơ chế cốt lõi (Phân biệt DinD và DooD)

"Để một container Jenkins gọi được lệnh Docker, chúng ta có hai trường phái thiết kế là DinD và DooD.

  • DinD (Docker-in-Docker): Là việc ta cài đặt một lõi Docker Engine (Daemon) hoàn toàn mới nằm trọn bên trong container Jenkins. Khi đó, Jenkins sẽ tự quản lý các container con của riêng nó, hoàn toàn cách ly với máy chủ vật lý bên ngoài.
  • DooD (Docker-out-of-Docker): Thay vì chạy lõi mới, ta chỉ cài phần công cụ dòng lệnh (Docker CLI) vào Jenkins. Sau đó, ta khoét một đường ống giao tiếp bằng cách mount file socket của máy chủ vật lý vào container (-v /var/run/docker.sock:/var/run/docker.sock). Khi Jenkins gõ lệnh docker build, lệnh này thực chất được truyền qua ống socket và do Docker Engine của máy chủ vật lý xử lý."

Cấp độ 2: Lập luận lựa chọn DooD cho dự án (Tư duy thực chiến)

"Trong dự án triển khai các Microservices Golang, em kiên quyết lựa chọn DooD thay vì DinD vì hai lý do sống còn:

  1. Hiệu năng và Caching: Khi build code Golang bằng Multi-stage, việc tận dụng Layer Cache của Docker là cực kỳ quan trọng để giảm thời gian build từ vài phút xuống còn vài giây. Nếu dùng DinD, bộ cache này nằm chết trong container Jenkins và rất dễ bị mất. Với DooD, mọi Image và Cache đều nằm trên máy chủ vật lý, giúp chia sẻ cache tài nguyên hiệu quả hơn rất nhiều.
  2. Bảo mật: Để chạy được DinD, container Jenkins bắt buộc phải được cấp quyền --privileged. Việc cấp đặc quyền cao nhất này cho một hệ thống CI/CD (nơi liên tục chạy các đoạn code từ bên ngoài) là một lỗ hổng bảo mật nghiêm trọng. Nếu hacker chiếm quyền Jenkins, họ có thể thao túng toàn bộ phần cứng máy chủ. DooD tuy vẫn mang rủi ro root qua socket, nhưng bề mặt tấn công hẹp hơn nhiều so với việc mở toang cửa bằng cờ privileged."

Cấp độ 3: Góc nhìn "Bắt bệnh" (Kinh nghiệm xương máu)

"Tuy nhiên, khi triển khai DooD trong thực tế, em thường phải xử lý một rào cản kỹ thuật là lỗi Permission denied khi Jenkins cố gắng truy cập file docker.sock. Nguyên nhân do file socket này thuộc sở hữu của user root trên host, trong khi Jenkins chạy dưới quyền user jenkins (UID 1000). Để giải quyết bài toán này một cách chuẩn mực và an toàn, em sẽ tạo một group docker trong Dockerfile của Jenkins và cấp quyền cho user jenkins vào group đó, thay vì dùng cách 'chữa cháy' nguy hiểm là chmod 777 file socket."

4. Góc nhỏ "Bắt bẻ" (Nhà tuyển dụng phản đòn)

Nếu bạn nêu bật vấn đề bảo mật của file socket, Interviewer có thể dồn tiếp một câu:

  • Interviewer vặn lại: "Bạn nói DooD an toàn hơn DinD. Nhưng nếu user Jenkins có quyền truy cập vào docker.sock, họ hoàn toàn có thể chạy một lệnh docker run -v /:/host-root ubuntu để mount toàn bộ ổ cứng máy chủ vào một container tạm, từ đó chiếm quyền root máy chủ. Vậy DooD đâu có thực sự an toàn?"
  • Cách bạn "đỡ đòn": "Chính xác, việc phơi bày docker.sock vẫn tiềm ẩn rủi ro chiếm quyền (Privilege Escalation). Đó là lý do trong kiến trúc Enterprise thực sự, em sẽ không cho phép Jenkins Master chạy bất kỳ tác vụ build nào. Jenkins Master sẽ bị cô lập hoàn toàn. Khi cần build code, Jenkins Master sẽ dùng Docker Agent (hoặc Kubernetes Pod) cấp phát động (Dynamic Provisioning) qua giao thức TCP có mã hóa TLS thay vì dùng chung socket nội bộ. Những Agent ảo này chỉ tồn tại trong vài phút để build code rồi tự hủy, từ đó chặn đứng triệt để nguy cơ leo thang đặc quyền."

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí