Удобно за начинаещи въведение в контейнери, виртуални машини и Docker

Ако сте програмист или техник, вероятно сте чували поне за Docker: полезен инструмент за опаковане, доставка и стартиране на приложения в „контейнери“. Трудно би било да не го направим, с цялото внимание, което получава в наши дни - както от разработчици, така и от системни администратори. Дори големите кучета като Google, VMware и Amazon изграждат услуги, които да го поддържат.

Независимо дали имате предвид непосредствения случай на използване на Docker, все още мисля, че е важно да разберем някои от основните понятия около това какво е „контейнер“ и как той се сравнява с виртуална машина (VM). Въпреки че Интернет е пълен с отлични ръководства за използване на Docker, не можах да намеря много лесни за начинаещи концептуални ръководства, особено за това от какво е съставен контейнерът. Така че, надявам се, тази публикация ще реши този проблем :)

Нека започнем, като разберем какви са дори виртуалните машини и контейнерите.

Какво представляват „контейнери“ и „виртуални машини“?

Контейнерите и виртуалните машини са сходни по своите цели: да изолират приложение и неговите зависимости в самостоятелна единица, която може да работи навсякъде.

Освен това контейнерите и виртуалните машини премахват необходимостта от физически хардуер, което позволява по-ефективно използване на изчислителните ресурси, както по отношение на енергопотреблението, така и на ефективността на разходите.

Основната разлика между контейнерите и виртуалните машини е в техния архитектурен подход. Нека да разгледаме отблизо.

Виртуални машини

VM по същество е емулация на реален компютър, който изпълнява програми като истински компютър. Виртуалните машини се изпълняват върху физическа машина, използвайки „хипервизор“ . Хипервизорът от своя страна работи или на хост машина, или на „гол метал“ .

Нека разопаковаме жаргона:

А хипервайзорна е парче от софтуер, фърмуер или хардуер, който виртуални машини работи над. Самите хипервизори работят на физически компютри, наричани „хост машина“ . Хост машината предоставя на виртуалните машини ресурси, включително RAM и CPU. Тези ресурси са разделени между виртуални машини и могат да бъдат разпределени, както сметнете за добре. Така че, ако една VM изпълнява по-тежко ресурсно приложение, може да разпределите повече ресурси за това, отколкото другите VM, работещи на същата хост машина.

Виртуалната машина, която се изпълнява на хост машината (отново с помощта на хипервизор), също често се нарича „машина за гости“. Тази машина за гости съдържа както приложението, така и всичко необходимо за стартирането му (напр. Системни двоични файлове и библиотеки). Той също така носи цял собствен виртуализиран хардуерен стек, включително виртуализирани мрежови адаптери, хранилище и процесор - което означава, че има и своя пълноценна операционна система за гости. Отвътре машината за гости се държи като собствена единица със собствени специални ресурси. Отвън знаем, че това е виртуална машина за споделяне на ресурси, предоставени от хост машината.

Както бе споменато по-горе, машината за гости може да работи или на хостван хипервизор, или на хипервизор с гол метал . Между тях има някои важни разлики.

Първо, хостваният виртуализационен хипервизор работи в операционната система на хост машината. Например, компютър, работещ под OSX, може да има VM (например VirtualBox или VMware Workstation 8), инсталирана върху тази ОС. VM няма директен достъп до хардуер, така че трябва да мине през операционната система на хоста (в нашия случай OSX на Mac).

Предимството на хоствания хипервизор е, че основният хардуер е по-малко важен. Операционната система на хоста отговаря за хардуерните драйвери вместо за самия хипервизор и поради това се счита, че има повече „хардуерна съвместимост“. От друга страна, този допълнителен слой между хардуера и хипервизора създава повече режийни ресурси, което намалява производителността на виртуалната машина.

Средата на хипервизора от чист метал се справя с проблема с производителността, като инсталира и изпълнява от хардуера на хост машината. Тъй като той взаимодейства директно с основния хардуер, не се нуждае от хост операционна система, на която да работи. В този случай първото нещо, инсталирано на сървъра на хост машината като операционна система, ще бъде хипервизорът. За разлика от хоствания хипервизор, хипервизорът без метал има свои собствени драйвери на устройства и взаимодейства директно с всеки компонент за всякакви задачи за I / O, обработка или специфична за OS. Това води до по-добра производителност, мащабируемост и стабилност. Компромисът тук е, че хардуерната съвместимост е ограничена, тъй като хипервизорът може да има вградени само толкова много драйвери на устройства.

След всички тези разговори за хипервизори, може би се чудите защо изобщо се нуждаем от този допълнителен слой „хипервизор“ между VM и хост машината.

Е, тъй като VM има собствена виртуална операционна система, хипервизорът играе съществена роля в предоставянето на VM платформа за управление и изпълнение на тази гост операционна система. Той позволява на хост компютрите да споделят своите ресурси между виртуалните машини, които работят като гости отгоре им.

Както можете да видите на диаграмата, виртуалните машини пакетират виртуалния хардуер, ядрото (т.е. ОС) и потребителското пространство за всяка нова виртуална машина.

Контейнер

За разлика от виртуалната машина, която осигурява хардуерна виртуализация, контейнерът осигурява виртуализация на ниво операционна система чрез абстрахиране на „потребителското пространство“. Ще видите какво имам предвид, когато разопаковаме термина контейнер .

За всички намерения и цели контейнерите изглеждат като VM. Например, те имат частно пространство за обработка, могат да изпълняват команди като root, имат частен мрежов интерфейс и IP адрес, позволяват персонализирани маршрути и iptable правила, могат да монтират файлови системи и т.н.

Голямата разлика между контейнерите и виртуалните машини е, че контейнерите * споделят * ядрото на хост системата с други контейнери.

Тази диаграма ви показва, че контейнерите пакетират само потребителското пространство, а не ядрото или виртуалния хардуер като VM. Всеки контейнер получава собствено изолирано потребителско пространство, за да позволи на множество контейнери да работят на една машина хост. Виждаме, че цялата архитектура на ниво операционна система се споделя между контейнери. Единствените части, които са създадени от нулата, са кошчетата и капаците. Това прави контейнерите толкова леки.

Къде влиза Docker?

Docker е проект с отворен код, базиран на Linux контейнери. Той използва функции на ядрото на Linux като пространства от имена и контролни групи, за да създава контейнери върху операционната система.

Контейнерите далеч не са нови; Google използва собствена технология за контейнери от години. Други технологии за контейнери на Linux включват зони Solaris, затвори BSD и LXC, които съществуват от много години.

И така, защо Docker изведнъж набира пара?

1. Лесна употреба: Docker улесни много за всеки - разработчици, системни администратори, архитекти и други - да се възползва от контейнерите, за да може бързо да изгради и тества преносими приложения. Той позволява на всеки да опакова приложение на своя лаптоп, което от своя страна може да работи непроменено на всеки публичен облак, частен облак или дори гол метал. Мантрата е: „изградете веднъж, бягайте навсякъде.“

2. Скорост: Докер контейнерите са много леки и бързи. Тъй като контейнерите са само изолирани среди, работещи на ядрото, те заемат по-малко ресурси. Можете да създадете и стартирате контейнер на Docker за секунди в сравнение с виртуални машини, което може да отнеме повече време, тъй като всеки път трябва да зарежда пълна виртуална операционна система.

3. Docker Hub: Потребителите на Docker също се възползват от все по-богатата екосистема на Docker Hub, която можете да смятате за „магазин за приложения за изображения на Docker“. Docker Hub има десетки хиляди публични изображения, създадени от общността, които са лесно достъпни за използване. Невероятно лесно е да търсите изображения, които отговарят на вашите нужди, готови за изтегляне и използване с малко или никакви модификации.

4. Модулност и мащабируемост: Docker улеснява разбиването на функционалността на вашето приложение в отделни контейнери. Например може да имате вашата база данни Postgres, работеща в един контейнер, и вашия сървър Redis в друг, докато приложението ви Node.js е в друг. С Docker стана по-лесно да свържете тези контейнери заедно, за да създадете вашето приложение, което улеснява мащабирането или актуализирането на компонентите независимо в бъдеще.

Не на последно място кой не обича кита на Docker? ;)

Основни концепции на Docker

Сега, когато имаме общата картина, нека разгледаме основните части на Docker парче по парче:

Докер двигател

Двигателят на Docker е слоят, върху който работи Docker. Това е леко изпълнение и инструменти, които управляват контейнери, изображения, компилации и други. Той работи в Linux системи и се състои от:

1. Docker Daemon, който работи в хост компютъра.

2. Клиент на Docker, който след това комуникира с Docker Daemon за изпълнение на команди.

3. REST API за дистанционно взаимодействие с Docker Daemon.

Докер клиент

Клиентът на Docker е това, с което вие, като краен потребител на Docker, комуникирате. Помислете за това като за потребителски интерфейс за Docker. Например, когато го направите ...

вие общувате с клиента на Docker, който след това съобщава вашите инструкции на Docker Daemon.

Docker Daemon

Демонът на Docker е това, което всъщност изпълнява команди, изпратени до клиента на Docker - като изграждане, стартиране и разпространение на вашите контейнери. Docker Daemon работи на хост машината, но като потребител никога не общувате директно с Daemon. Клиентът на Docker може да работи и на хост машината, но не се изисква. Той може да работи на различна машина и да комуникира с Docker Daemon, който работи на хост машината.

Докер файл

Dockerfile е мястото, където пишете инструкциите за изграждане на образ на Docker. Тези инструкции могат да бъдат:

  • RUN apt-get y install some-package : за инсталиране на софтуерен пакет
  • EXPOSE 8000: за излагане на порт
  • ENV ANT_HOME / usr / local / apache-ant за предаване на променлива на околната среда

и така нататък. След като настроите вашия Dockerfile, можете да използвате командата docker build, за да изградите изображение от него. Ето пример за Dockerfile:

Изображение на Docker

Изображенията са шаблони само за четене, които изграждате от набор от инструкции, написани във вашия Dockerfile. Изображенията определят едновременно как искате вашето пакетирано приложение и неговите зависимости да изглеждат * и * какви процеси да се изпълняват при стартирането му.

Образът на Docker се изгражда с помощта на Dockerfile. Всяка инструкция в Dockerfile добавя нов „слой“ към изображението, като слоевете представляват част от файловата система с изображения, която добавя или замества слоя под него. Слоевете са ключови за леката, но мощна структура на Docker. Docker използва Union File System, за да постигне това:

Съюзни файлови системи

Docker използва Union File Systems за изграждане на изображение. Можете да мислите за Union File System като подреждаема файлова система, което означава, че файловете и директориите на отделни файлови системи (известни като клонове) могат да бъдат наслагвани прозрачно, за да образуват една файлова система.

Съдържанието на директориите, които имат един и същ път в насложените клонове, се разглеждат като една обединена директория, което избягва необходимостта от създаване на отделни копия на всеки слой. Вместо това, всички те могат да получат указатели към един и същи ресурс; когато някои слоеве трябва да бъдат модифицирани, той ще създаде копие и ще модифицира локално копие, оставяйки оригинала непроменен. Ето как файловите системи могат * да изглеждат * записваеми, без всъщност да позволяват записване. (С други думи, система „копиране и запис“.)

Многослойните системи предлагат две основни предимства:

1. Без дублиране: слоевете помагат да се избегне дублирането на пълен набор от файлове всеки път, когато използвате изображение, за да създадете и стартирате нов контейнер, което прави екземпляра на докер контейнери много бърз и евтин.

2. Разделяне на слоеве: Промяната е много по-бърза - когато промените изображение, Docker разпространява само актуализациите на слоя, който е променен.

Томове

Томовете са частта от данни на контейнер, инициализирана при създаването на контейнер. Обемите ви позволяват да продължите и да споделяте данните на контейнера. Обемите от данни са отделни от стандартната файлова система на Съюза и съществуват като нормални директории и файлове в хост файловата система. Така че, дори ако унищожите, актуализирате или възстановите контейнера си, обемите от данни ще останат недокоснати. Когато искате да актуализирате том, правите промени в него директно. (Като допълнителен бонус обемите от данни могат да се споделят и използват повторно между множество контейнери, което е доста чисто.)

Докер контейнери

Контейнерът на Docker, както беше обсъдено по-горе, обвива софтуера на приложението в невидима кутия с всичко, което приложението трябва да изпълни. Това включва операционната система, кода на приложението, времето за изпълнение, системните инструменти, системните библиотеки и др. Docker контейнерите са изградени от Docker изображения. Тъй като изображенията са само за четене, Docker добавя файлова система за четене и запис върху файловата система само за четене на изображението, за да създаде контейнер.

Освен това, след като създава контейнера, Docker създава мрежов интерфейс, така че контейнерът да може да разговаря с локалния хост, да прикачва наличен IP адрес към контейнера и да изпълнява процеса, който сте посочили, за да стартирате приложението си при дефиниране на изображението.

След като успешно сте създали контейнер, можете да го стартирате във всяка среда, без да се налага да правите промени.

Щракнете двукратно върху „контейнери“

Фу! Това са много движещи се части. Едно нещо, което винаги ме интересуваше, е как всъщност се изпълнява контейнер, особено след като няма никаква абстрактна граница на инфраструктурата около контейнер. След много четене всичко има смисъл, така че ето моят опит да ви го обясня! :)

Терминът „контейнер“ всъщност е просто абстрактна концепция, която описва как няколко различни функции работят заедно, за да визуализират „контейнер“. Нека да преминем през тях много бързо:

1) Пространства от имена

Пространствата от имена предоставят контейнери със собствен изглед на основната Linux система, ограничавайки това, което контейнерът може да вижда и да има достъп. Когато стартирате контейнер, Docker създава пространства от имена, които конкретният контейнер ще използва.

Има няколко различни типа пространства от имена в ядрото, които Docker използва, например:

а. NET: Предоставя контейнер със собствен изглед на мрежовия стек на системата (напр. Собствени мрежови устройства, IP адреси, IP маршрутни таблици, / proc / net директория, номера на портове и т.н.).

б. PID: PID означава идентификатор на процеса. Ако някога сте изпълнявали ps aux в командния ред, за да проверите какви процеси се изпълняват във вашата система, ще видите колона с име „PID“. Пространството от имена PID дава на контейнерите свой собствен обхват на процесите, които могат да преглеждат и да си взаимодействат, включително независим init (PID 1), който е „предшественик на всички процеси“.

° С. MNT: Предоставя на контейнер собствен изглед на „монтиранията“ в системата. И така, процесите в различни пространства на имена на монтиране имат различни изгледи на йерархията на файловата система.

д. UTS: UTS означава UNIX Timesharing System. Тя позволява на процеса да идентифицира системни идентификатори (т.е. име на хост, име на домейн и т.н.). UTS позволява на контейнерите да имат собствено име на хост и име на домейн NIS, което е независимо от други контейнери и хост системата.

д. IPC: IPC означава InterProcess Communication. Пространството от имена на IPC е отговорно за изолирането на IPC ресурси между процесите, изпълнявани във всеки контейнер.

е. ПОТРЕБИТЕЛ: Това пространство от имена се използва за изолиране на потребители във всеки контейнер. Той функционира, като позволява на контейнерите да имат различен изглед на диапазоните uid (потребителски идентификатор) и gid (групов идентификатор), в сравнение с хост системата. В резултат на това uid и gid на процеса могат да се различават вътре и извън потребителското пространство на имена, което също позволява на процеса да има непривилегирован потребител извън контейнер, без да жертва привилегията на root в контейнер.

Docker използва тези пространства от имена заедно, за да изолира и да започне създаването на контейнер. Следващата характеристика се нарича контролни групи.

2) Контролни групи

Контролните групи (наричани още cgroups) е функция на ядрото на Linux, която изолира, приоритизира и отчита използването на ресурсите (CPU, памет, дискови I / O, мрежа и т.н.) на набор от процеси. В този смисъл cgroup гарантира, че контейнерите на Docker използват само ресурсите, от които се нуждаят - и, ако е необходимо, задават ограничения на ресурсите, които контейнерът * може да използва. Cgroups също така гарантират, че един контейнер не изчерпва един от тези ресурси и не сваля цялата система.

И накрая, обединяването на файловите системи е друга функция, която Docker използва:

3) Изолирана файлова система на Съюза:

Описано по-горе в раздела Docker Images :)

Това е наистина всичко, което има за контейнер на Docker (разбира се, дяволът е в подробностите за изпълнението - например как да управлявате взаимодействията между различните компоненти).

Бъдещето на Docker: Docker и VM ще съществуват съвместно

Докато Docker със сигурност печели много пара, не вярвам да се превърне в реална заплаха за виртуалните машини. Контейнерите ще продължат да се налагат, но има много случаи на използване, при които VM все още са по-подходящи.

Например, ако трябва да стартирате множество приложения на множество сървъри, вероятно има смисъл да използвате виртуални машини. От друга страна, ако трябва да стартирате много * копия * на едно приложение, Docker предлага някои убедителни предимства.

Освен това, докато контейнерите ви позволяват да разделите приложението си на по-функционални дискретни части, за да създадете разделяне на проблемите, това също означава, че има все по-голям брой части за управление, които могат да станат тромави.

Сигурността също е обект на загриженост при контейнерите на Docker - тъй като контейнерите споделят едно и също ядро, бариерата между контейнерите е по-тънка. Докато пълната виртуална машина може да издава само хиперповиквания към хост хипервизора, контейнерът на Docker може да прави системни извиквания към ядрото на хоста, което създава по-голяма повърхност за атака. Когато сигурността е особено важна, разработчиците вероятно ще изберат виртуални машини, които са изолирани от абстрахиран хардуер - което прави много по-трудно да си пречат помежду си.

Разбира се, въпроси като сигурността и управлението със сигурност ще се развият, тъй като контейнерите ще бъдат по-изложени в производството и по-нататъшен контрол от потребителите. Засега дебатът за контейнери срещу виртуални машини наистина е най-добре за разработчиците, които живеят и ги дишат всеки ден!

Заключение

Надявам се, че вече сте оборудвани със знанията, от които се нуждаете, за да научите повече за Docker и може би дори да ги използвате в проект един ден.

Както винаги, оставете ми ред в коментарите, ако съм направил някакви грешки или все пак мога да ви бъда полезен! :)