OpenVPN i Docker kan inte öppna /dev/net/tun: vad som saknas
En TUN-nod och nätverkskapaciteten är två separata tillstånd. Öppna båda och läs sedan nästa fel på dess egna villkor i stället för att upprepa samma åtgärd.
Containerbilder kan innehålla alla OpenVPN-binärfiler och konfigurationsfiler de behöver och ändå misslyckas vid det första nätverksanropet. Felet nämner /dev/net/tun eftersom programmet bad kärnan om ett TUN-gränssnitt och containern hade varken enhetsnoden eller förmågan att skapa en. Det är två separata tillstånd, och att åtgärda det ena lämnar det andra precis där det var.
Att skilja dem åt kräver ett kommando vardera. Felmeddelandet efteråt berättar vilken gräns du faktiskt stod vid.
Enhetsnoden och förmågan är två dörrar
Enhetsnoden är ett filsystemobjekt, så en container måste se den i sitt eget mount-namnrymd. Förmågan är ett tillstånd, så processen behöver CAP_NET_ADMIN i namnrymden där gränssnittet skapas. Att skicka igenom enheten utan förmågan ger en nod som öppnas och en ioctl som misslyckas. Att ge förmågan utan enheten lämnar programmet oförmöget att öppna något alls, och därför brukar de två dyka upp tillsammans i exempel.
Dockers devices-inställning mappar värdenhetens enhet in i containern, medan cap_add justerar förmågeuppsättningen. En bind mount av samma sökväg sätter filen i synfältet utan att tillämpa semantiken för enhetsåtkomst.
Återskapa det utanför Compose-filen
Innan du redigerar tjänsten, kontrollera att värden har enheten och att en bar container kan skapa ett gränssnitt. Kommandot nedan är medvetet minimalt, och dess enda syfte är att skilja ett värdproblem från ett compose-problem. Om det misslyckas hjälper ingen compose-ändring.
ls -l /dev/net/tun
docker run --rm --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun alpine sh -c 'apk add -q iproute2 && ip tuntap add dev tun9 mode tun && ip link show tun9'
En saknad nod på värden betyder att tun-modulen inte är tillgänglig, vilket är en åtgärd på värdsidan och inte i containern. En nod som finns men inte kan öppnas inuti containern pekar på enhetsåtkomst, och meddelandet kommer att säga permission denied i stället för no such file. Ordningen på dessa två fel är hela diagnosen. Skriv ner vilket du såg innan du ändrar en flagga.
Felen efter TUN är andra problem
Så snart gränssnittet dyker upp har nästa fel en annan ägare. Autentiseringsfel betyder att tunneln nådde servern och att inloggningsuppgifterna avvisades, så ändringar av förmågor hjälper inte. En tunnel som upprättas medan programmen fortfarande misslyckas pekar på rutter, vidarebefordran, DNS-uppslag inuti containern eller containerns egen nätverkslayout. Vart och ett av dessa är en vanlig nätverksfråga som TUN-tillståndet inte kan svara på. Att upprepa det ursprungliga testet efter varje ändring hindrar felen från att smälta samman till ett enda intryck.
Att kopiera varje inställning från ett fungerande exempel är hur en minimal åtgärd blir en oläslig tjänstedefinition. Ta bara med dem denna utrullning behöver och notera varför var och en finns där.
Verifiera gränssnittet inuti containern
Kontrollera gränssnittet och förmågeuppsättningen inifrån den körande containern i stället för från värden. Kommandona nedan visar enhetsnoden, förmågelistan och om ett gränssnitt alls kan skapas. Kör dem i samma container som kör klienten, och installera verktygen om bilden är minimal.
ls -l /dev/net/tun
capsh --print | grep -i net_admin
ip link add dev tun9 type tun && ip link show tun9
En förmåga som finns i bounding set men saknas i effective set beter sig annorlunda än en som aldrig beviljats, och capsh visar båda. Om noden finns och förmågan är där medan skapandet fortfarande misslyckas, tvingar körtidsmiljön något annat, som en seccomp-profil eller en AppArmor-policy som begränsar åtgärden. Det är en tredje gräns, dokumenterad av körtidsmiljön och inte av programmet.
Notera containerns flaggor, bilden och det exakta felet från varje försök. Nästa person som läser den anteckningen kan säga vilken dörr som var stängd utan att upprepa hela undersökningen.