Docker i Kubernetes: Prakticheskoye Rukovodstvo dlya Sovremennykh Razrabotchikov
Rukovodstvo bez vody po konteynerizatsii, luchshim praktikam Dockerfile, osnovam Kubernetes i ponimaniyu, kogda vam deystvitelno nuzhen orkestrator.
Kazhdyy razrabotchik v konechnom itoge stalkivayetsya s odnoy i toy zhe stenoy. Vy pishyete kod na svoyey mashine, on rabotayet idealno, vy pushite yego v steydzhin, i on vzryvayetsya s zagadochnoy oshibkoy o propushchennoy sistemnoy zavisimosti ili drugoy versii biblioteki. Klassicheskaya problema "rabotayet na moyey mashine" presledovala razrabotku PO desyatiletiyami, i Docker ne prosto reshil yeye — on sdelal resheniye nastolko prostym, chto teper net opravdaniya yego ne ispolzovat.
No Docker reshayet tolko problemu upakovki. Posle togo, kak vy konteynerizovali svoye prilozheniye, vam vse yeshche nuzhno zapustit yego v produktsii — potentsialno na neskolkikh serverakh, s balansirovkoy nagruzki, razvertyvaniyami bez prostoya, proverkami zdorovya i avtomaticheskim vosstanovleniyem. Vot zdes vkhodit Kubernetes. I vot zdes bolshinstvo razrabotchikov teryayutsya v slozhnosti, potomu chto Kubernetes vvodit sovershenno novuyu leksiku abstraktsiy, kotoruyu nuzhno vremya, chtoby internalizirovat.
Eto rukovodstvo razrezayet shum. Ono okhvatyvayet to, chem na samom dele yavlyayutsya konteynery pod kapotom, kak pisat Dockerfile, kotoryye effektivny i bezopasny, kontseptsii Kubernetes, kotoryye vam nuzhno znat dlya razvertyvaniya realnykh prilozheniy, kompromissy mezhdu Docker Compose i Kubernetes dlya lokalnoy razrabotki i, samoye glavnoye, kogda sleduyet obrashchatsya k kazhdomu instrumentu, a kogda ostavit yego v pokoye.
Chem na samom dele yavlyayutsya konteynery
Konteyner — eto ne oblegchennaya virtualnaya mashina. Eto samoye rasprostranennoye zabluzhdeniye, i ono privodit k nepravilnym myslennym modelyam. Virtualnaya mashina zapuskayet polnostyu gostevuyu operatsionnuyu sistemu poverkh gipervizora, so svoim yadrom, sobstvennym raspredeleniyem pamyati i sobstvennymi draverami ustroystv. Konteyner razdelyayet yadro hosta i rabotayet kak izolirovannyy polzovatelskiy protsess. Izolyatsiya obespechivayetsya funktsiyami yadra Linux — prostranstvami imyon dlya izolyatsii protsessov, cgroups dlya ogranicheniya resursov i overlay-faylovymi sistemami dlya effektivnykh sloyev obrazov.
Eto razlichiye vazhno, potomu chto obyasnyayet povedeniye, kotoroye vy budete nablyudat. Konteynery zapuskayutsya za millisekundy, potomu chto net neobkhodimosti zagruzhat yadro. Oni ispolzuyut menshe pamyati, potomu chto net dubliruyushchego yadra i izbytochnykh sistemnykh protsessov. No eto takzhe oznachayet, chto konteyner, zapushchennyy na Linux, ne mozhet zapustit druguyu versiyu yadra, chem khost, a Windows-konteyner trebuyet Windows-khosta (ili Hyper-V Linux VM na starykh versiyakh). V macOS Docker Desktop zapuskayet Linux-konteynery vnutri oblegchennoy VM imenno po etoy prichine.
Obraz — eto shablon tolko dlya chteniya: snimok faylovoy sistemy plyus metadannyye. Konteyner — eto zapushchennyy ekzemplyar etogo obraza s sloyem dlya zapisi poverkh. Vy mozhete sozdat obraz odin raz i zapustit desyatki konteynerov iz nego. Eto fundamentalnaya yedinitsa operatsii v mire Docker, i yasnoye ponimaniye etogo delayet vse ostalnoye legche.
Luchshiye praktiki Dockerfile
Dockerfile — eto retsept dlya sozdaniya obraza. Kazhdaya instruktsiya sozdayet novyy sloy, i sloi keshiruyutsya. Eto oznachayet, chto poryadok instruktsiy pryamo vliyayet na skorost sborki, razmer obraza i bezopasnost. Vot printsipy, kotoryye naiboleye vazhny v realnykh proyektakh.
Uporyadochivayte sloi po chastote izmeneniy
Docker keshiruyet kazhdyy sloy posle yego sborki. Yesli sloy ne izmenilsya so vremeni posledney sborki, Docker pereispolzuyet keshirovannuyu versiyu. Eto oznachayet, chto instruktsii, kotoryye izmenyayutsya redko, sleduyet pomeshchat naverkh, a te, kotoryye izmenyayutsya chasto — vniz. Sistemnyye zavisimosti (apt-get, apk add) izmenyayutsya pochti nikogda. Zavisimosti prilozheniya (npm install, pip install) izmenyayutsya, kogda vy obnovlyayete svoy lockfile. Iskhodnyy kod prilozheniya izmenyayetsya pri kazhdom commite.
# Plokho: iskhodnyy kod pered zavisimostyami
FROM node:20-alpine
WORKDIR /app
COPY . . # sbivayet kesh dlya vsego nizhe
RUN npm ci # zapuskayetsya pri kazhdoy sborke, dazhe yesli package.json ne izmenilsya
EXPOSE 3000
CMD ["node", "dist/index.js"]
# KHorosho: poryadok so stabilnym pervym sloyem
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci # keshiruyetsya, yesli package.json ne izmenilsya
COPY . . # tolko izmeneniye iskhodnika sbivayet etot sloy
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/index.js"]Raznitsa dramaticheskaya. Plokhoy Dockerfile perestroyvayet vse zavisimosti pri kazhdom commite. KHoroshiy perestroyvayet zavisimosti tolko kogda izmenyayetsya lockfile, chto obytno proiskhodit odin raz na pull request, a ne pri kazhdom commite. V Node.js proyekte s 500 zavisimostyami eto mozhet sberech dve minuty na sborku.
Mnogostadiynyye sborki
Mnogostadiynyye sborki pozvolyayut ispolzovat odin Dockerfile dlya sborki prilozheniya i sozdaniya minimalnogo runtime-obraza. Stadiya sborki soderzhit kompilatory, dev-zavisimosti i instrumenty sborki. Stadiya runtime kopiruyet tolko kompilirovannyy vyvod. Eto derzhit produktsionnyye obrazy malenkimi i umenshayet poverkhnost ataki.
# Build stage
FROM node:20-alpine AS builder
WORKDIR /build
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime stage — nachinayet s svezhey, minimalnoy bazy
FROM node:20-alpine AS runner
WORKDIR /app
# Tolko to, chto nuzhno dlya zapuska
COPY --from=builder /build/dist ./dist
COPY --from=builder /build/package.json ./
COPY --from=builder /build/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]Stadiya runtime ne vklyuchayet kompilyator TypeScript, iskhodnyye fayly ili kakiye-libo dev-zavisimosti. Dlya tipichnogo prilozheniya eto umenshayet obraz s 800 MB do meneye 200 MB. Sintaksis COPY --from=builder — eto klyuchevaya ideya: on tashchit fayly iz predydushchey stadii, ne perenosya sloi iz etoy stadii.
Zapusk ot imeni ne-root polzovatelya
Konteynery zapuskayutsya ot root po umolchaniyu. Eto risk bezopasnosti: yesli zloumyshlennik ekspluatiruyet vashe prilozheniye, on poluchayet root-dostup vnutri konteynera. Ispravleniye — odna stroka v vashem Dockerfile, kotoraya pereklyuchayet na ne-root polzovatelya. Bolshinstvo bazovykh obrazov postavlyayetsya s polzovatelem node ili nobody dlya etoy tseli.
Krome bezopasnosti, mnogostadiynyye sborki i pravilnoye uporyadochivaniye sloyev takzhe uluchshayut skorost CI/CD konveyera. Kazhdaya minuta, sberezhennaya na sborke obraza, — eto minuta, kotoruyu vashi razrabotchiki ne zhdut razvertyvaniya. V komande iz desyati razrabotchikov, razvertyvayushchikh pyat raz v den, ekoomiya v dve minuty na sborku vozvrashchayet boleye shestidesyati chasov rabochego vremeni razrabotchikov v god.
Osnovy Kubernetes
Kubernetes — eto orkestrator konteynerov. On beret klaster mashin (nod), planiruyet konteynery na nikh, derzhit ikh v rabochem sostoyanii, upravlyayet setyu i predostavlyayet deklarativnyy API dlya opisaniya zhelayemogo sostoyaniya vashey sistemy. Vy govorite Kubernetes, chto vy khotite — tri repliki vashego API-servera, port 8080 vystavlen, strategiya obnovleniya po ocheredi — i on realizuyet eto.
Krivaya obucheniya realna, potomu chto Kubernetes vvodit mnogourovnevyy nabor abstraktsiy. Tri, s kotorymi vy budete vzaimodeystvovat chashche vsego, — eto Pods, Deployments i Services.
Pods
Pod — eto naimenshaya razvertyvayemaya yedinitsa v Kubernetes. On predstavlyayet odin ili neskolko konteynerov, kotoryye razdelyayut setevoye prostranstvo imyon i tomov khraneniya. Na praktike bolshinstvo Podov zapuskayet odin konteyner. Patterny sidecar (glavnyy konteyner plyus konteyner dlya logirovaniya ili proksi) ispolzuyut mnogokonteynernyye Pody, no dlya yezhednevnoy razvertyvaniya prilozheniy vy budete ispolzovat odin konteyner na Pod.
Vy redko sozdayete Pody napryamuyu. Pody efemerny — oni mogut byt zaversheny i pereplanirovany v lyuboye vremya. Yesli vy sozdayete Pod vruchnuyu i node, na kotoroy on rabotayet, vykhodit iz stroyu, Pod teryayetsya navsegda. Vot gde vkhodyat Deployments.
Deployments
Deployment upravlyayet naborom identichnykh Podov (ReplicaSet). On obrabatyvayet obnovleniya po ocheredi, masshtabirovaniye, samoislovleniye i otkaty. Eto resurs, kotoryy vy budete ispolzovat dlya razvertyvaniya prilozheniy bez sostoyaniya (stateless).
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
labels:
app: api-server
spec:
replicas: 3
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api
image: myregistry/api-server:v1.2.3
ports:
- containerPort: 3000
resources:
requests:
cpu: 250m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /healthz
port: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000Etot Deployment obyavlyayet tri repliki API-servera. Kubernetes obespechit, chto vsegda rabotayut tri Poda. Yesli Pod padayet, Kubernetes sozdayet zamenu. Vo vremya obnovleniya po ocheredi (izmeneniye tega obraza) Kubernetes zamenyayet Pody odin za drugim, garantiruyu otsutstviye prostoya. LivenessProbe govorit Kubernetes, kogda Pod zdorov; readinessProbe govorit, kogda Pod gotov prinimat trafik.
Services
Pody imeyut dinamicheskiye IP-adresa. Kazhdyy raz, kogda Pod perezdayetsya, on poluchayet novyy IP. Service predostavlyayet stabilnuyu setevuyu tochku, kotoraya balansiruyet nagruzku po Podam, sootvetstvuyushchim yego selek-toru. Eto to, kak drugiye chasti vashey sistemy nakhodyat i obshchayutsya s vashim prilozheniyem.
apiVersion: v1
kind: Service
metadata:
name: api-server
spec:
selector:
app: api-server
ports:
- port: 80
targetPort: 3000
type: ClusterIPEtot Service otobrazhayet port 80 na stabilnom vnutriklasternom IP na port 3000 na Podakh s metkoy app: api-server. Drugiye servisy vnutri klastera mogut obrashchatsya k nemu po DNS-imenu api-server. Dlya vneshnego trafika vy by ispolzovali resurs LoadBalancer ili Ingress poverkh Service.
Kubernetes — eto ne platforma, na kotoruyu vy razvertyvayete. Eto platforma, kotoroy vy opisyvayete razvertyvaniye. Raznitsa mezhdu imperativnym i deklarativnym — eto yedinstvennyy naiboleye vazhnyy myslennyy sdvig, kotoryy vy mozhete sdelat.
Lokalnaya razrabotka: Docker Compose protiv Kubernetes
Samaya bolshaya oshibka, kotoruyu dopuskayut komandy, — eto predpolozheniye, chto im nuzhen Kubernetes dlya lokalnoy razrabotki, potomu chto oni ispolzuyut yego v produktsii. Docker Compose i Kubernetes sluzhat raznym tselyam, i vybor nepravilnogo dlya lokalnoy raboty sozdayet nenuzhnoye treniye.
Docker Compose razrabotan dlya lokalnoy razrabotki. On rabotayet na odnoy mashine, zapuskayet konteynery za sekundy i imeyet prostoy format YAML, kotoryy pryamo otobrazhayetsya na to, chto vam nuzhno: veb-server, baza dannykh, instants Redis i, vozmozhno, rabotnik ocheredi. Vy opredelyayete servisy, i docker compose up privodit vse v rabocheye sostoyaniye, s logami, strimyshchimisya v vash terminal, portami, otobrazhennymi na localhost, i goryachey perezagruzkoy, rabotayushchey iz korobki.
version: "3.8"
services:
api:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- DATABASE_URL=postgres://user:pass@db:5432/app
depends_on:
- db
db:
image: postgres:16-alpine
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:Etot Compose-fayl dayet vam rabochuyu sredu razrabotki s goryachey perezagruzkoy, lokalnoy bazoy dannykh s postoyannym khraneniyem i pravilnoy setevoy svyazyu mezhdu servisami. Eto zanimayet okolo tridtsati strok YAML i zapuskayetsya menshe chem za desyat sekund.
Minikube, Kind i k3s mogut zapuskat Kubernetes lokalno, no oni dobavlyayut znachitelnyye nakladnyye raskhody. Oni trebuyut bolshe pamyati, dolshe zapuskayutsya i vvodyat slozhnost (ingress-controllery, servisnyye mesh, klassy khraneniya), kotoraya vam prosto ne nuzhna, kogda vy iteriruyete nad odnoy funktsiyey. Zapusk Kubernetes lokalno polezen dlya testirovaniya spetsificheskogo povedeniya Kubernetes — vrode politik eviktsii podov, gorizontalnogo avtomaticheskogo masshtabirovaniya podov ili polzovatelskikh opredeleniy resursov — no eto ne zamena Compose v povsednevnoy razrabotke.
- Ispolzuyte Docker Compose dlya lokalnoy razrabotki. On bystr, prost i pryamo otobrazhayetsya na konteynery, kotoryye vy zapuskayete.
- Ispolzuyte Kubernetes (cherez Minikube ili Kind) dlya integracionnogo testirovaniya, kogda vasha produktsionnaya infrastruktura ispolzuyet funktsii Kubernetes, takie kak ConfigMaps, Secrets ili polzovatelskiye controllery.
- Ispolzuyte udalennyy klaster razrabotki tolko kogda vam nuzhen dostup k GPU, spetsializirovannoye oborudovaniye ili obshchaya sreda steydzhina, kotoraya tochno otrazhayet produktsiyu.
- Ne zapuskayte dva Kubernetes-klastera lokalno tolko potomu, chto u vas dve sredy. Compose obrabatyvayet eto odnym flagom --profile.
- Yesli vasha komanda tratit bolshe vremeni na otladku konfiguratsiy Kubernetes, chem na napisaniye koda prilozheniya, vy zashli slishkom daleko. Vernites k Compose i dobavlyayte slozhnost tolko togda, kogda bol ot yeye otsutstviya prevysit bol ot yeye podderzhaniya.
Obshchiye lovushki i kak ikh izbezhat
Dazhe posle togo, kak vy ponyali kontseptsii, opredelennyye oshibki povtoryayutsya v komandakh. Vot te, kotoryye stoit zapomnit, chtoby propustit dvukhdnevnyye sessii otladki.
Khaos s tegami obrazov — eto samaya rasprostranyonnaya produktsionnaya problema. Ispolzovaniye latest v kachestve tega obraza v Deployment Kubernetes oznachayet, chto vy ne mozhete skazat, kakaya versiya zapushchena na kakoy node. Kubernetes tyanet obraz tolko yesli yego net na node, tak chto latest na odnoy node mozhet byt drugoy versiyey, chem latest na drugoy. Vsegda ispolzuyte semanticheskiye versii ili SHA commitov. Yeshche luchshe — ispolzuyte polnostyu kvalifitsirovannyy digest obraza; eto yedinstvennoye, chto garantirovanno neizmenno.
Zaprosy i limiti resursov chasto opuskayutsya ili ustanavlivayutsya proizvolno. Yesli vy ne ustanavlivayete zaprosy, Kubernetes ne mozhet intellektualno planirovat vashi Pody, i nodi okazyvayutsya peregruzhennymi. Yesli vy ne ustanavlivayete limiti, utechka pamyati v odnom Pode mozhet obrushit drugiye Pody na toy zhe node. Ustanavlivayte i to, i drugoye, i ispolzuyte instrumenty vrode Vertical Pod Autoscaler v rezhime rekomendatsiy dlya ikh nastroyki na osnove fakticheskogo ispolzovaniya.
ConfigMaps i Secrets montiruyutsya kak peremennyye sredy ili fayly. Peremennyye sredy udobny, no lyuboye izmeneniye trebuyet perezapuska Poda, chtoby vstupit v silu. Montirovki na osnove faylov mogut byt obnovleny bez perezapuska (Pod chitayet novoye soderzhimoye pri dostupe k faylu), no mnogiye prilozheniya keshiruyut konfiguratsiyu pri zapuske. Znayte, kakoy shablon ispolzuyet vashe prilozheniye, i proyektiruyte svoy podkhod k konfiguratsii sootvetstvenno.
Postoyannyye tomu v Kubernetes — eto ne volshebstvo. PersistentVolumeClaim zaprashivayet khranilishche, no nizhestoyashchiy klass khraneniya dolzhen byt nastroen dlya vashego oblachnogo provaydera. Klassy khraneniya po umolchaniyu mogut ispolzovat setevoye khranilishche, kotoroye imeyet drugiye kharakteristiki proizvoditelnosti, chem lokalnyye SSD. Yesli proizvoditelnost vashey bazy dannykh vazhna, testiruyte svoy klass khraneniya do vykhoda v produktsiyu.
Logirovaniye i otladka v Kubernetes slozhneye, chem na odnom servere. Pody efemerny, poetomu logi ischezayut pri udalenii Poda. Ispolzuyte kubectl logs --tail=50 -f pod-name dlya zhivogo striminga, no dlya produktsionnoy otladki vam nuzhno tsentralizovannoye resheniye dlya logirovaniya (Loki, Elasticsearch ili oblachnaya sluzhba logirovaniya). Analogichno, vypolnyayte exec v Pod cherez kubectl exec -it pod-name -- sh dlya inspektsii rabotayushchego konteynera, no pomnite, chto lyubyye izmeneniya, kotoryye vy delayete vnutri rabotayushchego konteynera, teryayutsya pri perezapuske.
Deystvitelno li vam nuzhen Kubernetes?
Eto vopros, kotoryy nikto ne khochet zadavat, potomu chto Kubernetes khorosho vyglyadit v inzhenernom rezyume i signaliziruyet ob operatsionnoy zrelosti. No Kubernetes — eto resheniye konkretnoy problemy: zapusk neskolkikh konteynerizovannykh servisov na neskolkikh mashinakh s avtomaticheskim vosstanovleniyem, masshtabirovaniyem i razvertyvaniyem po ocheredi. Yesli u vas odin ili dva servisa rabotayushchikh na odnom servere, Kubernetes — eto perebor.
Vot pryamaya ramka prinyatiya resheniy. Yesli vy razvertyvayete odno prilozheniye, kotoroye obsluzhivayet menshe desyati tysyach zaprosov v sekundu, odin server s Docker Compose v produktsii (da, Compose otlichno rabotayet v produktsii dlya mnogikh nagruzok) budet sluzhit vam khorosho. Dobavte obratnyy proksi vrode Caddy ili Nginx, nastroyte avtomaticheskiye rezervnyye kopii, i u vas budet produktsionnaya sistema, kotoruyu odin razrabotchik mozhet ponyat i podderzhivat polnostyu.
Perekhodite na Kubernetes, kogda u vas yest neskolko servisov, kotoryye nuzhno razvertyvat nezavisimo, kogda vam nuzhno masshtabirovaniye po servisam (vashemu API nuzhno desyat replik, a vashemu rabotniku — tolko dve), kogda vam nuzhny razvertyvaniya bez prostoya kak rutinnaya operatsiya, ili kogda v vashey komande yest khotya by odin chelovek, chyey osnovnoy otvetstvennostyu yavlyayetsya infrastruktura. Do vypolneniya etikh usloviy operatsionnaya stoimost Kubernetes — kak v upravlenii klasterom, tak i v kognitivnoy nagruzke na razrabotchika — yavlyayetsya chistym minusom.
Mnogiye komandy vyigryvayut ot serediny. Ispolzuyte Docker Compose dlya lokalnoy razrabotki i upravlyayemuyu kontener-platformu vrode AWS App Runner, Google Cloud Run ili Fly.io dlya produktsii. Eti platformy dayut vam razvertyvaniye konteynerov, avtomaticheskiy HTTPS i masshtabirovaniye bez neobkhodimosti upravlyat ploskostyu upravleniya Kubernetes. Vy poluchayete bolshuyu chast preimushchestv konteynerizatsii bez krivoy obucheniya Kubernetes.
Luchshaya strategiya infrastruktury — eto ta, kotoraya pozvolyayet vashey komande dostavlyat funktsii. Docker i Kubernetes — eto instrumenty, a ne identichnosti. Ispolzuyte ikh, kogda oni pomogayut, i propuskayte, kogda oni net.
