>_ DevTrendspl

Język

Strona główna

Języki

Sekcje

Frontend Backend Mobilne DevOps AI / ML GameDev Blockchain Systemy wbudowane Bezpieczeństwo
C

Dlaczego przepisać runtime kontenerów w C

Spróbuj uruchomić Docker lub Podman z limitem pamięci wynoszącym 512 kilobajtów. Standardowy runtime runc po prostu zawiedzie z błędem przy takim limicie. Nie będzie miał wystarczającej ilości pamięci nawet na skonfigurowanie podstawowych struktur procesu i odczytanie deskryptorów plików.

Przyczyna leży w architekturze. Zdecydowana większość nowoczesnego stosu kontenerów jest napisana w Go. Dla narzędzi najwyższego poziomu jest to świetne rozwiązanie, ale na samym najniższym poziomie Go wnosi ze sobą własny runtime, garbage collector i narzut pamięciowy. Aby skonfigurować przestrzenie nazw jądra Linux przed uruchomieniem procesu głównego, runc musi uruchomić się ponownie i uciec się do obejść w C.

Projekt crun organizacji Containers radzi sobie z tym problemem bezpośrednio. Jest to lekka implementacja specyfikacji OCI (Open Container Initiative), napisana całkowicie w czystym C.

Co daje przejście na czyste C

Główna koncepcja jest prosta: usuń wszystko niepotrzebne z ścieżki krytycznej tworzenia kontenera. Gdy runtime nie jest obciążony dodatkowymi warstwami, zużycie zasobów i szybkość reakcji dramatycznie się poprawiają.

Zużycie pamięci i uruchamianie na granicach limitów

Testy porównawcze developerów pokazują wymowną różnicę:

# Запуск через runc падает
$ podman --runtime /usr/bin/runc run --rm --memory 4M fedora echo it works
Error: container_linux.go:346: starting container process caused "process_linux.go:327: getting pipe fds for pid 13859 caused \"readlink /proc/13859/fd/0: no such file or directory\"": OCI runtime command not found error

# Запуск через crun отрабатывает без запинки
$ podman --runtime /usr/bin/crun run --rm --memory 512k fedora echo it works
it works

Kontener z crun niezawodnie startuje nawet przy restrykcyjnym limicie pamięci 512 KB, podczas gdy runc zawodzi nawet przy 4 MB. Dla ciężkich mikroserwisów chmurowych różnica jednego megabajta może wydawać się błaha, ale na urządzeniach IoT, routerach i serwerach brzegowych ta oszczędność zwalnia cenną pamięć na rzeczywiste obciążenia robocze.

Szybkość sekwencyjnego uruchamiania

Gdy musisz często uruchamiać krótkotrwałe zadania (na przykład na platformach serverless lub runnerach CI/CD), czas inicjalizacji kontenera staje się wąskim gardłem. W teście uruchamiającym 100 kontenerów sekwencyjnie za pomocą polecenia /bin/true, różnica czasowa jest niemal dwukrotna:

| Runtime | Czas wykonania (100 kontenerów) | Różnica | | :--- | :--- | :--- | | crun | 0:01.69 | -49.4% | | runc | 0:03.34 | baseline |

Implementacja w C startuje dwukrotnie szybciej dzięki brakowi narzutu inicjalizacji runtime Go i mniejszej liczbie niepotrzebnych wywołań systemowych.

Używanie jako biblioteki

Większość runtime'ów istnieje tylko jako samodzielne pliki wykonywalne. Jeśli musisz uruchomić kontener OCI ze swojego programu, zazwyczaj musisz użyć fork() i wywołać zewnętrzne narzędzie.

W crun możesz zbudować bibliotekę współdzieloną libcrun. Otwiera to bezpośrednie API w C do pracy z kontenerami:

  • osadzanie uruchamiania izolowanego środowiska we własnych demonach
  • brak narzutu związanego z tworzeniem osobnych procesów
  • wbudowana obsługa powiązań Pythona i Luy

Budowanie i instalacja

Narzędzie jest dostępne w większości dystrybucji poprzez standardowe menedżery pakietów, ale budowanie ze źródeł jest również proste.

Budowanie na Ubuntu wymaga podstawowych plików nagłówkowych:

$ sudo apt-get install -y make git gcc build-essential pkgconf libtool \
   libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libjson-c-dev \
   go-md2man autoconf python3 automake

Sama kompilacja jest standardowa:

$ ./autogen.sh
$ ./configure
$ make
$ sudo make install

Jeśli planujesz używać biblioteki w swoim kodzie, flaga konfiguracji zmieni się na ./configure --enable-shared.

Dla powtarzalnych środowisk i serwerów bez dodatkowych zależności, projekt obsługuje statyczne budowanie przez Nix Flakes:

$ nix --extra-experimental-features "nix-command flakes" build "path:.#crun-static-amd64"
$ ./result/bin/crun --version

Rezultatem jest kompaktowy statyczny plik binarny dla x86_64 z glibc, gotowy do uruchomienia na dowolnej maszynie docelowej.

Dla kogo to jest

Przejście na crun ma sens w kilku scenariuszach:

  1. Edge computing i IoT. Gdy urządzenie ma przylutowane tylko 256 MB lub 512 MB RAM, oddawanie megabajtów runtime'owi jest nie do przyjęcia.
  2. Serverless i Functions-as-a-Service. W środowiskach z częstym tworzeniem i niszczeniem izolowanych kontenerów, 50% przyspieszenie uruchamiania bezpośrednio redukuje opóźnienie zimnego startu.
  3. Gęste pakowanie kontenerów. Jeśli setki małych workerów działa na jednym hoście, łączne oszczędności RAM sumują się do gigabajtów.

Zamiana runtime'a w Podman jest tak prosta jak jedna flaga --runtime /usr/bin/crun lub zmiana parametru w /etc/containers/containers.conf. Żadne zmiany w manifestach czy obrazach nie są potrzebne.

Powiązane projekty