Добра падумайце, перш чым выкарыстоўваць Docker-in-Docker для CI або тэставай асяроддзя

Добра падумайце, перш чым выкарыстоўваць Docker-in-Docker для CI або тэставай асяроддзя

Docker-in-Docker уяўляе сабой віртуалізаванае асяроддзе Docker-дэман, запушчанае ў самым кантэйнеры для зборкі выяў кантэйнера. Асноўнай мэтай стварэння Docker-in-Docker была дапамога ў распрацоўцы самога Docker. Многія людзі выкарыстоўваюць яго для запуску Jenkins CI. Спачатку гэта здаецца нармальным, але затым узнікаюць праблемы, якіх можна пазбегнуць, усталяваўшы Docker у кантэйнер Jenkins CI. У гэтым артыкуле расказваецца, як гэта зрабіць. Калі вас цікавіць выніковае рашэнне без падрабязнасцей, проста прачытайце апошні раздзел артыкула «Рашэнне праблемы».

Добра падумайце, перш чым выкарыстоўваць Docker-in-Docker для CI або тэставай асяроддзя

Docker-in-Docker: "Добры"

Больш за два гады таму я ўставіў у Docker сцяг –privileged і напісаў першую версію dind. Мэта складалася ў тым, каб дапамагчы асноўнай камандзе хутчэй распрацоўваць Docker. Да з'яўлення Docker-in-Docker тыповы цыкл распрацоўкі быў такім:

  • hackity hack;
  • зборка (build);
  • прыпынак запушчанага Docker-дэман;
  • запуск новага Docker-дэман;
  • тэсціраванне;
  • паўтор цыклу.

Калі ж вы жадалі зрабіць прыгожую, якая прайграваецца зборку (гэта значыць у кантэйнеры), то яна станавілася больш мудрагелістай:

  • hackity hack;
  • пераканацца ў тым, што запушчана працаздольная версія Docker;
  • сабраць новы Docker са старым Docker;
  • спыніць Docker-дэман;
  • запусціць новы Docker-дэман;
  • пратэставаць;
  • спыніць новы Docker-дэман;
  • паўтарыць.

Са з'яўленнем Docker-in-Docker працэс спрасціўся:

  • hackity hack;
  • зборка + запуск у адзін этап;
  • паўтор цыклу.

Ці не праўда, дык значна лепш?

Добра падумайце, перш чым выкарыстоўваць Docker-in-Docker для CI або тэставай асяроддзя

Docker-in-Docker: «Дрэнны»

Аднак, насуперак распаўсюджанаму меркаванню, Docker-in-Docker не складаецца на 100% з зорачак, поні і аднарогаў. Я маю на ўвазе, што існуе некалькі праблем, пра якія распрацоўшчыку трэба ведаць.

Адна з іх дакранаецца LSM (модуляў бяспекі Linux), такіх як AppArmor і SELinux: пры запуску кантэйнера "ўнутраны Docker" можа паспрабаваць прымяніць профілі бяспекі, якія будуць канфліктаваць або заблытваць "вонкавы Docker". Гэта самая складаная праблема, якую трэба было вырашыць пры спробе аб'яднаць зыходную рэалізацыю сцяга -privileged. Мае змены працавалі, і ўсе тэсты таксама б прайшлі на маёй машыне Debian і тэставых віртуальных машынах Ubuntu, але яны б абрынуліся і згарэлі на машыне Майкла Кросбі (наколькі я памятаю, у яго была Fedora). Я не магу ўспомніць дакладны чыннік праблемы, але магчыма, яна ўзнікала таму, што Майк - мудры чалавек, які працуе з SELINUX=enforce (я выкарыстаў AppArmor), і мае змены не ўлічвалі профілі SELinux.

Docker-in-Docker: "Злы"

Другая праблема злучана з драйверамі сховішчы Docker. Калі вы запускаеце Docker-in-Docker, вонкавы Docker працуе па-над звычайнай файлавай сістэмай (EXT4, BTRFS або любой іншай, якой вы размяшчаеце), а ўнутраны Docker працуе па-над сістэмай капіявання пры запісе (AUFS, BTRFS, Device Mapper і т. д. , у залежнасці ад таго, што настроены выкарыстоўваць знешні Docker). Пры гэтым узнікае мноства камбінацый, якія не будуць працаваць. Напрыклад, вы не зможаце запускаць AUFS па-над AUFS.

Калі вы запускаеце BTRFS па-над BTRFS, спачатку гэта павінна працаваць, але як толькі з'явяцца ўкладзеныя падраздзелы, выдаліць бацькоўскі падраздзел parent subvolume не атрымаецца. Модуль Device Mapper не мае прасторы імёнаў, таму, калі некалькі асобнікаў Docker выкарыстаюць яго на адной машыне, усе яны змогуць бачыць (і ўплываць) на выявы сябар на сябра і на прылады рэзервовага капіявання кантэйнераў. Гэта дрэнна.

Ёсць абыходныя шляхі для вырашэння многіх з гэтых праблем. Напрыклад, калі вы жадаеце выкарыстоўваць AUFS ва ўнутраным Docker, проста ператворыце тэчку /var/lib/docker у тым, і ўсё будзе ў парадку. Docker дадаў некаторыя базавыя прасторы імёнаў да мэтавых імёнаў Device Mapper, так што калі некалькі выклікаў Docker будуць выконвацца на адной машыне, яны не стануць "наступаць" сябар на сябра.

Тым не менш, такая настройка зусім не простая, як можна ўбачыць з гэтых артыкулаў у рэпазітары dind на GitHub.

Docker-in-Docker: становіцца яшчэ горш

А як наконт кэша зборкі? Гэта таксама можа быць дастаткова складана. Людзі часта пытаюцца мяне "калі я запускаю Docker-in-Docker, як я магу выкарыстоўваць вобразы, размешчаныя на маім хасце, замест таго, каб зноў выцягваць усё ў маім унутраным Docker"?

Некаторыя прадпрымальныя людзі спрабавалі прывязаць /var/lib/docker з хаста ў кантэйнер Docker-in-Docker. Часам яны сумесна выкарыстоўваюць /var/lib/docker з некалькімі кантэйнерамі.

Добра падумайце, перш чым выкарыстоўваць Docker-in-Docker для CI або тэставай асяроддзя
Жадаеце пашкодзіць дадзеныя? Таму што гэта менавіта тое, што пашкодзіць вашыя дадзеныя!

Docker-дэман відавочна быў распрацаваны для таго, каб мець эксклюзіўны доступ да /var/lib/docker. Нішто іншае не павінна "тычыцца, тыкаць або мацаць" любыя файлы Docker, змешчаныя ў гэтай тэчцы.

Чаму гэта так? Таму што гэта вынік аднаго з самых складаных урокаў, атрыманых пры распрацоўцы dotCloud. Кантэйнерны рухавічок dotCloud працаваў, маючы некалькі працэсаў, адначасова якія звяртаюцца да /var/lib/dotcloud. Хітрыя трукі, такія як атамарная замена файлаў (замест рэдагавання на месцы), перчэнне кода рэкамендацыйнымі і абавязковымі блакіроўкамі і іншыя эксперыменты з бяспечнымі сістэмамі, такімі як SQLite і BDB, спрацоўвалі не заўсёды. Калі мы перараблялі наш кантэйнерны рухавічок, які ў канчатковым выніку ператварыўся ў Docker, адным з галоўных дызайнерскіх рашэнняў было сабраць усе аперацыі з кантэйнерамі пад адзіным дэманам, каб скончыць з усёй гэтай лухтой адначасовага доступу.

Не зразумейце мяне няправільна: цалкам магчыма зрабіць нешта добрае, надзейнае і хуткае, што будзе складацца з некалькіх працэсаў і сучаснае раўналежнае кіраванне. Але мы думаем, што прасцей і лягчэй пісаць і падтрымліваць код, выкарыстоўваючы Docker у якасці адзінага гульца.

Гэта азначае, што калі вы падзяляеце каталог /var/lib/docker паміж некалькімі асобнікамі Docker, у вас будуць праблемы. Вядома, гэта можа спрацаваць, асабліва на ранніх стадыях тэсціравання. "Слухай, Ма, я магу "докерам" запусціць ubuntu!" Але паспрабуйце зрабіць нешта больш складанае, напрыклад, выцягнуць адну і тую ж выяву з двух розных асобнікаў, і вы ўбачыце, як палае свет.

Гэта азначае, што калі ваша сістэма CI выконвае зборкі і перазборкі, то кожны раз пры перазапуску кантэйнера Docker-in-Docker вы рызыкуеце скінуць у яго кэш ядзерную бомбу. Гэта зусім не крута!

Рашэнне праблемы

Давайце зробім крок назад. Вам сапраўды патрэбен Docker-in-Docker ці вы проста хочаце мець магчымасць запускаць Docker, а менавіта збіраць і запускаць кантэйнеры і вобразы з вашай сістэмы CI, у той час як сама гэтая сістэма CI знаходзіцца ў кантэйнеры?

Іду ў заклад, што большасці людзей патрэбен апошні варыянт, гэта значыць яны жадаюць, каб сістэма CI, такая як Jenkins, магла запускаць кантэйнеры. І самы просты спосаб зрабіць гэта - проста ўставіць сокет Docker у ваш CI-кантэйнер, звязаўшы яго са сцягам -v.

Прасцей кажучы, калі вы запускаеце свой CI-кантэйнер (Jenkins ці іншы), замест таго, каб узломваць нешта разам з Docker-in-Docker, пачніце яго з радка:

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

Цяпер гэты кантэйнер будзе мець доступ да сокету Docker і, такім чынам, зможа запускаць кантэйнеры. За выключэннем таго, што замест запуску "даччыных" кантэйнераў ён будзе запускаць "роднасныя" кантэйнеры.

Паспрабуйце гэта, выкарыстоўваючы афіцыйную выяву docker (які змяшчае двайковы файл Docker):

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

Гэта выглядае і працуе як Docker-in-Docker, але гэта не Docker-in-Docker: калі гэты кантэйнер будзе ствараць дадатковыя кантэйнеры, яны будуць створаны ў Docker вышэйшага ўзроўню. Вы не будзеце адчуваць пабочных эфектаў укладзенасці, і кэш зборкі будзе сумесна выкарыстоўвацца для некалькіх выклікаў.

Заўвага: папярэднія версіі гэтага артыкула раілі прывязаць двайковы файл Docker ад хаста да кантэйнера. Цяпер гэта стала ненадзейным, бо механізм Docker больш не распаўсюджваецца на статычныя ці амаль статычныя бібліятэкі.

Такім чынам, калі вы хочаце выкарыстоўваць Docker з Jenkins CI, у вас ёсць 2 варыянты:
усталёўка Docker CLI з выкарыстаннем базавай сістэмы пакавання выявы (т. е. калі ваша выява заснаваны на Debian, выкарыстайце пакеты .deb), выкарыстанне Docker API.

Крыху рэкламы 🙂

Дзякуй, што застаяцеся з намі. Вам падабаюцца нашыя артыкулы? Жадаеце бачыць больш цікавых матэрыялаў? Падтрымайце нас, аформіўшы замову ці парэкамендаваўшы знаёмым, хмарныя VPS для распрацоўшчыкаў ад $4.99, унікальны аналаг entry-level сервераў, які быў прыдуманы намі для Вас: Уся праўда аб VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps ад $19 ці як правільна дзяліць сервер? (даступныя варыянты з RAID1 і RAID10, да 24 ядраў і да 40GB DDR4).

Dell R730xd у 2 разы танней у дата-цэнтры Equinix Tier IV у Амстэрдаме? Толькі ў нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТБ ад $199 у Нідэрландах! Dell R420 – 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB – ад $99! Чытайце аб тым Як пабудаваць інфраструктуру корп. класа c ужываннем сервераў Dell R730xd Е5-2650 v4 коштам 9000 еўра за капейкі?

Крыніца: habr.com

Дадаць каментар