Docker: fena tavsiye değil

Makaleme yapılan yorumlarda Docker: kötü tavsiye İçinde anlatılan Dockerfile'ın neden bu kadar korkunç olduğunu açıklamak için birçok istek vardı.

Önceki bölümün özeti: İki geliştirici, sıkı bir son teslim tarihi altında bir Docker dosyası oluşturur. Bu süreçte Ops Igor Ivanovich onlara geliyor. Ortaya çıkan Dockerfile o kadar kötü ki yapay zeka kalp krizinin eşiğinde.

Docker: fena tavsiye değil

Şimdi bu Dockerfile'da neyin yanlış olduğunu bulalım.

Böylece bir hafta geçti.

Dev Petya, yemek odasında bir fincan kahve içerken Ops Igor Ivanovich ile buluşuyor.

P: Igor Ivanovich, çok meşgul müsün? Nerede hata yaptığımızı bulmak isterim.

AI: Bu iyi, istismarla ilgilenen geliştiricilerle sık sık karşılaşmıyorsunuz.
Öncelikle birkaç konuda anlaşalım:

  1. Docker ideolojisi: tek konteyner – tek süreç.
  2. Konteyner ne kadar küçük olursa o kadar iyidir.
  3. Önbellekten ne kadar çok şey alırsanız o kadar iyidir.

P: Neden bir kapta tek bir süreç olsun ki?

AI: Docker, bir konteyneri başlatırken işlemin durumunu pid 1 ile izler. İşlem ölürse Docker konteyneri yeniden başlatmaya çalışır. Diyelim ki bir konteynerde çalışan birden fazla uygulamanız var veya ana uygulama pid 1 ile çalışmıyor. Eğer süreç ölürse Docker'ın bundan haberi olmayacaktır.

Başka sorunuz yoksa lütfen bize Docker dosyanızı gösterin.

Ve Petya şunu gösterdi:

FROM ubuntu:latest

# Копируем исходный код
COPY ./ /app
WORKDIR /app

# Обновляем список пакетов
RUN apt-get update 

# Обновляем пакеты
RUN apt-get upgrade

# Устанавливаем нужные пакеты
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor

# Устанавливаем bundler
RUN gem install bundler

# Устанавливаем nodejs используется для сборки статики
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs

# Устанавливаем зависимости
RUN bundle install --without development test --path vendor/bundle

# Чистим за собой кэши
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
# Запускаем скрипт, при старте контейнера, который запустит все остальное.
CMD ["/app/init.sh"]

AI: Ah, hadi sırayla ele alalım. İlk satırla başlayalım:

FROM ubuntu:latest

Sen etiketi al latest. Etiket kullanma latest öngörülemeyen sonuçlara yol açar. Görüntü bakımcısının farklı bir yazılım listesiyle görüntünün yeni bir sürümünü oluşturduğunu düşünün, bu görüntü en son etiketi alır. Ve konteyneriniz en iyi ihtimalle inşaatı durdurur ve en kötü ihtimalle daha önce var olmayan hataları yakalarsınız.

Kabın hacmini şişiren birçok gereksiz yazılıma sahip tam teşekküllü bir işletim sistemi ile görüntü çekiyorsunuz. Ve ne kadar çok yazılım, o kadar çok delik ve güvenlik açığı demektir.

Ayrıca, görüntü ne kadar büyük olursa, ana bilgisayarda ve kayıt defterinde o kadar fazla yer kaplar (görüntüleri bir yerde saklıyor musunuz)?

P: Evet tabi ki kayıt defterimiz var onu siz ayarlayacaksınız.

AI: Peki neden bahsediyorum?.. Ah evet, hacimler... Ağ üzerindeki yük de artıyor. Tek bir görüntü için bu farkedilemez, ancak sürekli bir oluşturma, testler ve dağıtım olduğunda fark edilir. AWS'de Tanrı'nın modu yoksa kozmik bir fatura da alırsınız.

Bu nedenle, tam sürüm ve minimum yazılımla en uygun görüntüyü seçmeniz gerekir. Örneğin şunu alın: FROM ruby:2.5.5-stretch

P: Ah, anlıyorum. Mevcut görselleri nasıl ve nerede görüntüleyebilirim? Hangisine ihtiyacım olduğunu nasıl bilebilirim?

AI: Genellikle görüntüler alınır Liman işçisi, pornhub'la karıştırmayın :). Bir görüntü için genellikle birkaç montaj vardır:
Alp: görüntüler yalnızca 5 MB boyutunda minimalist bir Linux görüntüsünde toplanır. Dezavantajı: kendi libc uygulamasıyla derlenmesidir, standart paketler içinde çalışmaz. Gerekli paketi bulmak ve yüklemek çok zaman alacaktır.
çizik: temel görüntü, başka görüntüler oluşturmak için kullanılmaz. Yalnızca ikili, hazırlanmış verileri çalıştırmak için tasarlanmıştır. GO uygulamaları gibi ihtiyacınız olan her şeyi içeren ikili uygulamaları çalıştırmak için idealdir.
Ubuntu veya Debian gibi herhangi bir işletim sistemini temel alır. Neyse açıklamaya gerek yok sanırım.

AI: Şimdi tüm ekstraları yüklememiz gerekiyor. paketleri açın ve önbelleklerinizi temizleyin. Ve onu hemen atabilirsin apt-get yükseltmesi. Aksi takdirde, her derlemede temel görüntünün sabit etiketine rağmen farklı görüntüler elde edilecektir. Görüntüdeki paketleri güncellemek bakımcının görevidir ve buna etiketin değiştirilmesi de eşlik eder.

P: Evet denedim, şöyle oldu:

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: Fena değil ama üzerinde çalışılacak bir şey de var. Bakın, işte bu komut:

RUN rm -rf /usr/local/bundle/cache/*.gem 
    && apt-get clean  
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*  

... son görüntüdeki verileri silmez, yalnızca bu veriler olmadan ek bir katman oluşturur. Doğru şekilde şu şekilde:

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/* 

Ama hepsi bu değil. Orada ne var Ruby? O zaman başlangıçta projenin tamamını kopyalamanıza gerek kalmaz. Gemfile ve Gemfile.lock'u kopyalamanız yeterlidir.

Bu yaklaşımla, paket kurulumu her kaynak değişikliğinde değil, yalnızca Gemfile veya Gemfile.lock değiştiğinde yürütülecektir.

Aynı yöntemler, bağımlılık listesi içeren bir dosyaya dayalı olarak npm, pip, besteci ve diğerleri gibi bir bağımlılık yöneticisine sahip diğer diller için de çalışır.

Ve son olarak, başlangıçta Docker'ın "tek konteyner - tek süreç" ideolojisinden bahsettiğimi hatırlıyor musunuz? Bu, bir denetçiye ihtiyaç olmadığı anlamına gelir. Aynı nedenlerden dolayı systemd'yi de kurmamalısınız. Aslında Docker'ın kendisi bir süpervizördür. Ve içinde birden fazla işlemi çalıştırmaya çalıştığınızda, bu, tek bir denetleyici sürecinde birden fazla uygulamayı çalıştırmaya benziyor.
Oluştururken, tek bir görüntü oluşturacak ve ardından her birinde bir işlemin çalışması için gereken sayıda kapsayıcıyı başlatacaksınız.

Ama bunun hakkında daha sonra.

P: Sanırım anladım. Bakın ne oluyor:

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"]

Konteyneri başlatırken arka plan programlarının başlatılmasını geçersiz kılabilir miyiz?

AI: Evet, doğru. Bu arada hem CMD'yi hem de ENTRYPOINT'i kullanabilirsiniz. Ve farkın ne olduğunu bulmak sizin ödevinizdir. Habré'de bu konuyla ilgili güzel bir konu var makale.

Öyleyse devam edelim. Düğümü yüklemek için bir dosya indirirsiniz, ancak bunun ihtiyacınız olanı içereceğinin garantisi yoktur. Doğrulama eklememiz gerekiyor. Örneğin şöyle:

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/* 

Sağlama toplamını kullanarak doğru dosyayı indirdiğinizi doğrulayabilirsiniz.

P: Ancak dosya değişirse derleme başarısız olur.

AI: Evet ve tuhaf bir şekilde bu da bir artı. Dosyanın değiştiğini bileceksiniz ve orada neyin değiştiğini görebileceksiniz. Asla bilemezsiniz, mesela ulaşabildiği her şeyi silen veya bir arka kapı oluşturan bir komut dosyası eklediler.

Teşekkür ederim. Son Dockerfile'ın şöyle görüneceği ortaya çıktı:

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, yardımınız için teşekkür ederim. Koşma zamanım geldi, bugün 10 taahhüt daha yapmam gerekiyor.

Aceleci meslektaşını bakışlarıyla durduran Igor Ivanovich, sert kahvesinden bir yudum alıyor. %99.9 SLA ve hatasız kod hakkında birkaç saniye düşündükten sonra bir soru sorar.

AI: Günlükleri nerede saklıyorsunuz?

P: Tabii ki, Production.log'da. Bu arada evet ama ssh olmadan bunlara nasıl erişebiliriz?

AI: Bunları dosyalarda bırakırsanız sizin için zaten bir çözüm bulunmuş demektir. Docker exec komutu, bir kapta herhangi bir komutu yürütmenize olanak tanır. Örneğin kütükler için cat komutunu kullanabilirsiniz. Ve anahtarı kullanarak -o ve bash'ı çalıştırmak (eğer konteynere yüklenmişse) size konteynere etkileşimli erişim sağlayacaktır.

Ancak günlükleri dosyalarda saklamamalısınız. Bu, en azından kabın kontrolsüz büyümesine yol açar ve hiç kimse kütükleri döndürmez. Tüm günlükler stdout'a gönderilmelidir. Orada zaten komut kullanılarak görüntülenebilirler liman işçisi günlükleri.

P: Igor Ivanovich, belki günlükleri kullanıcı verileri olarak fiziksel bir düğümdeki monte edilmiş bir dizine koyabilirim?

AI: Düğümün diskine yüklenen verileri kaldırmayı unutmamanız iyi oldu. Bunu loglarla da yapabilirsiniz, sadece rotasyonu ayarlamayı unutmayın.
İşte bu, koşabilirsin.

P: Igor Ivanovich, bana ne okumam gerektiğini tavsiye edebilir misin?

AI: İlk önce oku Docker geliştiricilerinden önerilerDocker'ı onlardan daha iyi tanıyan pek kimse yok.

Staj yapmak istiyorsanız şu adrese gidin: yoğun. Sonuçta pratik olmadan teori ölüdür.

Kaynak: habr.com

Yorum ekle