Pierwszy artykuł z serii “Docker”. Postaram się w nim opisać sposoby na optymalizacje obrazu Dockera pod względem wielkości. Jest to dość istotny parametr obrazu, bo od niego zalezy szybkość wprowadzenia zmian na środowisko jak i ilość zajętego miejsca w całym klastrze (np. Kubernetesa).
Zainstalowałeś to posprzątaj
Najważniejszą rzeczą jest sprzątanie po instalacji oprogramowania w kontenerze. Dla przykładu posłużymy się obrazem którego używam do pisania artykułów na tym bloga.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM ruby:2.4
MAINTAINER Łukasz Żułnowski "lzulnowski@gmail.com"
RUN apt-get update && apt-get install -y -q \
build-essential \
wget \
curl
RUN gem install jekyll bundler
RUN mkdir -p /app
WORKDIR /app
EXPOSE 4000
CMD bundle install && bundle exec jekyll serve -H 0.0.0.0
Po zbudowaniu obraz wygląda następują:
1
2
3
4
docker build . -t blog
docker images blog
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest d21d207746fe 40 seconds ago 801MB
Dodajmy czyszczenie obrazu po instalacji pakietów za pomocą apt-get oraz kasujemy niepotrzebne pliki tymczasowe i man oraz dokumentacje. zbudujmy obraz jeszcze raz zobaczymy co się udało zaoszczędzić.
1
2
3
4
5
6
7
8
9
10
11
12
13
RUN apt-get update && apt-get install -y -q \
build-essential \
wget \
vim \
curl \
&& apt-get clean \
&& rm -rf \
/var/lib/apt/lists/* \
/tmp/* \
/var/tmp/* \
/usr/share/man \
/usr/share/doc \
/usr/share/doc-base
Po zbudowaniu obraz wygląda następująco:
1
2
3
docker images blog
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest 030a09e675d7 About a minute ago 729MB
Jak widać udało nam się zaoszczędzić trochę miejsca. Niby nic, ale w przypadku gdy doinstalujemy dużo zalezności potrafi to być gigantyczna przestrzeń.
Ważne: Czyszczenie powinno być zawsze wykonane w tej warstwie którą chcemy czyścić. Dodanie nowej warstwy tylko zwiększy obraz.
Instalujmy tylko to co jest nam potrzebne
Kolejnym sposobem z użyciem apt jest instalowanie tylko paczek, które naprawde są nam potrzebne. Do naszego polecenia dodamy przełącznik dzięki któremu nie zainstalują się paczki zależności opcjonalne których najczęściej nie potrzebujemy. Jeśli jest inaczej warto je wpisać do Dockerfile.
1
2
3
4
RUN apt-get update && apt-get install --no-install-recommends -y -q \
build-essential \
wget \
curl \
A tak wygląda obraz po tym zabiegu:
1
2
3
docker images blog
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest d632fd938793 4 seconds ago 708MB
Na tej operacji aż tak dużo nie uzyskaliśmy. Przy innych pakietach może być to bardziej korzystne. Tą metodę można znaleść w wielu oficjalnych obrazach np: elasticsearch
Obsługa zdalnych skryptów czy paczek
W przypadku gdy musimy użyć skryptu umieszczonego na przykład na GitHub nie powinniśmy go zostawiać w obrazie jeśli nie używamy go podczas pracy kontenera. To samo się tyczy paczek zip/tar itp.
Jak obsłużyć takie przypadki. Można to zrobić na 2 sposoby.
- Bespośrednie wykonanie skryptu bez zapisywania
1
RUN curl -sL https://deb.nodesource.com/setup_8.x |bash -
- Zapisanie i usunięcie w ramach jednej warstwy
1
2
3
RUN curl -sL https://deb.nodesource.com/setup_8.x \
&& bash ./setup_8.x \
&& rm -rf ./setup_8.x
Używanie odpowiednich obrazów
DockerHub jest pełny gotowych obrazów, lepszy i gorszych. Warto poświęcić wiecej czasu na znalezienie odpowiedniego obrazu dla siebie albo stworzyć go od podstaw. W trakcie tego artykułu zobaczyłem że nie potrzebnie używam tak dużego obrazu. Jest dostępny oficjalny obraz ruby który zawiera wszystko co jest mi potrzebne do pracy. Zobaczmy jak to będzie wyglądać:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM ruby:2.4-slim
MAINTAINER Łukasz Żułnowski "lzulnowski@gmail.com"
RUN apt-get update && apt-get install -y -q \
build-essential \
wget \
curl
RUN gem install jekyll bundler
RUN mkdir -p /app
WORKDIR /app
EXPOSE 4000
CMD bundle install && bundle exec jekyll serve -H 0.0.0.0
Jak widac zmieniony został tylko obraz którego użyliśmy jako bazy
1
2
3
docker images blog
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest 3143d1c2fa63 19 seconds ago 461MB
No i to jest optymalizacja, obraz zmniejszony został o więcej niż połowę.
Ilość warstw i ich kolejność
W tej kwesti zdania są podzielone. Niektórzy twierdzą że czym więcej tym lepiej a inni że wszystko w jednej warstwie. Ja stosuje zasadę czytelności. Staram się mieć jak najmniej warst ale też pilnuje żeby plik Dockerfile był podzielony na sekcje żeby utrzymanie obrazu było łatwiejsze.
Dodatkowo złotą zasadą, która przyśpiesza budowanie obrazu jest umieszczanie kodu aplikacji i często zmieniających się zależności na samym końcu. Dzięki temu proces CI jest szybszy bo nie ma konieczności przebudowania całego obrazu, a jedynie części, która się zmienia.
Przy tworzeniu Dockerfile’a trzeba brać pod uwagę całkiem inne aspekty niż podczas tradycyjnego stawiania środowiska. Te kilka trików pozwoli na tworzenie lekkich obrazów a w dodatku mamy wszystko pod kontrolą.