Cách tôi chạy Docker bên trong Docker và kết quả của nó

Chào mọi người! Trong của anh ấy bài viết trước, Tôi đã hứa sẽ nói về việc chạy Docker trong Docker và các khía cạnh thực tế của việc sử dụng bài học này. Đã đến lúc phải giữ lời hứa. Một nhà phát triển có kinh nghiệm có thể sẽ phản đối rằng những người cần Docker bên trong Docker chỉ cần chuyển tiếp ổ cắm daemon Docker từ máy chủ vào vùng chứa và điều này là đủ trong 99% trường hợp. Nhưng đừng vội ném cookie vào tôi, vì chúng ta sẽ nói về việc thực sự chạy Docker bên trong Docker. Giải pháp này có nhiều ứng dụng khả thi và bài viết này là về một trong số đó, vì vậy hãy ngồi lại và duỗi thẳng tay trước mặt.

Cách tôi chạy Docker bên trong Docker và kết quả của nó

bắt đầu

Mọi chuyện bắt đầu vào một buổi tối mưa tháng 5 khi tôi đang vệ sinh chiếc máy tôi thuê với giá 24 đô la trên Digital Ocean, chiếc máy đã bị đóng băng do Docker đã lấp đầy toàn bộ XNUMX gigabyte dung lượng ổ đĩa có sẵn bằng hình ảnh và vùng chứa của nó. Điều trớ trêu là tất cả những hình ảnh và vùng chứa này đều tạm thời và chỉ cần để kiểm tra hiệu suất ứng dụng của tôi mỗi khi phiên bản mới của thư viện hoặc khung công tác được phát hành. Tôi đã thử viết các tập lệnh shell và thiết lập một lịch trình cron để dọn rác, nhưng điều đó không giúp ích gì: lần nào nó cũng kết thúc với việc dung lượng ổ đĩa máy chủ của tôi bị ngốn và máy chủ bị treo (tốt nhất là vậy). Tại một thời điểm nào đó, tôi tình cờ thấy một bài viết về cách chạy Jenkins trong một vùng chứa cũng như cách nó có thể tạo và xóa các đường dẫn xây dựng thông qua một ổ cắm docker daemon được chuyển tiếp vào đó. Tôi thích ý tưởng này, nhưng tôi quyết định tiến xa hơn và thử thử nghiệm chạy Docker trực tiếp bên trong Docker. Vào thời điểm đó, đối với tôi, có vẻ như đây là một giải pháp hoàn toàn hợp lý để tải xuống hình ảnh Docker và tạo vùng chứa cho tất cả các ứng dụng mà tôi cần để thử nghiệm bên trong một vùng chứa khác (hãy gọi nó là vùng chứa theo giai đoạn). Ý tưởng là bắt đầu một vùng chứa dàn với cờ -rm, cờ này sẽ tự động xóa toàn bộ vùng chứa và tất cả nội dung của nó khi nó bị dừng. Tôi đã sửa đổi hình ảnh Docker từ chính Docker (https://hub.docker.com/_/docker), nhưng hóa ra nó quá cồng kềnh và tôi chưa bao giờ làm cho nó hoạt động được theo cách tôi cần và tôi muốn tự mình đi hết con đường này.

Luyện tập. nón

Tôi bắt đầu làm cho thùng chứa hoạt động theo cách tôi cần và tiếp tục các thử nghiệm của mình, kết quả là tôi đã tạo ra vô số nụ. Kết quả của sự tự tra tấn của tôi là thuật toán sau:

  1. Chúng tôi khởi chạy vùng chứa Docker ở chế độ tương tác.

    docker run --privileged -it docker:18.09.6

    Hãy chú ý đến phiên bản của hộp đựng, bước sang phải hoặc sang trái và DinD của bạn sẽ biến thành quả bí ngô. Trên thực tế, mọi thứ thường xuyên xảy ra sự cố khi có phiên bản mới được phát hành.
    Chúng ta phải ngay lập tức vào trong vỏ.

  2. Chúng tôi đang cố gắng tìm ra vùng chứa nào đang chạy (Trả lời: không có), nhưng hãy chạy lệnh:

    docker ps

    Bạn sẽ hơi ngạc nhiên, nhưng hóa ra daemon Docker thậm chí còn không chạy:

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. Hãy tự mình chạy nó:

    dockerd &

    Một bất ngờ khó chịu khác:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. Cài đặt gói iptables và bash (mọi thứ trong bash sẽ dễ chịu hơn so với sh):

    apk add --no-cache iptables bash

  5. Hãy khởi chạy bash. Cuối cùng chúng ta đã trở lại với shell thông thường

  6. Hãy thử khởi chạy lại Docker:

    dockerd &

    Chúng ta sẽ thấy một bảng nhật ký dài kết thúc bằng:

    INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization          
    INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock

  7. Bấm phím Enter. Chúng ta đã quay trở lại trận đấu.

Từ giờ trở đi, chúng ta có thể thử khởi chạy các vùng chứa Docker khác bên trong vùng chứa Docker của mình, nhưng nếu chúng ta muốn khởi chạy một vùng chứa Docker khác bên trong vùng chứa Docker hoặc có sự cố xảy ra và vùng chứa đó gặp sự cố thì sao? Bắt đầu tất cả một lần nữa.

Sở hữu hộp chứa DinD và các thử nghiệm mới

Cách tôi chạy Docker bên trong Docker và kết quả của nó
Để tránh lặp đi lặp lại các bước trên, tôi đã tạo thùng chứa DinD của riêng mình:

https://github.com/alekslitvinenk/dind

Giải pháp DinD đang hoạt động đã cho tôi khả năng chạy đệ quy Docker bên trong Docker và thực hiện nhiều thử nghiệm mạo hiểm hơn.
Bây giờ tôi sẽ mô tả một thử nghiệm (thành công) như vậy khi chạy MySQL và Nodejs.
Người thiếu kiên nhẫn nhất có thể thấy nó như thế nào ở đây

Vì vậy, hãy bắt đầu:

  1. Chúng tôi khởi chạy DinD ở chế độ tương tác. Trong phiên bản DinD này, chúng tôi cần ánh xạ thủ công tất cả các cổng mà vùng chứa con của chúng tôi có thể sử dụng (Tôi đang nghiên cứu vấn đề này)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    Chúng ta bước vào bash, từ đó chúng ta có thể bắt đầu ngay lập tức khởi chạy các vùng chứa con.

  2. Khởi chạy MySQL:

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. Chúng tôi kết nối với cơ sở dữ liệu theo cách tương tự như cách chúng tôi kết nối cục bộ. Hãy đảm bảo mọi thứ đều hoạt động.

  4. Khởi chạy container thứ hai:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    Xin lưu ý rằng ánh xạ cổng sẽ chính xác 8080:8080, vì chúng tôi đã ánh xạ cổng 80 từ máy chủ sang vùng chứa chính tới cổng 8080.

  5. Chúng tôi truy cập localhost trong trình duyệt, đảm bảo rằng máy chủ phản hồi “Xin chào thế giới!”

Trong trường hợp của tôi, thử nghiệm với các vùng chứa Docker lồng nhau tỏ ra khá tích cực và tôi sẽ tiếp tục phát triển dự án và sử dụng nó để dàn dựng. Đối với tôi, có vẻ như đây là một giải pháp nhẹ nhàng hơn nhiều so với Kubernetes và Jenkins X. Nhưng đây là ý kiến ​​chủ quan của tôi.

Tôi nghĩ đó là tất cả cho bài viết hôm nay. Trong bài viết tiếp theo, tôi sẽ mô tả chi tiết hơn các thử nghiệm chạy Docker đệ quy trong Docker và gắn các thư mục sâu vào các vùng chứa lồng nhau.

PS Nếu bạn thấy dự án này hữu ích, vui lòng đánh dấu sao cho nó trên GitHub, phân nhánh nó và giới thiệu với bạn bè của bạn.

Edit1 Đã sửa lỗi, tập trung vào 2 video

Nguồn: www.habr.com

Thêm một lời nhận xét