Síťařina v DC/OS v Azure Container Service

V síťařině jsem působil mnoho let a vždycky to bylo docela složité. Virtualizace a cloud situaci díky nástupu overlay sítím a mikrosegmentaci zrovna nezjednodušují a dnes se pak musí řešit otázka síťařiny v kontejnerech běžících nad virtualizací. Azure Container Service odladila a připravila robustní řešení pro open source orchestrátor dle vaší volby - Docker Swarm, Kubernetes, DC/OS.

Dnes se společně podíváme na síťování v DC/OS v Azure.

Koncept síťařiny v DC/OS (Marathon)

IP per kontejner

Původně byla síťařina v DC/OS postavena na sdílení adresy s hostitelem podobně, jako to dělal Docker. To s sebou při větším nasazení nese náročnou správu portů, nutnost služeb běžících na nestandardních portech apod. DC/OS to řešil konceptem virtuální IP, nicméně od verze 1.8 podporuje to, co považuji za správný postup - IP per kontejner s využitím otevřeného rámce Container Network Interface.

V Azure je automaticky připravena a nasazena overlay (VXLAN propojení mezi agenty) se zabudovaným řešením Navstar.

Otevřete svůj DC/OS cluster v Azure a v záložce network je vytvořena jedna obrovská výchozí síť (/8 pro cluster a /24 pro každého agenta).

Můžeme spustit nějaký kontejner v této IP-per-kontejner síti - jděte do Services.

Spustíme kontejner, který bude trvale vypisovat svojí IP adresu.

A použijeme overlay síť.

Podívejme se do logů - uvidíme jeho IP adresu.

Totéž najdeme i v DC/OS GUI v části o sítích.

Spustíme jiný kontejner ve virtuální overlay síti a vyzkoušíme přímou IP konektivitu mezi nimi.

Použijte image busybox a virtuální síť. Podívejme se do logu - kontejnery nám skutečně napřímo komunikují.

Private vs. Public agent

DC/OS při připojení uživatelů z reálného světa používá koncept privátních a veřejných agentů. Máte tedy kromě master dvě kategorie hostitelů. V privátních hostitelech poběží prakticky všechno a nic nebude mít veřejnou kontektivitu. Z hlediska Azure mají tyto vyhrazen svůj subnet pro hostitele (a jak už víme DC/OS použije overlay pro získání IP per kontejner).

Public agent má v Azure jiný subnet ve VNetu a kontejnery spuštěné v těchto VM mohou mít "externí" kontektivitu (tou zatím myslíme subnet tohoto VNetu). Ta vypadá tak, že kontejner může "vystrčit" svou službu na nějaký port hostitele. V typickém případě běží všechno v privátních VM a v public VM budou aplikační load balancery (viz dále).

Podíváme-li se do DC/OS GUI, najdeme v mém případě šest agentů - všimněte si jejich IP adres.

Podívejme se v Azure portálu na VNet, který nám Azure Container Service založila.

A také na přidělené adresy.

Azure balancing public agentů

Princip "vystrčení" služby v public VM spočívá v tom, že služba bude dostupná na každém z public agentů. Abychom se k aplikacím dostali, potřebujeme reálnou veřejnou IP a také load balancer, který bude požadavky na tuto veřejnou IP posílat na nějakou z public agent VM. To je pro vás v Azure připraveno. Podívejme se na veřejnou IP balanceru.

A na pool adres, na který Azure požadavky směruje.

Marathon Load Balancer

Zatím jsme si prošli všechno potřebné k tomu, abychom mohli mluvit mezi kontejnery a aby se k nim z venkovního světa někdo dostal. Můžeme tak nasadit třeba vlastní HAProxy balancer/proxy v public agentovi a v ní balancovat na aplikační kontejnery v privátním agentovi. Naštěstí si to nemusíme vytářet sami - marathon-lb dělá právě tohle.

Služba není v základu nainstalována, ale stačí jednou kliknout v DC/OS Universe - nic složitého.

Aplikaci vytvoříme s využitím JSON předpisu (potřebujeme totiž použít některé parametry, které v GUI nejsou). Deployment můžeme provést z GUI, jen použijeme JSON režim.

Vymažeme co tam je a použijeme tento JSON:

{
  "id": "web",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "yeasy/simple-web",
      "network": "USER",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 3,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external",
    "HAPROXY_0_VHOST":"tomuvdcosagents.westeurope.cloudapp.azure.com",
    "HAPROXY_0_MODE":"http"
  },
  "ipAddress": {
    "networkName": "dcos"
  }
}

Okomentujme klíčové části. V sekci kontejner vybíráme image a používáme síť typu USER (tou je overlay). ipAddress nám určuje naší overlay síť. Podívejme se na labels. VHOST je DNS jméno mé virtuální IP load balanceru pro public agenty v Azure.

Připojíme se na cluster a uvidíme aplikaci - pokud dáte refresh uvidíte, že požadavky jsou skutečně balancovány na instance webové aplikace.

Pozor ještě na jednu věc - Azure Container Service nám připravila balancing public agentů na těchto portech:

Pokud chcete nějaké další, musíte si pravidla přidat.

Marathon-lb v kombinaci s Azure DNS

Potíž v předchozím odstavci byla, že jsme jednou aplikací zabrali na portu 80 celý cluster. Můžeme samozřejmě nasadit další aplikace na jiných portech, ale to není praktické (uživatelům nechceme v URL říkat i nestandardní čísla portů). Marathon-lb je ale L7 balancer, takže můžeme identifikovat příchozí provoz podle URL a na základě toho si vybrat příslušnou aplikaci. Doménovým jménem můžeme rozlišit aplikace a přitom vše směřuje jen na jednu IP adresu.

Část své domény jsem delegoval do Azure DNS, tedy do DNS serverů jako služba, které mohu ovládat přímo z portálu či jinými Azure prostředky. Vytvořím záznam pro novou subdoménu, která bude směřovat na veřejnou IP mého public agent balanceru.

Vyzkoušel jsem teď v prohlížeči zadat appka.azure.tomaskubica.cz

Dostávám zprávu o chybějící službě přestože se dostáváme na naprosto stejnou IP jako v případětomuvdcosagents.westeurope.cloudapp.azure.com. Marathon-lb tedy dokáže rozlišit jakou doménu klient použil. Abychom si to potvrdili, pojďme rozjet v DC/OS jinou službu, třeba prázdný NGINX server.

Použijme tento JSON:

{
  "id": "web2",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx",
      "network": "USER",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 3,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external",
    "HAPROXY_0_VHOST":"appka.azure.tomaskubica.cz",
    "HAPROXY_0_MODE":"http"
  },
  "ipAddress": {
    "networkName": "dcos"
  }
}

Zkuste znovu web.

Funguje !

Rekapitulace

Shrňme si tedy celou komunikační dráhu. Klient zadá URL a jeho prohlížeč vytvoří DNS dotaz na aplikace.azure.tomaskubica.cz. DNS infrastruktura mu na to vrátí veřejnou IP load balanceru public agentů. Provoz jde do jednoho (náhodně vybraného) public agenta. Tam se dostává do marathon-lb, který si přečte požadovanou URL. Na základě jména vybere příslušnou Marathon službu běžící na privátních agentech a dál vybere jeden z kontejnerů, na kterém služba běží. Přes overlay síť do něj pošle požadavek.

 

Síťařina v kontejnerech zní možná trochu složitě, ale díky Azure Container Service se nemusíte nutně trápit s implementačními detaily. Vyzkoušejte, stojí to za to.

 

 



Kubernetes praticky: doporučená bezpečnostní nastavení a scan s kubesec.io Kontejnery
Privátní napojení PaaS služeb do VNETu s Azure Private Link Networking
Kubernetes praticky: používání externí konfigurace v Azure App Configuration Service Kontejnery
Automatické získávání IP range PaaS služeb v Azure přes API Networking
Kubernetes praticky: vystavování aplikací s Ingress a Azure App Gateway (WAF) Kontejnery Networking