Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Nagsimula noong Agosto 10 sa Slurm Docker video course, kung saan ganap naming pinag-aaralan ito - mula sa mga pangunahing abstraction hanggang sa mga parameter ng network.

Sa artikulong ito ay pag-uusapan natin ang kasaysayan ng Docker at ang mga pangunahing abstraction nito: Image, Cli, Dockerfile. Ang panayam ay inilaan para sa mga nagsisimula, kaya malamang na hindi ito interesado sa mga karanasang gumagamit. Walang dugo, apendiks o malalim na paglulubog. Ang pinaka-basic.

Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Ano ang Docker

Tingnan natin ang kahulugan ng Docker mula sa Wikipedia.

Ang Docker ay software para sa pag-automate ng deployment at pamamahala ng mga application sa mga containerized na kapaligiran.

Walang malinaw sa kahulugang ito. Lalo na hindi malinaw kung ano ang ibig sabihin ng "sa mga kapaligiran na sumusuporta sa containerization." Upang malaman, bumalik tayo sa nakaraan. Magsimula tayo sa panahon na karaniwan kong tinatawag na β€œMonolithic Era.”

Panahon ng monolitik

Ang monolitikong panahon ay ang unang bahagi ng 2000s, kung kailan ang lahat ng mga aplikasyon ay monolitik, na may isang grupo ng mga dependencies. Ang pag-unlad ay tumagal ng mahabang panahon. Kasabay nito, walang gaanong mga server; alam naming lahat ang mga ito sa pangalan at sinusubaybayan sila. Mayroong isang nakakatawang paghahambing:

Ang mga alagang hayop ay mga alagang hayop. Sa monolitikong panahon, itinuring namin ang aming mga server na parang mga alagang hayop, inayos at itinatangi, tinatangay ang mga butil ng alikabok. At para sa mas mahusay na pamamahala ng mapagkukunan, gumamit kami ng virtualization: kumuha kami ng isang server at pinutol ito sa ilang mga virtual machine, sa gayon ay tinitiyak ang paghihiwalay ng kapaligiran.

Hypervisor-based na virtualization system

Malamang na narinig ng lahat ang tungkol sa mga sistema ng virtualization: VMware, VirtualBox, Hyper-V, Qemu KVM, atbp. Nagbibigay sila ng application isolation at resource management, ngunit mayroon din silang mga disadvantages. Upang gawin ang virtualization, kailangan mo ng hypervisor. At ang hypervisor ay isang mapagkukunan sa itaas. At ang virtual machine mismo ay karaniwang isang buong colossus - isang mabigat na imahe na naglalaman ng isang operating system, Nginx, Apache, at posibleng MySQL. Ang imahe ay malaki at ang virtual machine ay hindi maginhawa upang gumana. Bilang resulta, maaaring maging mabagal ang pagtatrabaho sa mga virtual machine. Upang malutas ang problemang ito, ang mga sistema ng virtualization ay nilikha sa antas ng kernel.

Mga sistema ng virtualization sa antas ng kernel

Ang kernel-level virtualization ay sinusuportahan ng OpenVZ, Systemd-nspawn, LXC system. Ang isang kapansin-pansing halimbawa ng naturang virtualization ay ang LXC (Linux Containers).

Ang LXC ay isang operating system-level virtualization system para sa pagpapatakbo ng maramihang mga nakahiwalay na pagkakataon ng Linux operating system sa isang node. Ang LXC ay hindi gumagamit ng mga virtual machine, ngunit lumilikha ng isang virtual na kapaligiran na may sarili nitong espasyo sa proseso at network stack.

Talagang gumagawa ang LXC ng mga lalagyan. Ano ang pagkakaiba sa pagitan ng mga virtual machine at container?

Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Ang lalagyan ay hindi angkop para sa paghihiwalay ng mga proseso: ang mga kahinaan ay matatagpuan sa mga sistema ng virtualization sa antas ng kernel na nagpapahintulot sa kanila na makatakas mula sa lalagyan patungo sa host. Samakatuwid, kung kailangan mong ihiwalay ang isang bagay, mas mahusay na gumamit ng isang virtual machine.

Ang mga pagkakaiba sa pagitan ng virtualization at containerization ay makikita sa diagram.
May mga hardware hypervisor, hypervisor sa itaas ng OS, at mga lalagyan.

Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Ang mga hardware hypervisor ay cool kung gusto mo talagang ihiwalay ang isang bagay. Dahil posible na ihiwalay sa antas ng mga pahina ng memorya at mga processor.

Mayroong mga hypervisor bilang isang programa, at may mga lalagyan, at pag-uusapan pa natin ang mga ito. Walang hypervisor ang mga containerization system, ngunit mayroong Container Engine na gumagawa at namamahala ng mga container. Ang bagay na ito ay mas magaan, kaya dahil sa pagtatrabaho sa core mayroong mas kaunting overhead o wala sa lahat.

Ano ang ginagamit para sa containerization sa antas ng kernel

Ang mga pangunahing teknolohiya na nagbibigay-daan sa iyong lumikha ng container na nakahiwalay sa iba pang mga proseso ay ang Namespaces at Control Groups.

Mga Namespace: PID, Networking, Mount at User. Marami pa, ngunit para sa madaling pag-unawa ay tututukan natin ang mga ito.

Nililimitahan ng PID Namespace ang mga proseso. Kapag, halimbawa, gumawa kami ng PID Namespace at naglagay ng proseso doon, ito ay magiging kasama ng PID 1. Kadalasan sa mga system ang PID 1 ay systemd o init. Alinsunod dito, kapag naglagay kami ng proseso sa isang bagong namespace, nakakatanggap din ito ng PID 1.

Binibigyang-daan ka ng Networking Namespace na limitahan/ihiwalay ang network at ilagay ang sarili mong mga interface sa loob. Ang pag-mount ay isang limitasyon ng file system. Userβ€”paghihigpit sa mga user.

Mga Control Group: Memory, CPU, IOPS, Network - humigit-kumulang 12 mga setting sa kabuuan. Kung hindi man ay tinatawag din silang Cgroups (β€œC-groups”).

Ang Control Groups ay namamahala ng mga mapagkukunan para sa isang lalagyan. Sa pamamagitan ng Control Groups masasabi nating hindi dapat kumonsumo ang container ng higit sa isang tiyak na halaga ng mga mapagkukunan.

Para gumana nang buo ang containerization, ginagamit ang mga karagdagang teknolohiya: Mga Kakayahan, Copy-on-write at iba pa.

Ang mga kakayahan ay kapag sinabi natin sa isang proseso kung ano ang maaari at hindi nito magagawa. Sa antas ng kernel, ito ay mga bitmap lamang na may maraming mga parameter. Halimbawa, ang root user ay may ganap na mga pribilehiyo at kayang gawin ang lahat. Maaaring baguhin ng server ng oras ang oras ng system: mayroon itong mga kakayahan sa Time Capsule, at iyon lang. Gamit ang mga pribilehiyo, maaari mong madaling i-configure ang mga paghihigpit para sa mga proseso, at sa gayon ay maprotektahan ang iyong sarili.

Ang Copy-on-write system ay nagbibigay-daan sa amin na magtrabaho sa mga larawan ng Docker at gamitin ang mga ito nang mas mahusay.

Ang Docker ay kasalukuyang may mga isyu sa compatibility sa Cgroups v2, kaya ang artikulong ito ay partikular na nakatuon sa Cgroups v1.

Ngunit bumalik tayo sa kasaysayan.

Nang lumitaw ang mga sistema ng virtualization sa antas ng kernel, nagsimula silang aktibong magamit. Nawala ang overhead sa hypervisor, ngunit nanatili ang ilang problema:

  • malalaking imahe: itinutulak nila ang isang operating system, mga aklatan, isang grupo ng iba't ibang software sa parehong OpenVZ, at sa huli ang imahe ay lumalabas na medyo malaki;
  • Walang normal na pamantayan para sa packaging at paghahatid, kaya nananatili ang problema ng mga dependency. May mga sitwasyon kapag ang dalawang piraso ng code ay gumagamit ng parehong library, ngunit may magkaibang mga bersyon. Baka may conflict sa pagitan nila.

Upang malutas ang lahat ng mga problemang ito, dumating ang susunod na panahon.

Panahon ng lalagyan

Nang dumating ang Era of Containers, nagbago ang pilosopiya ng pagtatrabaho sa kanila:

  • Isang proseso - isang lalagyan.
  • Inihahatid namin ang lahat ng mga dependency na kailangan ng proseso sa lalagyan nito. Nangangailangan ito ng pagputol ng mga monolith sa mga microservice.
  • Kung mas maliit ang imahe, mas mabuti - may mas kaunting mga posibleng kahinaan, mas mabilis itong lumabas, at iba pa.
  • Ang mga pagkakataon ay nagiging panandalian.

Tandaan kung ano ang sinabi ko tungkol sa mga alagang hayop vs baka? Dati, ang mga pagkakataon ay parang alagang hayop, ngunit ngayon ay naging parang baka. Noong nakaraan, mayroong isang monolith - isang application. Ngayon ito ay 100 microservices, 100 container. Maaaring may 2-3 replika ang ilang lalagyan. Nagiging hindi gaanong mahalaga para sa atin na kontrolin ang bawat lalagyan. Ang mas mahalaga sa amin ay ang pagkakaroon ng serbisyo mismo: kung ano ang ginagawa ng hanay ng mga container na ito. Binabago nito ang mga diskarte sa pagsubaybay.

Noong 2014-2015, umunlad ang Docker - ang teknolohiyang pag-uusapan natin ngayon.

Binago ng Docker ang pilosopiya at standardized application packaging. Gamit ang Docker, maaari naming i-package ang isang application, ipadala ito sa isang repository, i-download ito mula doon, at i-deploy ito.

Inilalagay namin ang lahat ng kailangan namin sa lalagyan ng Docker, kaya nalutas ang problema sa dependency. Ginagarantiyahan ng Docker ang muling paggawa. Sa tingin ko maraming tao ang nakatagpo ng irreproducibility: gumagana ang lahat para sa iyo, itinutulak mo ito sa produksyon, at doon ito tumigil sa paggana. Sa Docker, nawawala ang problemang ito. Kung magsisimula ang iyong container ng Docker at gawin ang kailangan nitong gawin, kung gayon na may mataas na antas ng posibilidad na magsisimula ito sa produksyon at gawin ang parehong doon.

Digression tungkol sa overhead

Palaging may mga pagtatalo tungkol sa mga overhead. Ang ilang mga tao ay naniniwala na ang Docker ay hindi nagdadala ng karagdagang pagkarga, dahil ginagamit nito ang Linux kernel at lahat ng mga prosesong kinakailangan nito para sa containerization. Tulad ng, "kung sasabihin mo na ang Docker ay nasa itaas, kung gayon ang Linux kernel ay nasa itaas."

Sa kabilang banda, kung lalalim ka, mayroon talagang ilang mga bagay sa Docker na, na may kahabaan, ay masasabing nasa itaas.

Ang una ay PID namespace. Kapag naglagay kami ng proseso sa isang namespace, ito ay nakatalaga sa PID 1. Kasabay nito, ang prosesong ito ay may isa pang PID, na matatagpuan sa host namespace, sa labas ng container. Halimbawa, inilunsad namin ang Nginx sa isang lalagyan, ito ay naging PID 1 (master process). At sa host ay mayroon itong PID 12623. At mahirap sabihin kung gaano ito kalaki.

Ang pangalawang bagay ay Cgroups. Kunin natin ang Cgroups ayon sa memorya, iyon ay, ang kakayahang limitahan ang memorya ng isang lalagyan. Kapag ito ay pinagana, ang mga counter at memory accounting ay isinaaktibo: ang kernel ay kailangang maunawaan kung gaano karaming mga pahina ang inilaan at kung ilan ang libre pa para sa lalagyan na ito. Ito ay posibleng isang overhead, ngunit wala akong nakitang anumang tumpak na pag-aaral kung paano ito nakakaapekto sa pagganap. At ako mismo ay hindi napansin na ang application na tumatakbo sa Docker ay biglang nakaranas ng isang matalim na pagkawala sa pagganap.

At isa pang tala tungkol sa pagganap. Ang ilang mga parameter ng kernel ay ipinapasa mula sa host patungo sa lalagyan. Sa partikular, ilang mga parameter ng network. Samakatuwid, kung gusto mong magpatakbo ng isang bagay na may mataas na pagganap sa Docker, halimbawa, isang bagay na aktibong gagamit ng network, pagkatapos ay kailangan mong ayusin ang mga parameter na ito. Ilang nf_conntrack, halimbawa.

Tungkol sa konsepto ng Docker

Ang Docker ay binubuo ng ilang bahagi:

  1. Ang Docker Daemon ay ang parehong Container Engine; naglulunsad ng mga lalagyan.
  2. Ang Docker CII ay isang utility sa pamamahala ng Docker.
  3. Dockerfile - mga tagubilin sa kung paano bumuo ng isang imahe.
  4. Larawan β€” ang larawan kung saan inilalabas ang lalagyan.
  5. Lalagyan.
  6. Ang registry ng Docker ay isang repositoryo ng imahe.

Sa eskematiko, mukhang ganito:

Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Ang Docker daemon ay tumatakbo sa Docker_host at naglulunsad ng mga lalagyan. Mayroong isang Kliyente na nagpapadala ng mga utos: buuin ang imahe, i-download ang imahe, ilunsad ang lalagyan. Ang docker daemon ay pumupunta sa registry at ipapatupad ang mga ito. Maaaring ma-access ng Docker client ang parehong lokal (sa isang Unix socket) at sa pamamagitan ng TCP mula sa isang remote host.

Suriin natin ang bawat bahagi.

Docker daemon - ito ang bahagi ng server, gumagana ito sa host machine: nagda-download ng mga larawan at naglulunsad ng mga lalagyan mula sa kanila, gumagawa ng network sa pagitan ng mga lalagyan, nangongolekta ng mga log. Kapag sinabi nating "lumikha ng isang imahe," ginagawa din iyon ng demonyo.

Docker CLI β€” Bahagi ng kliyente ng Docker, utility ng console para sa pagtatrabaho sa daemon. Uulitin ko, maaari itong gumana hindi lamang sa lokal, kundi pati na rin sa network.

Mga pangunahing utos:

docker ps - ipakita ang mga lalagyan na kasalukuyang tumatakbo sa host ng Docker.
mga docker images - ipakita ang mga larawang na-download nang lokal.
paghahanap ng docker <> - maghanap ng imahe sa registry.
docker pull <> - mag-download ng imahe mula sa registry papunta sa makina.
build ng docker < > - kolektahin ang larawan.
docker run <> - ilunsad ang lalagyan.
docker rm <> - alisin ang lalagyan.
docker logs <> - container logs
docker start/stop/restart <> - gumagana sa container

Kung pinagkadalubhasaan mo ang mga utos na ito at kumpiyansa ka sa paggamit ng mga ito, isaalang-alang ang iyong sarili na 70% sanay sa Docker sa antas ng user.

dockerfile - mga tagubilin para sa paglikha ng isang imahe. Halos bawat utos ng pagtuturo ay isang bagong layer. Tingnan natin ang isang halimbawa.

Ano ang Docker: isang maikling iskursiyon sa kasaysayan at mga pangunahing abstraction

Ito ang hitsura ng Dockerfile: mga utos sa kaliwa, mga argumento sa kanan. Ang bawat command na narito (at karaniwang nakasulat sa Dockerfile) ay lumilikha ng bagong layer sa Image.

Kahit na tumingin sa kaliwang bahagi, maaari mong halos maunawaan kung ano ang nangyayari. Sinasabi namin: "lumikha ng isang folder para sa amin" - ito ay isang layer. Ang "Gawing gumagana ang folder" ay isa pang layer, at iba pa. Pinapadali ng layer cake ang buhay. Kung lumikha ako ng isa pang Dockerfile at magbabago ng isang bagay sa huling linya - nagpapatakbo ako ng isang bagay maliban sa "python" "main.py", o mag-install ng mga dependency mula sa isa pang file - pagkatapos ay ang mga nakaraang layer ay muling gagamitin bilang isang cache.

Imahen - ito ay container packaging; ang mga lalagyan ay inilunsad mula sa larawan. Kung titingnan natin ang Docker mula sa punto ng view ng isang manager ng package (na parang nagtatrabaho tayo sa mga deb o rpm na pakete), kung gayon ang imahe ay mahalagang isang rpm package. Sa pamamagitan ng yum install maaari naming i-install ang application, tanggalin ito, hanapin ito sa repository, at i-download ito. Ito ay halos pareho dito: ang mga lalagyan ay inilunsad mula sa larawan, sila ay naka-imbak sa Docker registry (katulad ng yum, sa isang repositoryo), at ang bawat larawan ay may SHA-256 hash, isang pangalan at isang tag.

Ang imahe ay binuo ayon sa mga tagubilin mula sa Dockerfile. Ang bawat pagtuturo mula sa Dockerfile ay lumilikha ng bagong layer. Maaaring magamit muli ang mga layer.

Docker registry ay isang imbakan ng imahe ng Docker. Katulad ng OS, ang Docker ay may pampublikong karaniwang pagpapatala - dockerhub. Ngunit maaari kang bumuo ng iyong sariling imbakan, ang iyong sariling pagpapatala ng Docker.

Lalagyan - kung ano ang inilunsad mula sa imahe. Nagtayo kami ng isang imahe ayon sa mga tagubilin mula sa Dockerfile, pagkatapos ay inilunsad namin ito mula sa larawang ito. Ang lalagyan na ito ay nakahiwalay sa iba pang mga lalagyan at dapat na naglalaman ng lahat ng kailangan para gumana ang application. Sa kasong ito, isang lalagyan - isang proseso. Ito ay nangyayari na kailangan mong gawin ang dalawang proseso, ngunit ito ay medyo salungat sa ideolohiya ng Docker.

Ang kinakailangan na "isang lalagyan, isang proseso" ay nauugnay sa PID Namespace. Kapag nagsimula ang isang proseso na may PID 1 sa Namespace, kung bigla itong mamatay, mamamatay din ang buong container. Kung ang dalawang proseso ay tumatakbo doon: ang isa ay buhay at ang isa ay patay, kung gayon ang lalagyan ay patuloy na mabubuhay. Ngunit ito ay isang tanong ng Pinakamahusay na Kasanayan, pag-uusapan natin ang tungkol sa mga ito sa iba pang mga materyales.

Upang pag-aralan ang mga tampok at buong programa ng kurso nang mas detalyado, mangyaring sundin ang link: "Docker video course'.

May-akda: Marcel Ibraev, certified Kubernetes administrator, practicing engineer sa Southbridge, speaker at developer ng Slurm courses.

Pinagmulan: www.habr.com

Magdagdag ng komento