Fikirkan dengan teliti sebelum menggunakan Docker-in-Docker untuk CI atau persekitaran ujian

Fikirkan dengan teliti sebelum menggunakan Docker-in-Docker untuk CI atau persekitaran ujian

Docker-in-Docker ialah persekitaran daemon Docker maya yang berjalan dalam bekas itu sendiri untuk membina imej kontena. Tujuan utama mencipta Docker-in-Docker adalah untuk membantu membangunkan Docker itu sendiri. Ramai orang menggunakannya untuk menjalankan Jenkins CI. Ini kelihatan biasa pada mulanya, tetapi kemudian timbul masalah yang boleh dielakkan dengan memasang Docker dalam bekas Jenkins CI. Artikel ini memberitahu anda cara melakukan ini. Jika anda berminat dengan penyelesaian akhir tanpa butiran, cuma baca bahagian terakhir artikel, "Menyelesaikan Masalah."

Fikirkan dengan teliti sebelum menggunakan Docker-in-Docker untuk CI atau persekitaran ujian

Docker-in-Docker: "Baik"

Lebih daripada dua tahun lalu saya dimasukkan ke dalam Docker bendera – istimewa dan menulis versi pertama dind. Matlamatnya adalah untuk membantu pasukan teras membangunkan Docker dengan lebih pantas. Sebelum Docker-in-Docker, kitaran pembangunan biasa kelihatan seperti ini:

  • hackity hack;
  • membina;
  • menghentikan daemon Docker yang sedang berjalan;
  • melancarkan daemon Docker baharu;
  • ujian;
  • ulangi kitaran.

Jika anda ingin membuat perhimpunan yang cantik dan boleh dihasilkan semula (iaitu, dalam bekas), maka ia menjadi lebih rumit:

  • hackity hack;
  • pastikan bahawa versi Docker yang berfungsi sedang berjalan;
  • bina Docker baharu dengan Docker lama;
  • hentikan daemon Docker;
  • mulakan daemon Docker baharu;
  • ujian;
  • hentikan daemon Docker baharu;
  • ulang.

Dengan kemunculan Docker-in-Docker, prosesnya menjadi lebih mudah:

  • hackity hack;
  • pemasangan + pelancaran dalam satu peringkat;
  • ulangi kitaran.

Bukankah lebih baik dengan cara ini?

Fikirkan dengan teliti sebelum menggunakan Docker-in-Docker untuk CI atau persekitaran ujian

Docker-in-Docker: "Teruk"

Walau bagaimanapun, bertentangan dengan kepercayaan popular, Docker-in-Docker bukanlah 100% bintang, kuda dan unicorn. Apa yang saya maksudkan ialah terdapat beberapa isu yang perlu diketahui oleh pembangun.

Salah satunya berkenaan dengan LSM (modul keselamatan Linux) seperti AppArmor dan SELinux: apabila menjalankan bekas, "Docker dalaman" mungkin cuba menggunakan profil keselamatan yang akan bercanggah atau mengelirukan "Docker luaran". Ini adalah masalah paling sukar untuk diselesaikan apabila cuba menggabungkan pelaksanaan asal bendera –privileged. Perubahan saya berjaya dan semua ujian akan lulus pada mesin Debian saya dan VM ujian Ubuntu, tetapi mereka akan ranap dan terbakar pada mesin Michael Crosby (dia mempunyai Fedora seperti yang saya ingat). Saya tidak ingat punca sebenar masalah itu, tetapi mungkin kerana Mike seorang yang bijak yang bekerja dengan SELINUX=enforce (saya menggunakan AppArmor) dan perubahan saya tidak mengambil kira profil SELinux.

Docker-in-Docker: "Jahat"

Isu kedua ialah dengan pemacu storan Docker. Apabila anda menjalankan Docker-in-Docker, Docker luaran berjalan di atas sistem fail biasa (EXT4, BTRFS, atau apa sahaja yang anda miliki) dan Docker dalaman berjalan di atas sistem copy-on-write (AUFS, BTRFS, Device Mapper , dsb.). , bergantung pada apa yang dikonfigurasikan untuk menggunakan Docker luaran). Ini mencipta banyak kombinasi yang tidak akan berfungsi. Contohnya, anda tidak akan dapat menjalankan AUFS di atas AUFS.

Jika anda menjalankan BTRFS di atas BTRFS, ia sepatutnya berfungsi pada mulanya, tetapi apabila terdapat subvolum bersarang, pemadaman subvolum induk akan gagal. Modul Device Mapper tidak mempunyai ruang nama, jadi jika berbilang kejadian Docker menjalankannya pada mesin yang sama, mereka semua akan dapat melihat (dan mempengaruhi) imej antara satu sama lain dan pada peranti sandaran kontena. Ini tidak baik.

Terdapat penyelesaian untuk menyelesaikan banyak masalah ini. Sebagai contoh, jika anda ingin menggunakan AUFS dalam Docker dalaman, cuma tukar folder /var/lib/docker ke dalam kelantangan dan anda akan baik-baik saja. Docker telah menambah beberapa ruang nama asas pada nama sasaran Device Mapper supaya jika berbilang panggilan Docker dijalankan pada mesin yang sama, mereka tidak akan memijak satu sama lain.

Walau bagaimanapun, persediaan sedemikian tidak sama sekali mudah, seperti yang dapat dilihat daripada ini Perkara dalam repositori dind di GitHub.

Docker-in-Docker: Ia menjadi lebih teruk

Bagaimana pula dengan binaan cache? Ini juga boleh menjadi agak sukar. Orang sering bertanya kepada saya "jika saya menjalankan Docker-in-Docker, bagaimanakah saya boleh menggunakan imej yang dihoskan pada hos saya dan bukannya menarik semuanya kembali ke Docker dalaman saya"?

Sesetengah orang yang berdaya usaha telah cuba mengikat /var/lib/docker daripada hos kepada bekas Docker-in-Docker. Kadangkala mereka berkongsi /var/lib/docker dengan berbilang bekas.

Fikirkan dengan teliti sebelum menggunakan Docker-in-Docker untuk CI atau persekitaran ujian
Adakah anda mahu merosakkan data anda? Kerana inilah yang akan merosakkan data anda!

Daemon Docker direka dengan jelas untuk mempunyai akses eksklusif ke /var/lib/docker. Tiada apa-apa lagi yang harus "menyentuh, mencucuk, atau mendorong" mana-mana fail Docker yang terdapat dalam folder ini.

Kenapa jadi begini? Kerana ini adalah hasil daripada salah satu pelajaran yang paling sukar dipelajari semasa membangunkan dotCloud. Enjin kontena dotCloud berjalan dengan mempunyai berbilang proses mengakses /var/lib/dotcloud secara serentak. Helah licik seperti penggantian fail atom (bukan pengeditan di tempat), kod lada dengan kunci nasihat dan mandatori, dan eksperimen lain dengan sistem selamat seperti SQLite dan BDB tidak selalu berfungsi. Apabila kami mereka bentuk semula enjin kontena kami, yang akhirnya menjadi Docker, salah satu keputusan reka bentuk yang besar adalah untuk menyatukan semua operasi kontena di bawah satu daemon untuk menghapuskan semua karut serentak.

Jangan salah faham: adalah mustahil untuk membuat sesuatu yang baik, boleh dipercayai dan pantas yang melibatkan pelbagai proses dan kawalan selari moden. Tetapi kami fikir ia lebih mudah dan lebih mudah untuk menulis dan mengekalkan kod menggunakan Docker sebagai satu-satunya pemain.

Ini bermakna jika anda berkongsi direktori /var/lib/docker antara berbilang contoh Docker, anda akan menghadapi masalah. Sudah tentu, ini boleh berfungsi, terutamanya pada peringkat awal ujian. "Dengar, Ma, saya boleh menjalankan ubuntu sebagai buruh pelabuhan!" Tetapi cuba sesuatu yang lebih kompleks, seperti menarik imej yang sama daripada dua keadaan berbeza, dan anda akan melihat dunia terbakar.

Ini bermakna jika sistem CI anda melakukan binaan dan binaan semula, setiap kali anda memulakan semula bekas Docker-in-Docker anda, anda berisiko menjatuhkan nuke ke dalam cachenya. Ini tidak keren sama sekali!

Penyelesaian

Mari kita berundur selangkah. Adakah anda benar-benar memerlukan Docker-in-Docker atau adakah anda hanya mahu dapat menjalankan Docker dan membina serta menjalankan bekas dan imej daripada sistem CI anda semasa sistem CI itu sendiri berada dalam bekas?

Saya yakin kebanyakan orang mahukan pilihan terakhir, bermakna mereka mahu sistem CI seperti Jenkins dapat menjalankan kontena. Dan cara paling mudah untuk melakukan ini ialah dengan hanya memasukkan soket Docker ke dalam bekas CI anda dan mengaitkannya dengan bendera -v.

Ringkasnya, apabila anda menjalankan bekas CI anda (Jenkins atau lain-lain), bukannya menggodam sesuatu bersama-sama dengan Docker-in-Docker, mulakannya dengan baris:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

Bekas ini kini akan mempunyai akses kepada soket Docker dan oleh itu boleh menjalankan bekas. Kecuali daripada menjalankan bekas "kanak-kanak", ia akan melancarkan bekas "adik-beradik".

Cuba ini menggunakan imej docker rasmi (yang mengandungi binari Docker):

docker run -v /var/run/docker.sock:/var/run/docker.sock 
           -ti docker

Ia kelihatan dan berfungsi seperti Docker-in-Docker, tetapi ia bukan Docker-in-Docker: apabila bekas ini mencipta bekas tambahan, ia akan dibuat dalam Docker peringkat atas. Anda tidak akan mengalami kesan sampingan bersarang dan cache pemasangan akan dikongsi merentas berbilang panggilan.

Nota: Versi sebelumnya artikel ini dinasihatkan untuk memautkan binari Docker daripada hos ke bekas. Ini kini menjadi tidak boleh dipercayai kerana enjin Docker tidak lagi meliputi perpustakaan statik atau hampir statik.

Jadi, jika anda ingin menggunakan Docker dari Jenkins CI, anda mempunyai 2 pilihan:
memasang CLI Docker menggunakan sistem pembungkusan imej asas (iaitu jika imej anda berdasarkan Debian, gunakan pakej .deb), menggunakan API Docker.

Beberapa iklan πŸ™‚

Terima kasih kerana tinggal bersama kami. Adakah anda suka artikel kami? Ingin melihat kandungan yang lebih menarik? Sokong kami dengan membuat pesanan atau mengesyorkan kepada rakan, cloud VPS untuk pembangun dari $4.99, analog unik pelayan peringkat permulaan, yang kami cipta untuk anda: Keseluruhan kebenaran tentang VPS (KVM) E5-2697 v3 (6 Teras) 10GB DDR4 480GB SSD 1Gbps daripada $19 atau bagaimana untuk berkongsi pelayan? (tersedia dengan RAID1 dan RAID10, sehingga 24 teras dan sehingga 40GB DDR4).

Dell R730xd 2 kali lebih murah di pusat data Equinix Tier IV di Amsterdam? Hanya disini 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV daripada $199 di Belanda! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - daripada $99! Baca tentang Bagaimana untuk membina infrastruktur corp. kelas dengan penggunaan pelayan Dell R730xd E5-2650 v4 bernilai 9000 euro untuk satu sen?

Sumber: www.habr.com

Tambah komen