I kommentaren till min artikel fanns det mÄnga förfrÄgningar om att förklara vad som Àr sÄ hemskt med den Dockerfile som beskrivs i den.
Sammanfattning av föregÄende avsnitt: tvÄ utvecklare under en strÀng deadline skriver en Dockerfile. Under processen kommer Ops Igor Ivanovich in. Den slutgiltiga Dockerfile Àr sÄ dÄlig att Igor Ivanovich nÀstan fÄr en hjÀrtattack.

LÄt oss nu reda ut vad som Àr fel med den hÀr Dockerfile.
SÄ, en vecka har gÄtt.
Utvecklare Petya trÀffar Ops Igor Ivanovich i matsalen över en kopp kaffe.
P: Igor Ivanovich, Àr du mycket upptagen? Jag skulle vilja gÄ igenom var vi gjorde fel.
II: Det Àr bra, man trÀffar sÀllan utvecklare som Àr intresserade av drift.
Först, lÄt oss komma överens om nÄgra saker:
- Docker-ideologi: en container â en process.
- Ju mindre containern Àr, desto bÀttre.
- Ju mer som tas frÄn cachen, desto bÀttre.
P: Men varför ska det bara vara en process i en container?
II: NÀr Docker startar en container övervakar den tillstÄndet för processen med pid 1. Om processen dör försöker Docker starta om containern. Anta att du har flera applikationer som körs i containern eller att den huvudsakliga applikationen inte körs med pid 1. Om processen dör fÄr Docker inte veta det.
Om det inte finns nÄgra fler frÄgor, visa din Dockerfile.
Och Petya visade:
FROM ubuntu:latest
# Kopiera kÀllkoden
COPY . /app
WORKDIR /app
# Uppdaterar paketlistan
RUN apt-get update
# Uppdaterar paketen
RUN apt-get upgrade
# Installerar nödvÀndiga paket
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
# Installerar bundler
RUN gem install bundler
# Installerar nodejs som anvÀnds för att bygga statiken
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
# Installerar beroenden
RUN bundle install --without development test --path vendor/bundle
# Rensar cachar
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ör skriptet vid start av containern som startar allt annat.
CMD ["/app/init.sh"]II: à h, lÄt oss gÄ igenom det steg för steg. Vi börjar med den första raden:
FROM ubuntu:latestDu tar taggen latest. Att anvÀnda taggen latest kan leda till oförutsÀgbara konsekvenser. TÀnk dig att underhÄllaren av bilden bygger en ny version av bilden med en annan programvarulista, denna bild fÄr taggen latest. Och din container slutar i bÀsta fall att byggas, och i vÀrsta fall fÄr du buggar som du inte hade tidigare.
Du tar en bild med ett fullt operativsystem som har en massa onödig programvara, vilket ökar storleken pÄ containern. Ju mer programvara, desto fler sÀkerhetshÄl och sÄrbarheter.
Dessutom, ju större bilden Àr, desto mer utrymme tar den pÄ vÀrden och i registret (du har ju nÄgonstans att lagra bilderna)?
P: Ja, sjÀlvklart, vi har ett register, du har ju konfigurerat det.
AI: SÄ, vad var jag inne pÄ?.. Aha, storlekar⊠Belastningen pÄ nÀtverket ökar ocksÄ. För en enskild bild mÀrks det inte, men nÀr du har kontinuerlig byggnation, tester och distribution, blir det pÄtagligt. Och om du inte har GudslÀget pÄ AWS, sÄ fÄr du Àven en astronomisk rÀkning.
DÀrför behöver du vÀlja den mest lÀmpliga bilden, med exakt version och minimi programvara. Till exempel, ta: FROM ruby:2.5.5-stretch
P: à h, jag förstÄr. Hur och var kan jag se de befintliga bilderna? Hur vet jag vilken jag behöver?
AI: Vanligtvis hÀmtas bilder frÄn , blanda inte ihop det med Pornhub :). För en bild finns det vanligtvis flera versioner:
Microsoft har meddelat om utvidgning av funktionaliteten i WSL2.: bilder som Àr byggda pÄ en minimalistisk Linux-bild, bara 5 MB. Nackdelen Àr att den Àr byggd med en egen implementation av libc, standardpaket fungerar inte. Det kan ta tid att hitta och installera det önskade paketet.
Scratch: grundbild som inte anvÀnds för att bygga andra bilder. Den Àr utformad för att köra binÀra, förberedd data. Den Àr perfekt för att köra binÀra applikationer som innehÄller allt som behövs, som till exempel Go-applikationer.
Baserat pÄ nÄgot operativsystem, som Ubuntu eller Debian. HÀr behöver jag nog inte förklara mer.
AI: Nu behöver vi installera alla tillÀggspaket och rensa vÄra cache. Och vi kan genast ta bort apt-get upgrade. Annars kommer olika versioner av bilderna att skapas vid varje byggnation, trots att basbildens tagg Àr faststÀlld. Att uppdatera paketen i bilden Àr en maintainer-uppgift som innebÀr att taggen Àndras.
P: Ja, jag försökte göra det, och sÄ hÀr blev det:
WORKDIR /app
COPY ./ /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: Inte dÄligt, men det finns ocksÄ saker att förbÀttra. Titta, det hÀr kommandot:
RUN rm -rf /usr/local/bundle/cache/*.gem
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ⊠tar bort inte data frÄn den slutgiltiga bilden, utan skapar endast ett extra lager utan dessa data. RÀtt sÄ:
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/* Men det Àr inte allt. Har du Ruby dÀr? DÄ behöver du inte kopiera hela projektet i början. Det rÀcker att kopiera Gemfile och Gemfile.lock.
Med denna metod kommer bundle install inte att köras vid varje Àndring av kÀllkoden, utan endast om Gemfile eller Gemfile.lock har Àndrats.
Samma metoder fungerar Àven för andra sprÄk med beroendehanterare, sÄsom npm, pip, composer och andra som baseras pÄ en fil med en lista över beroenden.
Och slutligen, minns du att jag i början pratade om Docker-ideologin âen container â en processâ? Det betyder att en övervakare inte behövs. Du bör inte heller installera systemd av samma skĂ€l. I praktiken Ă€r Docker sjĂ€lv en övervakare. Och nĂ€r du försöker köra flera processer i den, Ă€r det som att köra flera applikationer i en övervakare.
Vid byggandet kommer du att skapa en enhetlig bild och sedan starta det nödvÀndiga antalet containrar sÄ att en process körs i varje.
Men mer om det senare.
Q: Det verkar som jag har förstÄtt. Titta, vad vi har:
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"]Men ska vi omdefiniera att starta demoner vid containerstart?
AI: Ja, precis. Förresten kan du anvÀnda bÄde CMD och ENTRYPOINT. Att ta reda pÄ skillnaden Àr din lÀxa. Det finns bra information om detta pÄ Habré. .
SÄ, lÄt oss gÄ vidare. Du laddar ner installationsfilen för node, men det finns ingen garanti för att den innehÄller det du behöver. Vi mÄste lÀgga till validering. Till exempel sÄ hÀr:
KĂR 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/* Genom kontrollsumman kan du kontrollera att du har laddat ner rÀtt fil.
P: Men om filen Àndras kommer byggnaden att misslyckas.
AI: Ja, och konstigt nog Àr det ocksÄ en fördel. Du kommer att fÄ veta att filen har Àndrats och kan kika pÄ vad som har Àndrats. Man vet ju aldrig, de kanske har lagt till ett skript som raderar allt det rör vid, eller skapar en bakdörr.
P: Tack. SÄ den slutgiltiga Dockerfile kommer att se ut sÄ hÀr:
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, tack för hjÀlpen. Jag mÄste redan skynda mig, jag behöver göra 10 commits till idag.
Igor Ivanovich, som stoppade den brÄdskande kollegan med blicken, tar en klunk starkt kaffe. Efter att ha funderat i nÄgra sekunder om SLA pÄ 99,9 % och kod utan buggar stÀller han en frÄga.
AI: Var lagrar ni loggarna?
P: SjÀlvklart i production.log. Förresten, hur fÄr vi Ätkomst till dem utan ssh?
AI: Om ni lÀmnar dem i filer har vi redan en lösning för er. Kommandot docker exec tillÄter att köra vilket kommando som helst i containern. Till exempel kan ni göra cat för loggarna. Och om ni anvÀnder nyckeln -it och startar bash (om det Àr installerat i containern), fÄr ni interaktiv tillgÄng till containern.
Men det Àr inte bra att lagra loggar i filer. Minst sagt leder det till okontrollerad tillvÀxt av containern, loggarna roteras ju inte. Alla loggar bör skickas till stdout. DÀr kan de sedan ses med kommandot docker logs.
P: Igor Ivanovich, kanske vi kan flytta loggarna till en monterad katalog pÄ den fysiska noden, som anvÀndardata?
AI: Bra att ni inte glömde att flytta data som laddats till nodens disk. Loggar kan ocksÄ hanteras pÄ det sÀttet, men glöm inte att stÀlla in rotation.
Okej, du kan gÄ nu.
P: Igor Ivanovich, kan du rekommendera nÄgot att lÀsa?
AI: För att börja, lÀs , knappast nÄgon kan Docker bÀttre Àn de.
Och om du vill praktisera, gÄ pÄ . Teori utan praktik Àr död.
KĂ€lla: habr.com
