6.1 Wprowadzenie do optymalizacji obrazów
Obrazy Docker, mimo że są kompaktowe, zajmują jednak miejsce. Dlatego zmniejszenie ich rozmiarów to ważne zadanie, które pomaga poprawić wydajność, przyspieszyć ładowanie i wdrażanie kontenerów, a także zmniejszyć koszty przechowywania. Obraz można zoptymalizować poprzez ulepszenie Dockerfile, ponieważ można go zorganizować na różne sposoby. W tym wykładzie przeanalizujemy kilka strategii i najlepszych praktyk tworzenia zoptymalizowanych i lekkich obrazów Docker.
Dlaczego ważne jest zmniejszenie rozmiaru obrazów Docker?
- Szybkość wdrażania: mniejsze obrazy szybciej ładują się z rejestru Docker i są wdrażane w kontenerach, co jest szczególnie istotne w zautomatyzowanych systemach CI/CD.
- Efektywne wykorzystanie zasobów: lekkie obrazy zajmują mniej miejsca na dysku, oszczędzają zasoby sieciowe podczas transmisji i zapewniają bardziej efektywne wykorzystanie mocy obliczeniowej.
- Bezpieczeństwo: mniejsze obrazy zazwyczaj zawierają mniej niepotrzebnych komponentów, co zmniejsza ryzyko potencjalnych luk w zabezpieczeniach.
- Uproszczenie aktualizacji: aktualizacja lekkich obrazów odbywa się szybciej i wymaga mniej zasobów, co przyspiesza proces wsparcia.
6.2 Strategie redukcji rozmiaru obrazów Docker
1. Korzystanie z minimalnych obrazów bazowych
Wybór obrazu bazowego bezpośrednio wpływa na rozmiar końcowego obrazu Docker. Korzystanie z minimalnych obrazów bazowych, takich jak alpine
, pozwala znacząco zmniejszyć rozmiar obrazu.
Przykład:
Zamiana obrazu ubuntu
na alpine
:
# FROM ubuntu:20.04
FROM alpine:3.12
alpine
— to lekka dystrybucja Linuxa, która zajmuje około 5 MB, podczas gdy obraz ubuntu
może zajmować setki megabajtów.
2. Minimalizacja liczby warstw
Każda instrukcja w Dockerfile dodaje nową warstwę do obrazu. Łączenie kilku poleceń w jednej instrukcji RUN
zmniejsza liczbę warstw, co pomaga zredukować całkowity rozmiar obrazu.
Przykład:
Przed optymalizacją:
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*
Po optymalizacji:
RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/*
Usuwanie pamięci podręcznej menedżera pakietów (rm -rf /var/lib/apt/lists/*)
dodatkowo zmniejsza rozmiar obrazu, usuwając pliki tymczasowe utworzone podczas instalacji.
3. Usuwanie plików tymczasowych
Usuwanie plików tymczasowych i niepotrzebnych danych po instalacji pakietów pomaga utrzymać obraz czysty i lekki.
Przykład:
RUN apt-get update && apt-get install -y curl git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
4. Korzystanie z .dockerignore
Plik .dockerignore
pomaga wykluczyć niepotrzebne pliki i katalogi z kontekstu budowy, co zmniejsza rozmiar obrazu i przyspiesza proces budowy.
Przykład .dockerignore
:
node_modules
dist
*.log
Dockerfile*
.dockerignore
5. Budowa wieloetapowa (multi-stage builds)
Budowa wieloetapowa pozwala używać kilku pośrednich obrazów do stworzenia końcowego lekkiego obrazu, zawierającego tylko potrzebne pliki i zależności.
Przykład:
# Etap budowy
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Etap końcowy
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
W tym przykładzie pierwszy etap tworzy budowę aplikacji, a końcowy etap korzysta tylko z wyników budowy, co zmniejsza rozmiar końcowego obrazu.
6. Optymalizacja instalacji pakietów
Instalowanie tylko potrzebnych pakietów i korzystanie z opcji menedżerów pakietów dla minimalnej instalacji pomaga zmniejszyć rozmiar obrazu.
Przykład:
Korzystanie z parametru --no-install-recommends
dla apt-get
:
RUN apt-get update && apt-get install -y --no-install-recommends curl git && \
rm -rf /var/lib/apt/lists/*
7. Kompresja i minimalizacja danych
Korzystanie z narzędzi do kompresji i minimalizacji danych pomaga zmniejszyć rozmiar obrazu.
Przykład:
Kompresja plików tekstowych i logów:
RUN gzip /path/to/large/file.log
8. Usuwanie nieużywanych bibliotek i zależności
Usuwanie nieużywanych bibliotek i zależności po instalacji potrzebnych pakietów pomaga utrzymać obraz lekki.
Przykład:
Dla aplikacji Python:
RUN pip install --no-cache-dir -r requirements.txt
6.3 Przykłady zoptymalizowanych Dockerfile
Przykład 1: Zoptymalizowany Dockerfile dla Node.js
FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
Ten przykład korzysta z wieloetapowego budowania. Najpierw aplikacja jest budowana w etapie pośrednim, a potem tylko wyniki budowy są kopiowane do finalnego obrazu na bazie Nginx.
Przykład 2: Zoptymalizowany Dockerfile dla Pythona
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
W tym przykładzie używany jest lekki obraz bazowy python:3.9-slim
. Instalacja zależności jest przeniesiona do osobnego kroku, co pozwala na użycie cache Docker, jeśli plik requirements.txt
nie został zmieniony.
GO TO FULL VERSION