Wskazówki konfiguracyjne replikacji MongoDB przy użyciu Podmana (Compose)

Autor
Damian
Terlecki
6 minut
Databases

W internecie łatwo znajdziesz działające konfiguracje uruchomieniowe MongoDB w trybie replikacji przy użyciu Dockera/Docker Compose. Niestety z kilku powodów żadna z nich nie chciała mi zadziałać przy wykorzystaniu Podman Compose na systemie z Linuxem. Aby zrozumieć problem, powiedzmy, że replikacja jest zwykle inicjowana przez powłokę (mongosh) po połączeniu się z instancją mongod (działającą z parametrami --replSet, --bind_ip i opcjonalnie --port):

rs.initiate(
   {
      _id: "myReplSet",
      version: 1,
      members: [
         { _id: 0, host : "mongodb0.example.net:27017" },
         { _id: 1, host : "mongodb1.example.net:27017" },
         { _id: 2, host : "mongodb2.example.net:27017" }
      ]
   }
)

Wybór nazwy hosta poszczególnych członków zbioru replikacji

Zacznijmy od tego, że adresy zdefiniowane w konfiguracji muszą być dostępne zarówno z poziomu każdego członka zbioru replikacji, jak i z poziomu maszyny klienta (hosta). Częstym rozwiązaniem jest użycie host.docker.internal zamiast w miejscu mongodbN.example.net. W domyślnej konfiguracji sieci typu bridge jest ona mapowana na host-gateway np. przy użyciu opcji extra_hosts na poziomie serwisu w konfiguracji Docker Compose. Jest to adres hosta widoczny z poziomu kontenera. Podman ma tu swój odpowiednik host.containers.internal, który działa bez definiowania dodatkowego hosta.

Uwaga: błąd 'invalid IP address in add-host: "host-gateway"' może oznaczać, że korzystasz ze starej wersji silnika dockera/podmana w systemie Linux. W najbardziej podstawowych przypadkach możesz podstawić w tym miejscu wartość 172.17.0.1, ale może się ona różnić w przypadku pracy z wieloma sieciami. Sprawdź ten wątek SO, aby dobrać lepsze, ale bardziej złożone rozwiązania.

Alternatywnie możesz użyć nazwy usługi lub na poziomie usługi przydzielić nazwę kontenera container_name i hosta hostname, aby skonfigurować replikację z niestandardowymi nazwami hostów.

Wybór portów

Drugie zastrzeżenie dotyczy konfiguracji portu. Ta sama nazwa hosta lub mapowanie na to samo IP oznacza, że porty dla każdego członka muszą się różnić (np. 27017, 27018, 27019) i odpowiadać definicji replikacji, konfiguracji mongod, a także powiązaniom portów między hostem a kontenerami.

Niedopasowania mogą prowadzić do:

  • usunięcie węzła z klienckiego widoku klastra ("canonical address of the node does not match server address, removing node from client view of cluster");
  • problemy z dostępem do wszystkich węzłów z poziomu hosta;
  • błędy inicjacji replikacji podczas próby odnalezienia się członka w konfiguracji replset ("error trying to find self in the replset config").

UnknownHostException

Trzecim problemem jest to, że nazwa hosta host.docker.internal jest standardowo nieosiągalna na hostach z systemem Linux i wymaga dodania wpisu do /etc/hosts. Najczęściej mapowany jest on na domyślny adres pętli zwrotnej 127.0.0.1. Dodatkowo w przypadku Podmana adresy z /etc/hosts hosta przenoszone są do /etc/hosts kontenerów, powodując błędy inicjacji replikacji.

Zrzut ekranu przedstawiający zduplikowany wpis 'host.docker.internal' w '/etc/hosts' kontenera pochodzący zarówno z hosta jak i z kontenera. Zrzut ekranu przedstawiający błąd replikacji przy zduplikowanym wpisie 'host.docker.internal' w pliku '/etc/hosts' powodowany połączeniem z niewłaściwym adresem IP.

Wykorzystanie niedawno dodanej opcji --no-hosts (Podman 4.0), koliduje niestety z host.containers.internal/host.docker.internal. W przypadku starszych wersji prymitywnym rozwiązaniem jest modyfikacja pliku /etc/hosts kontenera tuż przed uruchomieniem instancji mongod. Znacznie lepszym rozwiązaniem jest wyłączenie tego zachowania globalnie, poprzez nieco nowszą (Podman 4.1) opcję konfiguracyjną, w pliku $HOME/.config/containers/containers.conf:

[containers]
base_hosts_file="none"

Podsumowanie

Jeśli napotkasz problemy z konfiguracją replikacji MongoDB na potrzeby dewelopmentu bądź testowania, w systemie Linux lub przy użyciu Podmana, zwróć uwagę na następujące elementy:

  • Zestawy replik powinny być skonfigurowane z nazwami hostów i kombinacjami portów osiągalnymi z każdego węzła, jak również z poziomu klienta (np. hosta).
  • Użyj odrębnych portów dla każdego węzła, tak aby widok RS odpowiadał również powiązaniom portów pomiędzy kontenerami a hostem.
  • Użyj nazwy hosta host.docker.internal (może wymagać extra_hosts)/host.containers.internal (Podman) przy konfiguracji adresów członków.
  • Alternatywnie, zdefiniuj container_name i hostname na poziomie usługi, jeśli chcesz skonfigurować replikację z niestandardowymi nazwami hostów.
  • W przypadku błędu nieosiągalnej nazwy adresu członka z poziomu hosta, dodaj mapowanie na adres IP do pliku /etc/hosts.
  • Wyłącz kopiowanie /etc/hosts z komputera hosta poprzez plik containers.conf, jeśli korzystasz z Podmana.
  • Alternatywnie Linux pozwala uruchomienie serwisu w tej samej sieci za pomocą właściwości network_mode: host a tym samym uproszczoną konfigurację replikacji przy użyciu localhosta.