Minu artikli kommentaarides oli palju palveid selgitada, miks on kirjasolev Dockerfile nii kohutav.
Eelmise osa kokkuvõte: kaks arendajat tiheda tähtaega koostavad Dockerfile'i. Protsessi käigus tuleks nende juurde Ops Igor Ivanovitš. Lõpptulemus on nii halb, et tehisintellekt jääb südamerikkega silmitsi.

Vaadakem nüüd, mis ei ole õigesti selle Dockerfile'i juures.
Nii, nädal on möödunud.
Arendaja Peeter kohtub söökla lauas Ops Igor Ivanovitšiga tassikese kohvi juures.
P: Igor Ivanovitš, kas te olete väga hõivatud? Tahaksin aru saada, kus me eksisime.
II: See on hea, arendajaid, keda huvitab eksploorimine, ei kohtu sageli.
Alustuseks lepime kokku mõnes asjas:
- Docker'i ideoloogia: üks konteiner - üks protsess.
- Mida väiksem konteiner, seda parem.
- Mida rohkem võetakse vahemikust, seda parem.
P: Aga miks peab ühes konteineris olema ainult üks protsess?
Docker jälgib konteineri käivitamisel protsessi seisundit, mille pid on 1. Kui see protsess sureb, püüab Docker konteinerit uuesti käivitada. Oletame, et konteineris jookseb mitu rakendust või peamine rakendus ei ole käivitunud pid 1-ga. Kui protsess sureb, ei saa Docker sellest teada.
Kui küsimusi enam pole, näita oma Dockerfile'i.
Ja Peeter näitas:
FROM ubuntu:latest
# Kopeerime lähtekoodi
COPY ./ /app
WORKDIR /app
# Uuendame paketiloendit
RUN apt-get update
# Uuendame pakette
RUN apt-get upgrade
# Paigaldame vajalikud paketid
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
# Paigaldame bundleri
RUN gem install bundler
# Paigaldame nodejs, mida kasutatakse staatika kokkuvõtmiseks
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
# Paigaldame sõltuvused
RUN bundle install --without development test --path vendor/bundle
# Koristame vahemälud puhtaks
RUN rm -rf /usr/local/bundle/cache/*.gem
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN rake assets:precompile
# Käivitame skripti konteineri käivitamisel, mis käivitab kõik ülejäänu.
CMD ["/app/init.sh"]Ohe, hakkame järk-järgult tegema. Alustame esimisest reast:
FROM ubuntu:latestSa võtad sildi latest. Sildi kasutamine latest viib ettearvamatutele tagajärgedele. Kujutage ette, et pildi hooldaja koondab uue versiooni pildist, millel on erinev tarkvarade nimekiri, see pilt saab tähise latest. Ja teie konteiner ei pruugi üldse koguda või halvemal juhul saate vigu, mida varem polnud.
Te võtate pildi täieliku operatsioonisüsteemiga, kus on palju mittevajalikku tarkvara, mis paisutab konteineri mahtu. Ja mida rohkem tarkvara, seda rohkem on auke ja haavatavusi.
Lisaks, mida suurem on pilt, seda rohkem ruumi see võtab nii hostis kui registry's (kas sa ei hoia pilte kuskil)?
K: Jah, muidugi, meil on registry, te ju seadistati selle.
AI: Nii, millest ma rääkisin?.. Ah jah, mahud... Samuti kasvab koormus võrgus. Ühe pildi puhul on see tundmatu, kuid kui toimub pidev kogumine, testimine ja juurutamine, on see tuntav. Ja kui sul pole AWS-is Jumala režiimi, saad veel ka kosmilise arve.
Seega tuleb valida sobivaim pilt, täpse versiooni ja minimaalsete tarkvaradega. Näiteks, võta: FROM ruby:2.5.5-stretch
K: Okei, selge. Kuidas ja kus vaadata olemasolevaid pilote? Kuidas mõista, mida mul vaja on?
AI: Tavaliselt võetakse pilte , ära aja segi porn hubiga :). Pildi jaoks on tavaliselt mitu versiooni:
Alpine: pildid on koostatud minimalistlikul Linuxi kujul, vaid 5 MB. Puuduseks on see, et see on koostatud oma libc rakendusega, tavalised paketid ei toimi. Sobiva paketi leidmine ja installimine võtab aega.
Scratch: baaspilt, mida ei kasutata teiste piltide koostamiseks. See on mõeldud ainult eelnevalt valmistatud andmete käitamiseks. Sobib ideaalselt binaarsete rakenduste käitamiseks, mis sisaldavad kõike vajalikku, näiteks Go-rakendusi.
Tuginedes mõnele operatsioonisüsteemile, näiteks Ubuntu või Debian. Siin pole arvatavasti vaja lisaselgitusi.
AI: Nüüd peame installima kõik täiendavad paketid ja puhastama vahemälu. Ja võime kohe välja visata apt-get upgrade. Vastupidiselt sellele, iga kord, kui pilt koostatakse, kuigi põhikujul on fikseeritud silt, saavad tulemuseks erinevad pildid. Pakettide värskendamine pildis on hooldajate ülesanne, see kaasneb sildi muutmisega.
Q: Jah, ma proovisin seda teha, see õnnestus mulle nii:
TÖÖKATALOOG /app
KOPEERI ./ /app
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash -
&& apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor nodejs
&& gem install bundler
&& bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*AI: Pole paha, aga siin on ka millega tegeleda. Vaata, see käsk:
RUN rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* … ei eemalda andmeid lõplikust pildist, vaid loob lihtsalt täiendava kihi ilma nende andmeteta. Õige on nii:
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash -
&& apt-get -y install libpq-dev imagemagick gsfonts nodejs
&& gem install bundler
&& bundle install --without development test --path vendor/bundle
&& rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* Aga see pole veel kõik. Mis teil seal on, Ruby? Siis ei ole vaja alguses kogu projekti kopeerida. Piisab, kui kopeerite Gemfile ja Gemfile.lock.
Sellise lähenemise korral ei tehta bundle install'i iga allika muudatuse korral, vaid ainult siis, kui Gemfile või Gemfile.lock on muutunud.
Samad meetodid toimivad ka teiste keelte jaoks, millel on sõltuvuste haldurid, nagu npm, pip, composer ja teised, mis põhinevad sõltuvuste nimekirja failil.
Ja lõpuks, kas mäletad, et alguses rääkisin Docker'i ideoloogiast "üks konteiner — üks protsess"? See tähendab, et superviisorit ei ole vaja. Samuti ei tasu installida systemd, samadel põhjustel. Tegelikult on Docker ise superviisor. Ja kui sa üritad sees käivitada mitut protsessi, on see nagu ühes protsessis superviisor käivitama mitut rakendust.
Kogumise ajal lood ühe pildi ja seejärel käivitad vajaliku arvu konteinerid, et igas töötaks üks protsess.
Aga sellest hiljem.
K: Tundub, et sain aru. Vaadake, mis välja tuleb:
FROM ruby:2.5.5-stretch
WORKDIR /app
COPY Gemfile* /app
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash -
&& apt-get -y install libpq-dev imagemagick gsfonts nodejs
&& gem install bundler
&& bundle install --without development test --path vendor/bundle
&& rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY . /app
RUN rake assets:precompile
CMD ["bundle", "exec", "passenger", "start"]Aga kas me ületame demonite käivitamise konteineri käivitamisel?
AI: Jah, kõik on õige. Muide, saad kasutada nii CMD-d kui ka ENTRYPOINT-i. Ja mõista, mis vahe on, see on sinu kodutöö. Selle teema kohta on Habr's hea artikkel. .
Nii, läheme edasi. Sa laadid alla node'ile installifaili, kuid pole mingit garantiid, et see sisaldab vajalikku. Tuleks lisada valideerimine. Näiteks nii:
RUN curl -sL https://deb.nodesource.com/setup_9.x > setup_9.x
&& echo "958c9a95c4974c918dca773edf6d18b1d1a41434 setup_9.x" | sha1sum -c -
&& bash setup_9.x
&& rm -rf setup_9.x
&& apt-get -y install libpq-dev imagemagick gsfonts nodejs
&& gem install bundler
&& bundle install --without development test --path vendor/bundle
&& rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* Kontrollsummaga saad kontrollida, et oled õige faili alla laadinud.
K: Aga kui fail muutub, siis ehitamine ebaõnnestub.
AI: Jah, ja see on ka pluss. Sa saad teada, et fail on muutunud, ja saad vaadata, mis seal muutunud on. Kes teab, võib-olla on lisatud skript, mis kustutab kõik, millele ta ulatub, või teeb backdoor'i.
K: Aitäh. Niisiis, lõplik Dockerfile näeb välja nii:
FROM ruby:2.5.5-stretch
WORKDIR /app
COPY Gemfile* /app
RUN curl -sL https://deb.nodesource.com/setup_9.x > setup_9.x
&& echo "958c9a95c4974c918dca773edf6d18b1d1a41434 setup_9.x" | sha1sum -c -
&& bash setup_9.x
&& rm -rf setup_9.x
&& apt-get -y install libpq-dev imagemagick gsfonts nodejs
&& gem install bundler
&& bundle install --without development test --path vendor/bundle
&& rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY . /app
RUN rake assets:precompile
CMD ["bundle”, “exec”, “passenger”, “start"]P: Igor Ivanovich, aitäh abi eest. Mul on juba aeg minna, pean täna veel 10 commit'i tegema.
Igor Ivanovich peatab pilguga kiirustava kolleegi ja võtab lonksu tugevat kohvi. Mõeldes paar sekundit SLA 99.9% ja veatu koodi üle, küsib ta küsimuse.
AI: Kuidas te logisid hoiustate?
P: Muidugi, production.log. Üks asi, kuidas me saame neile ssh kaudu juurde?
AI: Kui jätate need failidesse, on lahendus juba välja mõeldud. Käsk 'docker exec' võimaldab teil käivitada mis tahes käsku konteineris. Näiteks võite logide jaoks kasutada 'cat'. Ja kui kasutate lippu -it ja käivitades bash'i (kui see on konteineris paigaldatud), saate interaktiivse juurdepääsu konteinerile.
Aga logide salvestamine failides ei ole mõistlik. See toob vähemalt kaasa konteineri kontrollimatu kasvu, kuna keegi ei roti logisid. Kõik logid tuleks suunata stdout-i. Sealt saab neid vaadata käsuga docker logs.
K: Igor Ivanovitš, kas võiks logid viia mountitud katalooge, füüsilisse sõlme, nagu kasutajaandmed?
AI: Hea, et te ei unustanud andmeid, mis on sõlme kettale laaditud. Logidega on samuti võimalik, lihtsalt ära unusta seada rotatsiooni.
Kõik, nüüd võid minna.
K: Igor Ivanovitš, soovitage, mida lugeda?
AI: Alustuseks loe , tõenäoliselt ei tea keegi Dockerit paremini kui nemad.
Ja kui soovid praktikat, mine . Teooria ilma praktikata on surnud.
Allikas: habr.com
