Docker multi-stage build i konflikty bibliotek

0

Potrzebuję obraz Dockera, który będzie zawierał:

  • janus-pp-rec
  • ffmpeg
  • Java 11 JDK

Tworzę obraz Dockera z multi-stage build, czyli:

FROM swmansion/janus-gateway:latest as janus
FROM jrottenberg/ffmpeg:latest as ffmpeg
FROM eclipse-temurin:11 as java

COPY --from=janus / /
COPY --from=ffmpeg / /

Czyli bierzemy 3 gotowe obrazy i do ostatniego kopiujemy pliki z 2 poprzednich. Skopiowanie tylko /usr/local lub /usr kończy się tym, że brakuje bibliotek. Natomiast jeśli zbuduję obraz tak jak powyżej, to występują konflikty, prawdopodobnie niezgodne wersje bibliotek:

$ docker container exec videoprocessing janus-pp-rec

janus-pp-rec: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0)
janus-pp-rec: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by /usr/lib/x86_64-linux-gnu/libavutil.so.56)
janus-pp-rec: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/lib/x86_64-linux-gnu/libavutil.so.56)
...
janus-pp-rec: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.25' not found (required by /usr/lib/x86_64-linux-gnu/libopenmpt.so.0)
...

$ docker container exec videoprocessing ffmpeg

ffmpeg: error while loading shared libraries: libavdevice.so.58: cannot open shared object file: No such file or directory

Jak uniknąć konfliktów bibliotek? Czy Linux zawiera jakieś mechanizmy, żeby jednocześnie mogło być wiele wersji bibliotek? Może macie inny pomysł?

4

Czy Linux zawiera jakieś mechanizmy, żeby jednocześnie mogło być wiele wersji bibliotek?

Ten właśnie problem rozwiązuje Nix!
(gdzie każda aplikacja może mieć swój własny glibc, swoje własne libcokolwiek i wszystko śmiga)

Nix potrafi również budować obrazy Dockerowe, więc polecam rzucić okiem choćby z ciekawości.

Co do samego problemu, zostając przy Dockerze - glibc jest w założeniu kompatybilny wstecznie, zatem sugerowałbym albo zmienić kolejność COPY (aby np. obraz ze starszym glibc był kopiowany pierwszy), albo kopiować tylko potrzebne ścieżki, a nie cały system plików (COPY --from=ffmpeg /usr/lib/cokolwiek-co-ffmpeg-potrzebuje).

2

Nie wolno tak robić COPY --from=janus / / bo bibiloteki są zależne od tego co jest w systemie. Co jak np. w drugim obrazie masz starszą wersją tej samej biblioteki? Robiąc takie COPY nadpiszesz starszą wersję nową.

Jeśli chcesz pozostać przy bieżącym podejściu to sprawdź co dokładne jest wymagane do skopiowania: najprawdopodobniej będą to wszystkie zbudowane binarki i liby oraz wymagane shared liby (możesz je sprawdzić za pomocą ldd binarka lub ldd libka). Alternatywą są statyczne bulidy: są to binarki/liby, które mają wszystkie (lub prawie wszystkie) zależności wbudowane w siebie, więc nie ma problemu, że w zależności od systemu coś przestaje działać. Taka strategia jest zalecana, jeśli chodzi o kontenery (google uu siebie buduje wszystko statycznie, nowoczesne języki takie jak go czy rust by default budują wszystko statycznie, bo tak jest prościej) bo jest prościej i paradoksalnie takie kontenery są zazwyczaj dużo mniejsze

0

@slsy: Właśnie poszedłbym w kierunku statycznych buildów. Dla ffmpeg są takie obrazy. Dla Janusa chyba nie. Mimo wszystko lepiej będzie zbudować wszystko ręcznie, czyli napisać całe wypracowanie w Dockerfile, które nam zbuduje wszystko, co trzeba.

Odnośnie Janusa https://github.com/meetecho/janus-gateway/issues/2166

Zrobię też POC z użyciem Nix i dam znać, co się lepiej sprawdza.

1 użytkowników online, w tym zalogowanych: 0, gości: 1