Strona korzysta z plików cookies w celu realizacji usług i zgodnie z Polityką Plików Cookies.


08.07.2019

Narzędzie EDR

ESET Enterprise Inspector
08.07.2019

Usuwanie skutków awarii

Veeam Availability Orchestrator v2
08.07.2019

Indywidualna konfiguracja

baramundi Management Suite 2019
05.07.2019

Technologia Ceph

SUSE Enterprise Storage 6
05.07.2019

Szybkie i bezpieczne...

Konica Minolta bizhub i-Series
05.07.2019

Edge computing

Atos BullSequana Edge
04.07.2019

Terabitowa ochrona

Check Point 16000 i 26000
04.07.2019

Obsługa wideokonferencji

Poly G7500
04.07.2019

Laptop biznesowy

Fujitsu LIFEBOOK U939X

Kubernetes - uniwersalna orkiestracja

Data publikacji: 21-02-2019 Autor: Grzegorz Kuczyński

W poprzedniej części naszego cyklu opisaliśmy, jak wdrożyć wysoką skalowalność i aktualizacje typu rollout w aplikacje oferujące ciągłą dostępność. W trzeciej części cyklu skupimy się na sposobie przygotowania optymalnych kontenerów dla naszych aplikacji oraz wdrażania bardziej złożonych aplikacji typu stateful.

 

Przygotowywanie kontenerów z aplikacjami to temat na tyle ogólny, że może przydać się również przy innych projektach, gdzie będziemy wykorzystywali Dockera. Niemniej wszystkie omawiane w niniejszym artykule przykłady będą dotyczyły konteneryzacji z przeznaczeniem dla klastra Kubernetes. Pociąga to za sobą pewne wymagania. Po pierwsze wydajność, po drugie bezpieczeństwo i po trzecie niezależność. Dzięki tym trzem elementom będziemy w stanie budować lepsze rozwiązania i w łatwy sposób nimi zarządzać. Zanim przejdziemy do sedna sprawy, warto przypomnieć fakt, że kontenery w systemie Linux nie są wirtualizacją, ale formą separacji procesu w wydzielonym środowisku systemu operacyjnego. Oznacza to, że taka aplikacja nie potrzebuje większości narzędzi i bibliotek znajdujących się w systemie, ponieważ ich nie używa.

> OGÓLNE ZASADY

Jedną z kluczowych cech dobrego kontenera jest jego wielkość. Jak wiemy, Kubernetes, tworząc pod, pobiera z repozytorium publicznego lub prywatnego określone obrazy na określone nody. Jednak gdy któryś z podów ulegnie awarii i wyłączeniu, to zostanie odbudowany, ale niekoniecznie na tym samym nodzie. To z kolei wymaga ponownego pobrania obrazu kontenera. Taka sama sytuacja ma miejsce, gdy awarii ulega sam nod. Podłączenie nowego czystego noda będzie wymagało pobrania kilku obrazów przed uruchomieniem na nim podów. Tak więc wielkość obrazu wpływa na szybkość operacji wykonywanych w klastrze.

Kolejną cechą wynikającą z poprzedniej jest bezpieczeństwo. Często do działania samej aplikacji wystarczy jej wersja binarna i kilka bibliotek oraz minimalne środowisko uruchomieniowe. Jeżeli wyeliminujemy wszystkie zbędne jego części, to tym samym usuniemy część potencjalnych zagrożeń. Niestety takie kontenery bez standardowych narzędzi bywają dość nieskuteczne w rozwiązywaniu problemów.

Ostatnią cechą, jaką wymieniliśmy, jest niezależność. Jest to bardzo szerokie pojęcie i kryje się za nim cała metodyka budowania funkcjonalnych kontenerów. W kontenerze może działać kilka procesów, np. Apache i MySQL, ale wtedy nie będziemy mogli ani skalować ich oddzielnie, ani aktualizować. Dlatego jeden kontener powinien odpowiadać za możliwie najmniejszą funkcjonalność. Dla przykładu środowisko LAMP może składać się z kontenera z procesem Apache, oddzielnego kontenera z procesem php-fpm i oddzielnego z MySQL. Ponadto powinniśmy oddzielać konfigurację i dane od samych aplikacji, tak aby były one tylko programami, do których możemy za każdym razem dołączyć inną konfigurację i inne dane. Przydział prostych zadań do pojedynczego kontenera pomaga również w rozwiązywaniu problemów i wprowadzaniu zmian w ogólnym środowisku.

> MINIMALNY OBRAZ BAZOWY

Kontenery Docker możemy tworzyć z gotowych już obrazów albo z tzw. abstrakcyjnego obrazu scratch, który reprezentuje pustą warstwę. Najlepiej, aby nasz obraz składał się z jak najmniejszej liczby narzędzi, ale jeżeli zamierzamy budować go na bazie jednej z popularnych dystrybucji, np. Debiana, to warto używać tego samego obrazu do wszystkich naszych aplikacji. Jeżeli zbudujemy trzy kontenery Apache, php-fpm i MySQL na bazie tego samego obrazu, to każdy pod będzie potrzebował tego samego obrazu bazowego. Natomiast jeżeli jeden z nich zbudujemy na bazie np. Ubuntu, to taki nod w naszym klastrze będzie musiał pobrać już dwa obrazy bazowe, które zazwyczaj są największą częścią kontenera. W celu zmniejszenia wielkości obrazu bazowego powstała dystrybucja Alpine Linux, której głównym celem jest minimalizacja pojemności budowanych na jej bazie kontenerów. Dla przykładu warto zapoznać się z wielkością obrazów bazowych wspomnianych dystrybucji – wynoszą one: Debian 100 MB, Ubuntu 86 MB, Alpine Linux 4 MB.

> DOCKER BUILD CACHE

Niezależnie od tego, czy będziemy tworzyć własne kontenery bazowe, czy używać gotowych kontenerów, musimy być świadomi pewnych szczegółów, jak działa Docker. Jedną z pułapek, w jaką możemy wpaść, jest mechanizm build cache. Otóż tworząc pliki Dockerfile, należy pamiętać, że tylko komendy RUN, COPY, ADD tworzą nową warstwę. Dlatego też oficjalne kontenery starają się wykonać większość operacji w ramach jednej komendy RUN. Dzięki temu minimalizowana jest liczba tworzonych warstw i nakłady z tym związane dla Dockera. Jednak Docker analizuje plik Dockerfile i sprawdza każdą z tych komend pod kątem historii. Jeżeli wcześniej wykonano już komendę:

to kolejne jej wystąpienie spowoduje użycie stworzonej już warstwy i w efekcie otrzymamy starszą wersję oprogramowania. Dlatego należy używać poniższego sposobu aktualizacji przed instalacją pakietów:

> BUDOWANIE OBRAZÓW MULTI-STAGE

Prawie wszystkie popularne aplikacje udostępniają już zoptymalizowane obrazy z użyciem np. Alpine Linux, więc jeżeli nie mamy jakichś szczególnych powodów, to ogólnie dostępne obrazy powinny w większości przypadków nam wystarczyć. Jednak w sytuacji gdy zamierzamy konteneryzować własną aplikację binarną, warto zapoznać się z mechanizmem Multi-stage, który pozwala na ponowne zdefiniowanie obrazu bazowego. Załóżmy, że mamy własną aplikację napisaną w języku C. Najlepiej ją skompilować na docelowym systemie, ale wszystkie narzędzia do tego służące nie są już nam potrzebne. Wystarczy sam plik binarny i niezbędne biblioteki. Poniżej pokazano pliki test.c i Dockerfile, w których budujemy naszą aplikację na bazie obrazu Alpine Linux. Po kompilacji ponownie pobieramy czysty obraz Alpine i z wcześniejszego kontenera kopiujemy tylko plik wynikowy. Ponieważ nasz program nie korzysta z żadnych bibliotek dodatkowych, a tylko ze standardowej biblioteki języka C, która znajduje się w nawet najmniejszym userlandzie, to nie musimy nic doinstalowywać do czystego obrazu Alpine.

# cat test.c
#include <stdio.h>
int main ()
{
printf("test");
return 0;
}
# cat Dockerfile
FROM alpine:latest AS builder
RUN apk update && apk add --no-cache gcc libc-dev
WORKDIR /root/
COPY test.c .
RUN gcc test.c -o /usr/local/bin/test
FROM alpine:latest
COPY --from=builder /usr/local/bin/
test /usr/local/bin/test
ENTRYPOINT ["/usr/local/bin/test"]

 

[...]

 

Autor zawodowo zajmuje się informatyką. Jest członkiem społeczności open source, prowadzi blog nt. systemu GNU/Linux. 

Artykuł pochodzi z miesięcznika: IT Professional

Pełna treść artykułu jest dostępna w papierowym wydaniu pisma.

.

Transmisje online zapewnia: StreamOnline

All rights reserved © 2019 Presscom / Miesięcznik "IT Professional"