Jak niezgodność MTU w Docker i OpenStack niszczy CI/CD: diagnostyka i naprawa
Awaria builda w piątek wieczorem często okazuje się nie przypadkowym błędem, a skutkiem niezgodności MTU między kontenerami Docker a siecią overlay OpenStack. Problem objawia się tylko podczas przesyłania dużych ilości danych, na przykład przy klonowaniu repozytorium, podczas gdy małe zapytania przechodzą bez błędów. To tworzy iluzję funkcjonalności sieci, dopóki nie rozpocznie się prawdziwa praca.
Dlaczego małe zapytania działają, a duże nie
Kluczową cechą tego problemu jest jego selektywność. Komendy takie jak curl -I lub ping, które generują małe pakiety, wykonują się pomyślnie. Problem występuje przy operacjach wymagających przesyłania danych dużymi segmentami: git clone, docker pull, ładowanie artefaktów. Przyczyna leży w Maximum Transmission Unit – maksymalnym rozmiarze pakietu IP, który może być przesłany bez fragmentacji.
W standardowej sieci Ethernet MTU wynosi 1500 bajtów. Jednak w środowiskach chmurowych, takich jak OpenStack, do tworzenia izolowanych sieci używane są technologie overlay VXLAN lub GRE. Dodają one do każdego pakietu nagłówek serwisowy o rozmiarze około 50 bajtów. W efekcie, choć fizyczna sieć obsługuje MTU 1500, dla pakietów maszyny wirtualnej pozostaje tylko 1450 bajtów.
Docker domyślnie tworzy sieć bridge z MTU 1500, nie uwzględniając specyfiki infrastruktury. Kontener formuje pakiety w oparciu o tę wartość. Gdy taki pakiet dociera do interfejsu sieciowego hosta z MTU 1450, nie może zostać przesłany z powodu ustawionej flagi DF (Don't Fragment). Idealnie, zadziałałby mechanizm Path MTU Discovery, ale w praktyce komunikaty ICMP "Fragmentation Needed" są blokowane przez zapory, grupy bezpieczeństwa lub błędnie obsługiwane przez routery.
Diagnostyka problemu w 30 sekund
Określić niezgodność MTU można za pomocą trzech komend:
- Sprawdź MTU interfejsu sieciowego hosta:
```
ip link show ens3 | grep mtu
```
Oczekiwany wynik w OpenStack: mtu 1450.
- Sprawdź MTU wewnątrz kontenera:
```
docker run --rm alpine ip link show eth0 | grep mtu
```
Docker domyślnie pokaże mtu 1500. Jeśli ta wartość jest większa niż na hoście, problem został wykryty.
- Przeprowadź test kontrolny z ping, zabraniającym fragmentacji:
```
docker run --rm alpine ping -s 1422 -M do -c 3 gitlab.example.com
docker run --rm alpine ping -s 1423 -M do -c 3 gitlab.example.com
```
Pierwsza komenda (1422 = 1450 − 28) powinna zakończyć się sukcesem, druga – zwrócić błąd Message too long.
Krok po kroku rozwiązanie problemu
Konfiguracja MTU w Docker
Główna naprawa polega na skonfigurowaniu Docker do używania poprawnego MTU. W tym celu edytuj plik /etc/docker/daemon.json:
{
"mtu": 1450
}
Po zmianie konfiguracji zrestartuj demona Docker:
sudo systemctl restart docker
Praca z istniejącymi sieciami
Ważne jest zrozumienie, że zmiana daemon.json wpływa tylko na nowo tworzone sieci. Istniejące sieci, szczególnie tworzone przez Docker Compose, zachowają stare MTU. Są dwa rozwiązania:
- Ponownie utwórz wszystkie sieci i kontenery:
```
docker compose down && docker compose up -d
```
- Jawnie określ MTU w konfiguracji Docker Compose:
```yaml
networks:
app-net:
driver: bridge
driver_opts:
com.docker.network.driver.mtu: 1450
```
Kroki końcowe
Po skonfigurowaniu MTU zrestartuj GitLab Runner i wykonaj test kontrolny:
sudo gitlab-runner restart
docker run --rm alpine ping -s 1422 -M do -c 3 gitlab.example.com
Jeśli test przechodzi bez błędów, problem rozwiązany.
Częste błędy i najlepsze praktyki
- Nie ustawiaj MTU "na zapas". Zmniejszenie MTU do 1300 "na wszelki wypadek" obniży przepustowość o 10-15% z powodu zwiększenia liczby pakietów. Używaj rzeczywistej wartości uzyskanej podczas diagnostyki.
- Automatyzuj konfigurację. Parametr MTU powinien być częścią konfiguracji infrastruktury (Terraform, Ansible, cloud-init), a nie ręcznej edycji.
- Pamiętaj o niestandardowych sieciach.
daemon.jsonnie aktualizuje MTU już utworzonych sieci. Używajdocker network inspectdo weryfikacji. - Nie polegaj na Path MTU Discovery. W środowiskach chmurowych ten mechanizm często nie działa z powodu blokowania ICMP.
Co jest ważne
- Problem niezgodności MTU objawia się tylko przy przesyłaniu dużych ilości danych, co utrudnia diagnostykę.
- Sieci overlay w OpenStack zmniejszają dostępny MTU o około 50 bajtów z powodu nagłówków serwisowych.
- Docker domyślnie używa MTU 1500, co prowadzi do konfliktu w środowiskach chmurowych.
- Główne rozwiązanie to jawna konfiguracja MTU w Docker, odpowiadająca MTU interfejsu sieciowego hosta.
- Konfiguracja powinna być zautomatyzowana i włączona w proces wdrażania infrastruktury.
— Editorial Team
Brak komentarzy.