Docker-in-Docker adalah lingkungan daemon Docker tervirtualisasi yang berjalan di dalam container itu sendiri untuk membuat image container. Tujuan utama pembuatan Docker-in-Docker adalah untuk membantu mengembangkan Docker itu sendiri. Banyak orang menggunakannya untuk menjalankan Jenkins CI. Ini tampak normal pada awalnya, tetapi kemudian muncul masalah yang dapat dihindari dengan menginstal Docker di container Jenkins CI. Artikel ini memberi tahu Anda cara melakukan ini. Jika Anda tertarik dengan solusi akhir tanpa rincian, baca saja bagian terakhir artikel, “Memecahkan Masalah.”
Docker-in-Docker: "Bagus"
Lebih dari dua tahun yang lalu saya memasukkan Docker
- peretasan peretasan;
- membangun;
- menghentikan daemon Docker yang sedang berjalan;
- meluncurkan daemon Docker baru;
- pengujian;
- ulangi siklusnya.
Jika Anda ingin membuat rakitan yang indah dan dapat direproduksi (yaitu, dalam wadah), maka prosesnya menjadi lebih rumit:
- peretasan peretasan;
- pastikan versi Docker yang berfungsi sedang berjalan;
- membangun Docker baru dengan Docker lama;
- hentikan daemon Docker;
- memulai daemon Docker baru;
- tes;
- hentikan daemon Docker baru;
- mengulang.
Dengan hadirnya Docker-in-Docker, prosesnya menjadi lebih sederhana:
- peretasan peretasan;
- perakitan + peluncuran dalam satu tahap;
- ulangi siklusnya.
Bukankah lebih baik begini?
Docker-in-Docker: "Buruk"
Namun, bertentangan dengan kepercayaan populer, Docker-in-Docker tidak 100% berupa bintang, kuda poni, dan unicorn. Yang saya maksud adalah ada beberapa masalah yang perlu diwaspadai oleh seorang pengembang.
Salah satunya menyangkut LSM (modul keamanan Linux) seperti AppArmor dan SELinux: saat menjalankan sebuah container, "Docker internal" mungkin mencoba menerapkan profil keamanan yang akan menimbulkan konflik atau membingungkan "Docker eksternal". Ini adalah masalah yang paling sulit dipecahkan ketika mencoba menggabungkan implementasi asli dari –privileged flag. Perubahan saya berhasil dan semua tes akan lulus pada mesin Debian saya dan VM pengujian Ubuntu, tetapi mereka akan crash dan terbakar pada mesin Michael Crosby (seingat saya dia punya Fedora). Saya tidak ingat persis penyebab masalahnya, tapi mungkin karena Mike adalah orang bijak yang bekerja dengan SELINUX=enforce (saya menggunakan AppArmor) dan perubahan saya tidak memperhitungkan profil SELinux.
Docker-in-Docker: "Jahat"
Masalah kedua adalah dengan driver penyimpanan Docker. Saat Anda menjalankan Docker-in-Docker, Docker eksternal berjalan di atas sistem file biasa (EXT4, BTRFS, atau apa pun yang Anda miliki) dan Docker internal berjalan di atas sistem copy-on-write (AUFS, BTRFS, Device Mapper , dll.). , tergantung pada apa yang dikonfigurasi untuk menggunakan Docker eksternal). Hal ini menciptakan banyak kombinasi yang tidak akan berhasil. Misalnya, Anda tidak akan dapat menjalankan AUFS di atas AUFS.
Jika Anda menjalankan BTRFS di atas BTRFS, ini akan berfungsi pada awalnya, tetapi setelah ada subvolume yang disarangkan, penghapusan subvolume induk akan gagal. Modul Device Mapper tidak memiliki namespace, jadi jika beberapa instance Docker menjalankannya di mesin yang sama, semuanya akan dapat melihat (dan memengaruhi) image satu sama lain dan pada perangkat cadangan container. Ini buruk.
Ada solusi untuk mengatasi banyak masalah ini. Misalnya, jika Anda ingin menggunakan AUFS di Docker internal, cukup ubah folder /var/lib/docker menjadi volume dan Anda akan baik-baik saja. Docker telah menambahkan beberapa namespace dasar ke nama target Device Mapper sehingga jika beberapa panggilan Docker berjalan di mesin yang sama, panggilan tersebut tidak akan saling menginjak.
Namun, pengaturan seperti itu sama sekali tidak sederhana, seperti terlihat pada gambar di bawah ini
Docker-in-Docker: Ini menjadi lebih buruk
Bagaimana dengan cache build? Ini juga bisa jadi cukup sulit. Orang sering bertanya kepada saya “jika saya menjalankan Docker-in-Docker, bagaimana saya bisa menggunakan gambar yang dihosting di host saya alih-alih menarik semuanya kembali ke Docker internal saya”?
Beberapa orang yang giat telah mencoba mengikat /var/lib/docker dari host ke container Docker-in-Docker. Terkadang mereka berbagi /var/lib/docker dengan banyak container.
Apakah Anda ingin merusak data Anda? Karena justru hal inilah yang akan merusak data Anda!
Daemon Docker jelas dirancang untuk memiliki akses eksklusif ke /var/lib/docker. Tidak ada lagi yang boleh "menyentuh, menyodok, atau menusuk" file Docker apa pun yang terletak di folder ini.
Mengapa demikian? Karena ini adalah hasil dari salah satu pelajaran tersulit yang didapat selama mengembangkan dotCloud. Mesin kontainer dotCloud dijalankan dengan memiliki beberapa proses yang mengakses /var/lib/dotcloud secara bersamaan. Trik licik seperti penggantian file atom (alih-alih mengedit di tempat), menambahkan kode dengan kunci penasehat dan wajib, dan eksperimen lain dengan sistem aman seperti SQLite dan BDB tidak selalu berhasil. Saat kami mendesain ulang mesin container kami, yang akhirnya menjadi Docker, salah satu keputusan desain besar adalah mengkonsolidasikan semua operasi container di bawah satu daemon untuk menghilangkan semua omong kosong konkurensi.
Jangan salah paham: sangat mungkin membuat sesuatu yang baik, andal, dan cepat yang melibatkan banyak proses dan kontrol paralel modern. Namun menurut kami lebih sederhana dan mudah untuk menulis dan memelihara kode menggunakan Docker sebagai satu-satunya pemain.
Artinya, jika Anda berbagi direktori /var/lib/docker di antara beberapa instance Docker, Anda akan mengalami masalah. Tentu saja ini bisa berhasil, terutama pada pengujian tahap awal. “Dengar, Bu, saya bisa menjalankan ubuntu sebagai buruh pelabuhan!” Namun cobalah sesuatu yang lebih kompleks, seperti mengambil gambar yang sama dari dua kejadian berbeda, dan Anda akan melihat dunia terbakar.
Artinya, jika sistem CI Anda melakukan pembangunan dan pembangunan kembali, setiap kali Anda memulai ulang kontainer Docker-in-Docker, Anda berisiko memasukkan nuklir ke dalam cache-nya. Ini sama sekali tidak keren!
Solusinya
Mari kita mundur selangkah. Apakah Anda benar-benar membutuhkan Docker-in-Docker atau Anda hanya ingin dapat menjalankan Docker dan membangun serta menjalankan container dan image dari sistem CI Anda saat sistem CI itu sendiri berada di dalam container?
Saya yakin kebanyakan orang menginginkan opsi terakhir, artinya mereka menginginkan sistem CI seperti Jenkins yang dapat menjalankan container. Dan cara termudah untuk melakukannya adalah dengan memasukkan soket Docker ke dalam wadah CI Anda dan mengaitkannya dengan flag -v.
Sederhananya, saat Anda menjalankan container CI (Jenkins atau lainnya), alih-alih meretas sesuatu bersama Docker-in-Docker, mulailah dengan baris:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
Kontainer ini sekarang akan memiliki akses ke soket Docker dan karenanya dapat menjalankan kontainer. Kecuali bahwa alih-alih menjalankan container “anak”, ia akan meluncurkan container “saudara”.
Coba ini menggunakan image buruh pelabuhan resmi (yang berisi biner Docker):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti docker
Ini terlihat dan berfungsi seperti Docker-in-Docker, tetapi bukan Docker-in-Docker: ketika kontainer ini membuat kontainer tambahan, kontainer tersebut akan dibuat di Docker tingkat atas. Anda tidak akan mengalami efek samping dari penyarangan dan cache perakitan akan dibagikan ke beberapa panggilan.
Catatan: Versi sebelumnya dari artikel ini menyarankan untuk menautkan biner Docker dari host ke container. Ini sekarang menjadi tidak dapat diandalkan karena mesin Docker tidak lagi mencakup perpustakaan statis atau hampir statis.
Jadi, jika Anda ingin menggunakan Docker dari Jenkins CI, Anda memiliki 2 pilihan:
menginstal Docker CLI menggunakan sistem pengemasan gambar dasar (yaitu jika gambar Anda didasarkan pada Debian, gunakan paket .deb), menggunakan Docker API.
Beberapa iklan 🙂
Terima kasih untuk tetap bersama kami. Apakah Anda menyukai artikel kami? Ingin melihat konten yang lebih menarik? Dukung kami dengan melakukan pemesanan atau merekomendasikan kepada teman,
Dell R730xd 2x lebih murah di pusat data Equinix Tier IV di Amsterdam? Hanya disini
Sumber: www.habr.com