Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

10 жніўня ў Слёрм стартаваў відэакурс па Docker, у якім мы разбіраем яго цалкам - ад асноўных абстракцый да параметраў сеткі.

У гэтым артыкуле пагаворым аб гісторыі з'яўлення Docker і яго асноўных абстракцыях: Image, Cli, Dockerfile. Лекцыя разлічана на пачаткоўцаў, таму ці наўрад будзе цікавая дасведчаным карыстачам. Тут не будзе крыві, апендыкса і глыбокага апускання. Самыя асновы.

Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

Што такое Docker

Паглядзім на вызначэнне Docker з Вікіпедыі.

Docker - гэта праграмнае забеспячэнне для аўтаматызацыі разгортвання і кіравання праграмамі ў асяроддзях з падтрымкай кантэйнерызацыі.

З гэтага азначэння нічога незразумела. Асабліва незразумела, што значыць "у асяроддзях з падтрымкай кантэйнерызацыі". Каб разабрацца, вернемся ў мінулае. Пачнём з эпохі, якую я ўмоўна называю «Маналітнай эрай».

Маналітная эра

Маналітная эра - гэта пачатак 2000-х, калі ўсе прыкладанні былі маналітнымі, з кучай залежнасцяў. Распрацоўка ішла доўга. Пры гэтым сервераў было не так шмат, мы ўсе іх ведалі па імёнах і маніторылі. Ёсць такое пацешнае параўнанне:

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

Сістэмы віртуалізацыі на базе гіпервізара

Пра сістэмы віртуалізацыі напэўна ўсё чулі: VMware, VirtualBox, Hyper-V, Qemu KVM і т. д. Яны забяспечваюць ізаляцыю прыкладанняў і кіраванне рэсурсамі, але ў іх ёсць і мінусы. Каб зрабіць віртуалізацыю, патрэбен гіпервізор. А гіпервізор - гэта аверхед рэсурсаў. Ды і сама віртуальная машына звычайна цэлая махіна – цяжкая выява, на ім аперацыйная сістэма, Nginx, Apache, магчыма і MySQL. Выява вялікай, віртуальнай машынай няёмка аперыраваць. Як следства, праца з віртуалкамі можа быць маруднай. Каб вырашыць гэтую праблему, стварылі сістэмы віртуалізацыі на ўзроўні ядра.

Сістэмы віртуалізацыі на ўзроўні ядра

Віртуалізацыю на ўзроўні ядра падтрымліваюць сістэмы OpenVZ, Systemd-nspawn, LXC. Яркі прыклад такой віртуалізацыі – LXC (Linux Containers).

LXC - сістэма віртуалізацыі на ўзроўні аперацыйнай сістэмы для запуску некалькіх ізаляваных асобнікаў аперацыйнай сістэмы Linux на адным вузле. LXC не выкарыстоўвае віртуальныя машыны, а стварае віртуальнае асяроддзе з уласнай прасторай працэсаў і сеткавым стэкам.

Па сутнасці LXC стварае кантэйнеры. У чым розніца паміж віртуальнымі машынамі і кантэйнерамі?

Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

Кантэйнер не падыходзіць для ізалявання працэсаў: у сістэмах віртуалізацыі на ўзроўні ядра знаходзяць уразлівасці, якія дазваляюць вылезці з кантэйнера на хост. Таму калі вам трэба нешта ізаляваць, то лепш выкарыстоўваць віртуалку.

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

Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

"Жалезныя" гіпервізары - гэта крутая штука, калі вы сапраўды хочаце нешта ізаляваць. Бо там ёсць магчымасць ізаляваць на ўзроўні старонак памяці, працэсараў.

Ёсць гіпервізары як праграма, і ёсць кантэйнеры, пра іх мы і будзем казаць далей. У сістэмах кантэйнерызацыі гіпервізара няма, але ёсць Container Engine, які стварае кантэйнеры і кіруе імі. Штука гэта больш легкаважная, таму за кошт працы з ядром оверхед менш, ці яго няма зусім.

Што выкарыстоўваецца для кантэйнерызацыі на ўзроўні ядра

Асноўныя тэхналогіі, якія дазваляюць ствараць ізаляваны ад іншых працэсаў кантэйнер, - гэта Namespaces і Control Groups.

Namespaces: PID, Networking, Mount і User. Ёсць яшчэ, але для прастаты разумення спынімся на гэтых.

PID Namespace абмяжоўвае працэсы. Калі мы, напрыклад, ствараем PID Namespace, змяшчаем туды працэс, то ён становіцца з PID 1. Звычайна ў сістэмах PID 1 - гэта systemd або init. Адпаведна, калі мы змяшчаем працэс у новы namespace, ён таксама атрымлівае PID 1.

Networking Namespace дазваляе абмежаваць/ізаляваць сетку і ўсярэдзіне ўжо размяшчаць свае інтэрфейсы. Mount - гэта абмежаванне па файлавай сістэме. User – абмежаванне па карыстачах.

Control Groups: Memory, CPU, IOPS, Network – усяго каля 12 налад. Інакш іх яшчэ называюць Cgroups («Cі-групы»).

Control Groups кіруюць рэсурсамі для кантэйнера. Праз Control Groups мы можам сказаць, што кантэйнер не павінен спажываць больш нейкай колькасці рэсурсаў.

Каб кантэйнерызацыя паўнавартасна працавала, выкарыстоўваюцца дадатковыя тэхналогіі: Capabilities, Copy-on-write і іншыя.

Capabilities - гэта калі мы кажам працэсу, што ён можа рабіць, а чаго не можа. На ўзроўні ядра гэта проста бітавыя карты са мноствам параметраў. Напрыклад, карыстач root мае поўныя прывілеі, можа рабіць усё. Сервер часу можа змяняць сістэмны час: у яго есць capabilities на Time Capsule, і ўсё. З дапамогай прывілеяў можна гнутка наладзіць абмежаванні для працэсаў, і тым самым засцерагчы сябе.

Сістэма Copy-on-write дазваляе нам працаваць з выявамі Docker, выкарыстоўваць іх больш эфектыўна.

На дадзены момант Docker мае праблемы з сумяшчальнасцю Cgroups v2, таму ў артыкуле разглядаюцца менавіта Cgroups v1.

Але вернемся да гісторыі.

Калі з'явіліся сістэмы віртуалізацыі на ўзроўні ядра, іх пачалі актыўна прымяняць. Оверхед на гіпервізор знік, але некаторыя праблемы засталіся:

  • вялікія выявы: у тую ж OpenVZ штурхаюць аперацыёнку, бібліятэкі, кучу рознага софту, і ў выніку выява ўсё роўна атрымліваецца немаленькім;
  • няма звычайнага стандарту пакавання і дастаўкі, таму застаецца праблема залежнасцяў. Бываюць сітуацыі, калі два кавалкі кода выкарыстоўваюць адну бібліятэку, але з рознымі версіямі. Паміж імі магчымы канфлікт.

Каб усе гэтыя праблемы вырашыць, надышла наступная эра.

Эра кантэйнераў

Калі наступіла Эра кантэйнераў, змянілася філасофія працы з імі:

  • Адзін працэс - адзін кантэйнер.
  • Усе неабходныя працэсу залежнасці дастаўляем у яго кантэйнер. Гэта патрабуе распілоўваць маналіты на мікрасэрвісы.
  • Чым менш вобраз, тым лепш менш магчымых уразлівасцяў, хутчэй раскочваецца і гэтак далей.
  • Інстансы становяцца эфемернымі.

Памятайце, я казаў пра pets vs cattle? Раней інстансы былі падобныя да свойскіх жывёл, а цяпер сталі як cattle - быдла. Раней быў маналіт - адно прыкладанне. Цяпер гэта 100 мікрасэрвісаў, 100 кантэйнераў. У нейкіх кантэйнераў можа быць па 2-3 рэплікі. Нам становіцца не гэтак важна кантраляваць кожны кантэйнер. Нам хутчэй важная даступнасць самага сэрвісу: таго, што робіць гэты набор кантэйнераў. Гэта мяняе падыходы ў маніторынгу.

У 2014-2015 гадах здарыўся росквіт Docker – той тэхналогіі, пра якую мы і будзем зараз казаць.

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

У Docker-кантэйнер мы закладваем усё неабходнае, таму вырашаецца праблема залежнасцяў. Docker гарантуе ўзнаўляльнасць. Я думаю, многія сутыкаліся з невоспроизводимостью: у цябе ўсё працуе, пушыш на прадакшэн, там гэта перастае працаваць. З Docker гэтая праблема сыходзіць. Калі твой Docker-кантэйнер запускаецца і робіць тое, што патрабуецца рабіць, то з вялікай дзеллю верагоднасці ён запусціцца на прадакшэне і там зробіць тое ж самае.

Адступленне пра оверхед

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

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

Першае - гэта PID namespace. Калі мы ў namespace змяшчаем нейкі працэс, яму прысвойваецца PID 1. У той жа час у гэтага працэсу ёсць яшчэ адзін PID, які знаходзіцца на хаставым namespace, за межамі кантэйнера. Напрыклад, мы запусцілі ў кантэйнеры Nginx, ён стаў PID 1 (майстар-працэс). А на хасце ў яго PID 12623. І складана сказаць, наколькі гэта оверхед.

Другая штука – гэта Cgroups. Возьмем Cgroups па памяці, гэта значыць магчымасць абмяжоўваць кантэйнеру памяць. Пры яе ўключэнні актывуюцца лічыльнікі, memory accounting: ядру трэба разумець, колькі старонак выдзелена, а колькі яшчэ свабодна для гэтага кантэйнера. Гэта магчыма оверхед, але дакладных даследаванняў аб тым, як ён уплывае на прадукцыйнасць, я не сустракаў. І сам не заўважаў, што прыкладанне, запушчанае ў Docker, раптам рэзка губляла ў прадукцыйнасці.

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

Аб канцэпцыі Docker

Docker складаецца з некалькіх кампанентаў:

  1. Docker Daemon - тое самае Container Engine; запускае кантэйнеры.
  2. Docker CII - утыліта па кіраванні Docker.
  3. Dockerfile - інструкцыя па тым, як збіраць выяву.
  4. Image - выява, з якога раскочваецца кантэйнер.
  5. Кантэйнер.
  6. Docker registry - сховішча выяў.

Схематычна гэта выглядае прыкладна вось так:

Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

На Docker_host працуе Docker daemon, запускае кантэйнеры. Ёсць Client, які перадае каманды: зьбяры выяву, запампуй выяву, запусці кантэйнер. Docker daemon ходзіць у registry і выконвае іх. Docker-кліент можа звяртацца і лакальна (да юнікс-сокету), і па TCP з выдаленага хаста.

Пройдзем па кожным кампаненце.

Docker daemon (дэман) - Гэта серверная частка, яна працуе на хост-машыне: спампоўвае вобразы і запускае з іх кантэйнеры, стварае сетку паміж кантэйнерамі, збірае логі. Калі мы кажам "ствары вобраз", гэтым таксама займаецца дэман.

Докер CLI - кліенцкая частка Docker, кансольная ўтыліта для працы з дэманам. Паўтару, яна можа працаваць не толькі лакальна, але і па сетцы.

Базавыя каманды:

docker ps - паказаць кантэйнеры, якія зараз запушчаныя на Docker-хасце.
docker images - паказаць выявы, запампаваныя лакальна.
docker search <> - пошук выявы ў registry.
docker pull <> - спампаваць выяву з registry на машыну.
docker build < > - Сабраць выяву.
docker run <> - запуск кантэйнер.
docker rm <> - выдаліць кантэйнер.
docker logs <> - логі кантэйнера
docker start/stop/restart <> — праца з кантэйнерам

Калі вы асвоіце гэтыя каманды і будзеце ўпэўнена імі карыстацца, то лічыце, што на 70% асвоілі Docker на ўзроўні карыстача.

Докер-файл - інструкцыя для стварэння выявы. Амаль кожная каманда інструкцыі - новы пласт. Паглядзім на прыкладзе.

Што такое Docker: кароткі экскурс у гісторыю і асноўныя абстракцыі

Прыкладна так выглядае Dockerfile: злева каманды, справа - аргументы. Кожная каманда, што тут ёсць (і ўвогуле пішацца ў Dockerfile), стварае новы пласт у Image.

Нават гледзячы на ​​левую частку можна прыкладна зразумець, што адбываецца. Мы кажам: "ствары нам тэчку" - гэта адзін пласт. "Зрабі тэчку працоўнай" - гэта яшчэ адзін пласт, і гэтак далей. Плаццёны пірог спрашчае жыццё. Калі я ствару яшчэ адзін Dockerfile і ў апошнім радку штосьці зменю - запушчу не "python" "main.py", а што-небудзь іншае, або ўсталюю залежнасці з іншага файла - то папярэднія пласты будуць перавыкарыстаныя, як кэш.

малюнак - Гэта ўпакоўка кантэйнера, з выявы запускаюцца кантэйнеры. Калі глядзець на Docker з пункта гледжання пакетнага мэнэджара (як быццам мы працуем з deb або rpm-пакетамі), то image – гэта ў сутнасці rpm-пакет. Праз yum install мы можам паставіць дадатак, выдаліць яго, знайсці ў рэпазітары, спампаваць. Тут прыкладна тое ж самае: з выявы запускаюцца кантэйнеры, яны захоўваюцца ў Docker registry (па аналогіі з yum, у рэпазітары), і кожны image мае хэш SHA-256, імя і тэг.

Image збіраецца па інструкцыі з Dockerfile. Кожная інструкцыя з Dockerfile стварае новы пласт. Пласты могуць выкарыстоўвацца паўторна.

Docker registry - Гэта рэпазітар вобразаў Docker. Па аналогіі з АС, у Docker ёсць агульнадаступны стандартны рэестр – dockerhub. Але можна сабраць свой рэпазітар, свой Docker registry.

Кантэйнер - тое, што запускаецца з выявы. Па інструкцыі з Dockerfile сабралі выяву, затым мы яго з гэтай выявы запускаем. Гэты кантэйнер ізаляваны ад астатніх кантэйнераў, ён павінен утрымоўваць у сабе ўсё неабходнае для працы прыкладання. Пры гэтым адзін кантэйнер - адзін працэс. Здараецца, што даводзіцца рабіць два працэсы, але гэта некалькі супярэчыць ідэалогіі Docker.

Патрабаванне "адзін кантэйнер - адзін працэс" звязана з PID Namespace. Калі ў Namespace запускаецца працэс з PID 1, калі ён раптам памрэ, то ўвесь кантэйнер таксама памірае. Калі ж там запушчана два працэсы: адзін жыве, а другі памёр, то кантэйнер усё роўна працягне жыць. Але гэта да пытання Best Practices, мы пра іх пагаворым у іншых матэрыялах.

Больш дэталёва вывучыць асаблівасці і поўную праграму курса можна па спасылцы: «Відэакурс па Docker.

Аўтар: Марсэль Ібраеў, сертыфікаваны адміністратар Kubernetes, практыкуючы інжынер у кампаніі Southbridge, спікер і распрацоўшчык курсаў Слёрм.

Крыніца: habr.com

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