Kubernetes Best Practices

Ik was aan het chatten met een voormalige Googler SRE die (correct) erop wees dat Kubernetes zeer snel evolueert (te snel om de valuta te behouden), (veel) nieuwe concepten gebruikt en dat er (te) veel manieren zijn om hetzelfde probleem op te lossen.

Veel hiervan is waar en niet noodzakelijk een slechte zaak, noch noodzakelijk anders dan welke andere technologie dan ook. Waar ik het niet mee eens ben, is dat deze factoren zijn goedkeuring van Kubernetes hebben afgeraden. Ik zou je willen aanmoedigen erin te duiken. Kubernetes is het succes dat het is * ondanks * deze (redelijke) zorgen omdat het zo heel erg goed is.

In dit bericht ga ik je een aantal rudimentaire best practices geven waarvan ik hoop dat je deze technologie bij de containers kunt pakken en erin kunt duiken.

In willekeurige volgorde:

  1. Laat iemand anders zwoegen!

Gebruik een Kubernetes-service zoals Kubernetes Engine. Tenzij u intellectueel nieuwsgierig bent, een ontwikkelaar die werkt aan Kubernetes of u bent een platformprovider die klanten vraagt ​​om een ​​Kubernetes-service, bespaar het gedoe en gebruik een Kubernetes-service. Heb je je eigen huis en je auto gebouwd? Of slaap je graag op een plek waar de Wolf niet kan omver blazen en een auto besturen die je betrouwbaar van A naar B brengt?

Dus als je een van mijn andere berichten hebt gelezen, raad ik ook aan om regionale clusters te evalueren en dus kijk je naar iets in de trant van:

gcloud beta-containerclusters creëren $ {CLUSTER} ...
gcloud beta-containerclusters krijgen inloggegevens $ {CLUSTER} ...

En dan ben je klaar om te gaan met:

kubectl toepassen --bestandsnaam = marvels.yaml

2. Probeer 'Kubernetes' te denken

Dit * kan * meer een uitdaging zijn met Kubernetes Engine dan op andere platforms, maar op Google Cloud Platform bent u gedwongen om inzicht te houden in de status van uw bronnen in Kubernetes (bijv. Knooppunten, Ingresses) en tegelijkertijd , de onderliggende bronnen in Compute Engine (bijv. VM's, HTTP / S Load Balancers). Dit deeltje-golf dualiteitsprobleem is jammer. Met dank aan Dale H. voor het eerste articuleren van dit voor mij.

Probeer waar mogelijk te blijven denken in termen van de bronnen van Kubernetes en negeer de onderliggende GCE-bronnen. Nu ik meer dan een jaar mijn werk heb gericht op Kubernetes, is het gemakkelijker geworden om puur te denken in termen van 'een aantal' pods die worden getoond door Services (en Ingresses).

3. Naamruimten, Naamruimten, Naamruimten

Update: Dank aan Michael Hausenblas voor het opleiden van mij over een best practice van * niet * verwijzen naar naamruimten vanuit YAML-bestanden van Kubernetes. Hoewel u altijd naamruimten moet gebruiken, biedt het opgeven van deze wanneer u het bestand toepast meer flexibiliteit en de mogelijkheid om dezelfde YAML-bestanden te gebruiken tegen, b.v. verschillende landschappen. Zie Michael's artikel hier.

Mike Altarace en ik blogden manen geleden over Namespaces in Kubernetes en waar je ze zou moeten gebruiken. Sindsdien negeerde ik mijn eigen advies vrijwel omdat ik dacht dat mijn use-cases zo klein waren dat het gebruik van Namespaces te zwaar zou zijn. Ik had het fout. Gebruik altijd naamruimten.

Zoals containers zijn voor processen, zijn Namespaces voor Kubernetes-projecten. Afgezien van de beveiligingsgrens die Namespaces overbrengt, zijn ze een uitstekende manier om uw werk te partitioneren en bieden ze een uitstekende manier om het te resetten of te verwijderen:

kubectl delete namespace / $ WORKING_PROJECT

Het enige nadeel is dat u bij het gebruik van de niet-standaard naamruimte uw werknaamruimte --namespace = $ WORKING_PROJECT op kubectl-opdrachten moet opgeven, wat naar mijn mening een goede beveiligingsmethode kan zijn. U kunt echter altijd --alle-naamruimten of een andere naamruimte instellen als standaard (koppeling).

4. Te veel manieren om een ​​probleem op te lossen

Dit is een ontmoedigende zorg. Ik denk dat het waarschijnlijk niet waar is, maar bij gebrek aan goede begeleiding en best practices, lijkt het erop dat er teveel vergelijkbare manieren zijn om hetzelfde probleem op te lossen. Ik heb een gemeenschappelijk patroon dat ik gebruik en dat ik hier samenvat om discussie aan te moedigen:

  • YAML-bestanden zijn kennis in koude opslag (zie # 5)
  • Uw containers moeten één ding goed doen (zie "distroless")
  • Implementeer altijd implementaties (zie # 6)
  • Als je L7 aka HTTP / S Load-Balancing wilt, gebruik dan Ingress (zie # 7 - ha!)
  • Beheer inloggegevens veilig met Secrets (link)

5. Bias naar kubectl past --bestandsnaam toe op alternatieven

Het is gemakkelijk om een ​​snelle hit te krijgen met kubectl create namespace / $ {WORKING_DIR}, maar na verschillende van dergelijke commando's vraagt ​​u zich misschien af ​​hoe u de huidige status hebt bereikt en - nog belangrijker - hoe u deze status opnieuw kunt creëren. Ik moedig u aan om YAML-bestanden te maken om uw bronnen te beschrijven in plaats van het equivalente kub ectl create-commando.

Ik moedig u aan om bekend te raken met de * uitstekende * Kubernetes API-documentatie (link, link en 1.10) die uitputtend, nauwkeurig en gemakkelijk te navigeren is (misschien de perfecte documentatie !?). Maar zelfs met deze krachtige tool is het soms een beetje een uitdaging om een ​​kubectl-opdracht te nemen die voor u werkt en deze naar YAML te converteren. Het is niet:

kubectl get deployment / $ {MY_DEPLOYMENT} --output = yaml
kubectl service krijgen / $ {MY_SERVICE} --output = yaml
kubectl om het even wat / $ {MY_ANYTHING} --output = yaml

Leid de resultaten naar een bestand als u wilt, maar gebruik deze als basis voor een gelijkwaardig (!) YAML-bestand. U moet alle exemplaarverwijzingen verwijderen.

Als je eenmaal masterpiece.yaml hebt gemaakt, moedig ik je aan om altijd een aanvraag in te dienen om de initiële creatie te doen, een aanvraag te doen voor eventuele latere updates en, als je moet verwijderen. Dat is het!

kubectl toepassen --bestandsnaam = masterpiece.yaml
kubectl delete --bestandsnaam = masterpiece.yaml

Klein inzicht: u hoeft YAML-bestanden niet lokaal op te halen om te kunnen implementeren. U kunt kubectl ook toepassen --bestandsnaam met URL's en zolang de afhankelijke bestanden lokale referenties zijn, werkt de implementatie.

Klein inzicht: de enige plaats die ik hier zie is in Kubernetes-land, maar het is een legitieme praktijk, je kunt meerdere YAML's-bestanden combineren in één YAML-bestand met --- en ... bestandseparatoren. Dus in plaats van een naamruimte YAML, een implementatie-YAML en een service YAML, hebt u misschien een mega-YAML die alle drie de bestanden in één consolideert.

Dit is geldige YAML (kopieer en plak het in bijvoorbeeld YAML Lint). Het is * ongeldige * Kubernetes-specificatie | YAML omdat elke specificatie onvolledig is, maar, als ze allemaal werden voltooid, is dit prima YAML en een goede manier om middelen gekoppeld te houden.

Zie #B (Xsonnet) voor één kritiek.

6. Gebruik implementaties

Er zit een heleboel kracht in implementaties, volstaat mijn leidraad om te zeggen: gebruik de hele tijd, elke keer. Zelfs wanneer u uw eerste enkele podnginx implementeert. Implementaties zijn "First Class" -reizen voor de prijs van Coach, je kunt in rollende implementaties vallen, je maakt een fout, solliciteert opnieuw en Kubernetes zorgt voor het doden van de ondeugende pods en vervangt ze door goed opgevoede pods.

7. LoadBalancer en Ingress

Deze veroorzaken verwarring. In mijn gedachten (en ik kan het verkeerd hebben), wanneer ik Services maak met --type = LoadBalancer, wil ik | een Network LB krijgen. Als ik HTTP / S (niveau 7) load-balancing wil, moet ik een Ingress maken. Ingress is een verwarrende bron van Kubernetes. Het volstaat te zeggen, L7 == Ingress (en veel configuratievermogen als gevolg).

Kubernetes Engine manifesteert Ingress-bronnen als GCE HTTP / S Load-Balancers. Christopher Grant doet heel goed zijn best om Ingress te demystificeren in zijn functie (hier en hier).

8. NodePorts

Ik heb niet (ooit?) Direct een ClusterIP gemaakt. Ik heb Kubernetes dingen gedaan die ertoe hebben geleid dat diensten worden blootgesteld door ClusterIP's. Meestal (!) Heb ik NodePorts gemaakt of doe ik dingen (bijv. Ingress-bronnen maken) die NodePorts gebruiken.

NodePorts zijn geassocieerd met Kubernetes Nodes en het zijn poorten. De krachtige faciliteit die ze bieden, is dat * elke * node in het cluster (of is dit NodePool? [[TODO]]) dezelfde service op dezelfde (node) poort blootstelt.

Als ik een service maak die wordt weergegeven op NodePort X, kan ik er zeker van zijn dat als ik toegang krijg tot die poort op * een * knooppunt in het cluster, ik toegang krijg tot de service. Dit vormt de basis van de load-balancing-mogelijkheden van Kubernetes omdat het cluster inkomende aanvragen voor de service naar deze poort op elk knooppunt kan routeren.

Google Cloud SDK (ook bekend als gcloud) bevat een ssh-client die het triviaal maakt om verbinding te maken met Compute Engine VM's (zoals u zich zult herinneren Kubernetes Cluster Nodes). ssh-client heeft port-forwarding-mogelijkheden. Dus als we verbinding willen maken met een Kubernetes-service en we kunnen de NodePort van de service opzoeken, dan kunnen we triviaal (!) Port-forward naar die service door port-forwarding (met behulp van gcloud of een ssh-client) naar de poort op elke Knooppunt.

In het volgende voorbeeld wordt kubectl gebruikt om het 0e knooppunt in het cluster te pakken. De naam van het Kubernetes Engine Node is hetzelfde als de VM-naam Compute Engine. Gegeven een service met de naam $ {MY_SERVICE} in een naamruimte met de naam $ {MY_NAMESPACE}, bepalen we de NodePort van de service. Vervolgens schakelen we over naar gcloud en gebruiken we de ingebouwde ssh voor port-forward (met --ssh-flag = "- L XXXX: localhost: XXXX).

NODE_HOST = $ (\
  kubectl knooppunten krijgen \
  --output = jsonpath = "{. items [0] .metadata.name}")
NODE_PORT = $ (\
  kubectl services krijgen / $ {MY_SERVICE} \
  --namespace = $ {MY_NAMESPACE} \
  --output = jsonpath = "{. spec.ports [0] .nodePort}")
echo $ {NODE_PORT}
gcloud bereken ssh $ {NODE_HOST} \
--ssh-flag = "- L $ {NODE_PORT}: localhost: $ {NODE_PORT}" \
--project = $ {YOUR_PROJECT}

Wat is hier zo krachtig aan? Nu hebt u mogelijk toegang tot de service alsof deze lokaal is en zonder gaten in een firewall te hoeven slaan.

NodePorts zijn hoog genummerde poorten (~ 30.000 - 32.767).

9. Hacking kubectl gebruikt JSON

Google's Cloud SDK (ook bekend als gcloud) is echt uitstekend, maar kubectl (Kubernetes CLI) is beter (sic). Een krachtige functie is het formatteren en filteren van uitvoer. Dit maakt niet-coderende (niet-API-wrangling) manieren mogelijk om scripts en andere tools uit te breiden met informatie van Kubernetes-clusters.

Alle bronstatus van Kubernetes is toegankelijk via b.v. kubectl krijgt (naar mijn ervaring nuttiger voor dit doel dan kubectl beschrijven) commando's. Het enige dat overblijft is om de naald te vinden in wat een hooiberg van JSON kan zijn.

De kunst is om:

kubectl krijgt [resource] / [resource-name] --output = JSON

En kijk vervolgens naar de resultaten om een ​​querystring te bouwen:

kubectl krijgt [resource] / [resource-name] --output = jsonpath = ". items [*]"

en verfijn iteratief het vastgestelde resultaat totdat u de item (s) hebt die u zoekt. Hier is een voorbeeld dat zou moeten werken met elk cluster:

kubectl krijgt knooppunten --output = json
kubectl get nodes --output = jsonpath = "{. items [*]}
kubectl get nodes --output = jsonpath = "{. items [0]}
kubectl get nodes --output = jsonpath = "{. items [0] .metadata.name}

Ten slotte is er een fatsoenlijk argument (en een stelling in * nix) voor het leren van één JSON-parsing-tool en het toepassen van die tool op alle JSON-parsingbehoeften. Is er in dit geval een redelijke concurrent van jq? Ik vermoed van niet.

Plus jq heeft een uitstekende speeltuin (jqplay.org).

A. Gebruik etiketten

Het is lang geleden, maar allerlei softwarediensten ondersteunen nu het concept van willekeurige etikettering van middelen (meestal sleutel / waarde-paren). De reden dat dit krachtig is, is dat deze metagegevens een open, volledig door de gebruiker gedefinieerde manier bieden om naar bronnen te zoeken. Kubernetes maakt inherent gebruik van dit principe; het is een intrinsieke mogelijkheid en geen na-gedachte | bolt-on.

Een Kubernetes-service onthult een willekeurig aantal Kubernetes-pods. Een Services onthult * geen * Pods genaamd "Henry" of Pods die een ReplicaSet bevatten. In plaats daarvan stelt een service pods bloot waarvan de labels voldoen aan criteria die zijn gedefinieerd tijdens de specificatie van de service en deze labels zijn natuurlijk door de gebruiker gedefinieerd.

NB In het bovenstaande voorbeeld gebruiken we een naamruimte met de naam project-x en deze naamruimte-specificatie verschijnt in de naamruimte (wanneer deze is gemaakt), de implementatie om te bepalen waar de implementatie bestaat, en in de service. De implementatie (die microservice-y wordt genoemd) maakt een ReplicaSet (impliciet hier gespecificeerd; dit is wat implementaties maken) die 100 pods kan behouden. Elke pod heeft een label-app: publicname-a en bevat één container met de naam grpc-proxy op basis van een afbeelding met de naam image-grpc-proxy. De service wordt service-p genoemd. Cruciaal is dat de Service (!) Pods selecteert (alleen in de naamruimte project-x) die een label-app hebben: publicname-a. De service selecteert elke pod (in de naamruimte project-x) met dit label (sleutel: waarde) -paar * en niet alleen de pods die in deze implementatie zijn gemaakt. De Service verwijst niet naar pods op basis van hun naam (die is gebaseerd op de implementatienaam), hun containernaam of de naam van de containerafbeelding, alleen de labels die aan de pod zijn gekoppeld.

NB Dit is * geen * een goede praktijk maar het bewijst het punt. Als u een configuratie zoals hierboven uitvoert en vervolgens afzonderlijk maakt, b.v. een pod met Nginx (in de naamruimte project-x) en vervolgens voegde u de label-app toe: publicname-a, deze zou snel worden opgenomen in de set pods die zijn geaggregeerd door de service-p Service. Als u het label zou verwijderen uit een van de pods die door de service zijn verzameld, zou de pod niet meer worden opgenomen.

Deze functie wordt geïllustreerd door rollende updates waarbij de implementatie een nieuwe ReplicaSet maakt met nieuwe pods voor versie X ', anders dan de ReplicaSet en pods voor versie X. De Service kan worden gedefinieerd om het kruispunt van pods zichtbaar te maken die in beide versies lopen omdat het wordt niet gedefinieerd in termen van de ReplicaSets of specifieke pods, maar door door de gebruiker gedefinieerde labels ("selectors") die door u worden toegepast wanneer de pods worden gemaakt.

Dat is heel krachtig!

B. Gebruik Jsonnet, mogelijk Ksonnet

Twee uitdagingen met alle (!?) Gestructureerde formaten (YAML, JSON, XML, CSV ;-) zijn zelfreferenties en variabelen. Terwijl u specificaties van marvellous.yaml maakt voor uw Kubernetes-implementatie, zult u dit probleem snel tegenkomen. Je zult merken dat je letterlijk gebruikt (bijvoorbeeld voor afbeeldingsnamen en samenvattingen) en, zelfs met de gewaardeerde implementaties, herhalende namen en selectors.

Er is geen oplossing voor deze problemen als u zich beperkt tot YAML en JSON. Google heeft Jsonnet gedeeltelijk gemaakt om deze problemen aan te pakken. De slimme Heptio-mensen hebben Jsonnet uitgebreid naar Kubernetes met ... Ksonnet.

Beide zijn sjabloontalen die de hierboven geschetste problemen (en meer) aanpakken. Ik moedig je aan om Jsonnet te overwegen. Zoals met mijn aanbeveling om jq te overwegen, leer Jsonnet een keer en pas het overal toe waar u JSON gebruikt. Ksonnet is specifiek voor Kubernetes en - in mijn beperkte (!) Ervaring - vond ik dat de voordelen van deze specificiteit niet opwegen tegen de leercurve.

C. YAML of JSON

Kubernetes behandelt YAML en JSON grotendeels gelijk. Persoonlijk vind ik YAML verkieslijk voor configuratiebestanden die ik kubectl - omdat YAML korter is dan JSON. Hoewel ik YAML moeilijker vind om te schrijven.

Als het echter gaat om het begrijpen van structuur en parseren, geef ik de voorkeur aan --output = JSON en ook omdat - output = JSONPATH. Ik ben een grote Golang-fan, maar Go-sjablonen zijn niet zo intuïtief en ik gebruik ze niet.

weinig inzicht: YAML is een superset van JSON (link) ... wacht! wat?

D. Downward Dog API en config

De "Downward API" om het de juiste, zij het niet minder verwarrende naam te geven, is een faciliteit in Kubernetes waarmee Pods een idee kunnen krijgen van de cluster om hen heen. Ik neem aan dat de normale stroom van de buitenwereld naar de pod en zijn containers gaat * maar * er zijn momenten waarop het nuttig is voor een container (!) Om informatie over zijn omgeving te verkrijgen, b.v. zijn knooppuntnaam | IP, de naam van de pod (spatie) | IP.

De neerwaartse API-waarden worden aan de container gepresenteerd via omgevingsvariabelen. Omgevingsvariabelen worden (zoals elders) gebruikt om containers of een andere status aan containers te geven. Een heel mooi gevolg van het gebruik van omgevingsvariabelen en de implementatie van de Downward API (met een kleine waarschuwing) is dat de container ontkoppeld blijft van Kubernetes.

Hier is een voorbeeld van mijn buddy - Sal Rashid - die de Downward API gebruikt om de Node- en Pod-status te verzamelen en deze aan de gebruiker te presenteren:

https://github.com/salrashid123/istio_helloworld/blob/master/all-istio.yaml

NB Zie de secties die beginnen op regels 76, 80, 84, 88 waar Pod-naam, naamruimte, IP en knooppuntnaam tijdens runtime door de Downward API worden verstrekt aan de container met de naam myapp-container.

De Downward API is de enige praktische manier om deze gegevens voor een container te verzamelen. Het is dus meer een "enige oefening" dan een "beste oefening".

In veel van mijn berichten, terwijl ik oplossingen voor Kubernetes bouw, test ik het proces lokaal en buiten een container, vervolgens in een container (omgevingsvariabelen opgeven) en vervolgens op een Kubernetes-cluster. De gecontaineriseerde mechanismen zijn consistent (zie hieronder), hoewel er meestal een wordt uitgevoerd op Docker en een op Kubernetes.

In een bericht dat ik onlangs schreef over het door Google geoptimaliseerde OS-besturingssysteem, demonstreer ik een container die lokaal wordt uitgevoerd onder Docker, op afstand onder Container-Optimized OS en vervolgens op Kubernetes.

Dit wordt lokaal onder Docker uitgevoerd. Merk op hoe de omgevingsvariabelen (--env) worden gebruikt om gcr.io/${PROJECT}/datastore te configureren.

Docker uitvoeren \
--interactief \
--tty \
--publish = 127.0.0.1: 8080: 8080 \
--env = GCLOUD_DATASET_ID = $ {PROJECT} \
--env = GOOGLE_APPLICATION_CREDENTIALS = / tmp / $ {ROBOT} .key.json \
--volume = $ PWD / $ {ROBOT} .key.json: / tmp / $ {ROBOT} .key.json \
gcr.io/${PROJECT}/datastore

Dit is hetzelfde resultaat als het implementeren van een container-geoptimaliseerde VM. Bekijk deze keer de waarden die zijn opgegeven voor de container-env-vlag:

gcloud beta-rekeninstanties create-with-container $ {INSTANCE} \
--zone = $ {ZONE} \
--image-family = cos-stable \
--image-project = cos-cloud \
--container-image=gcr.io/${PROJECT}/${IMAGE}@${DIGEST} \
--container-herstart-beleid = altijd \
--container-env = \
GCLOUD_DATASET_ID = $ {PROJECT}, \
GOOGLE_APPLICATION_CREDENTIALS = / tmp / $ {ROBOT} .key.json \
--container-mount-gastheer-path = \
mount-path = / tmp \
gastheer-path = / tmp \
mode = rw \
--project = $ {PROJECT}

En tot slot is hier het YAML-fragment van de implementatie voor Kubernetes:

containers:
      - naam: datastore
        afbeelding: gcr.io/${PROJECT}/datastore
        imagePullPolicy: Altijd
        volumeMounts:
          - naam: datastore
            mountPath: / var / secrets / google
        env:
        - naam: GOOGLE_APPLICATION_CREDENTIALS
          waarde: /var/secrets/google/datastore.key.json
        - naam: GCLOUD_DATASET_ID
          waarde: $ {PROJECT}
        poorten:
        - naam: http
          containerpoort: 8080

Ik vind dus het gebruik van omgevingsvariabelen voor configuratie nogal onhandig. Er is geen duidelijke opzettelijke binding van specifieke omgevingsvariabelen aan specifieke processen en je realiseert je alleen dat ze niet correct zijn geconfigureerd wanneer dingen kapot gaan. Het is gemakkelijk om je omgevingsvariabelen voor te stellen die conflicteren in een niet-gecontaineriseerde omgeving, hoewel dit een minder probleem is met containers omdat we, zoals hierboven, expliciet waarden instellen voor een specifieke container.

Dat gezegd hebbende, het is de beste praktijk om omgevingsvariabelen op deze manier te gebruiken.

E. Zijspannen en waarom pods niet altijd synoniem zijn met containers

5 cl cognac
2 cl drievoudige sec
2 cl citroensap
Voorbereiding Giet alle ingrediënten in een cocktailshaker gevuld met ijs. Goed schudden en zeef in cocktailglas.

Meestal maak je Kubernetes-pods die afzonderlijke containers bevatten en vraag je je af waarom er allemaal overhead is aan een pod als je maar één container nodig hebt. Pods zijn meer analoog aan een hostomgeving die veel containers kan draaien. Vaak zul je overwegen om meerdere containers in een pod te gebruiken ...

... en slechts één keer dat je zou moeten :-)

Waarschijnlijk meer dan één, maar laten we het maar één keer houden.

Het antipatroon (doe dit niet) is om uw huidige configuratie voor te stellen (laten we aannemen dat een webserver en een database-backend) en beide in een pod te jammen. Dit is * geen * een goed idee * tenzij * elke webserverinstantie onlosmakelijk en voor altijd verbonden moet zijn met een specifieke database-instantie. Dit is onwaarschijnlijk.

Wat waarschijnlijker is, is dat uw webserverinstanties moeten schalen door de verzamelde frontend-belasting en uw database-instances moeten schalen (onafhankelijk van dit en) op basis van hun geaggregeerde vermogen om de front-endbelasting te verwerken. Wanneer u aggregaat ziet, denk aan Service en wanneer u denkt aan Service, probeer dan een willekeurig aantal Pods te overwegen (omdat het belangrijk is voor uw factuur, maar voor de meeste andere doeleinden maakt het niet uit hoeveel Pods nodig zijn zolang de nummer is precies goed voor de werklast).

Wanneer moet u meerdere containers per pod overwegen? De enige keer dat dit * altijd * zinvol is, is wanneer u het gedrag van de primaire pod in een container wilt aanvullen, uitbreiden of verrijken. Laten we het webserver- en database-voorbeeld van bovenaf opnieuw bekijken. In dit scenario ben je er hopelijk nu van overtuigd dat je twee Services (en twee Deployments) gaat inzetten, een voor de frontend en een voor de backend.

Het is een goede en gebruikelijke praktijk om uw webserverinstantie zelf te voorzien van een reverse-proxy. Gewoonlijk zou dit Nginx of HAProxy zijn en het wordt steeds gebruikelijker om Envoy te gebruiken (ik raad aan om, als u naar proxy's kijkt, Envoy te overwegen; zie #F Istio). Een reverse-proxy zorgt voor consistentie (we gebruiken alleen bijv. Envoy), zelfs als u verschillende webservers gebruikt (bijv. Apache, Tomcat met Java enz.), Zelfs als u een combinatie van HTTP-, gRPC-, Web Sockets-verkeer hebt. , zelfs als u wat verkeer naar uw webserver wilt sturen en wat verkeer naar een cache (bijv. Varnish).

In alle voorgaande scenario's zou het logisch zijn om het "zijspan" -model te gebruiken. In dit model heeft de primaire container (uw webserver) aanvullende, aanvullende containers (Envoy-proxy, Varnish-cache enz.). Deze moeten nauw gekoppeld zijn aan een specifieke webserverinstantie * en * functioneel, de combinatie is de "eenheid".

Het is heel gebruikelijk om logging, monitoring, trace en andere infrastructurele componenten ook als zijspannen te zien leveren. Een motivatie hier is om zorgen te scheiden. Om ontwikkelaars een consistente vereiste te bieden die code produceert die 'beheersbaar' is en SRE de flexibiliteit biedt om voorkeurstools te kiezen wetende dat alle code in de vloot zal loggen, metrieken uitzenden, traceerbaar zijn, consequent auth toepassen etc. Dit is een patroon die de basis vormt voor servicegaas (zie #F Istio). Dit is de laatste beste, zij het in opkomst zijnde praktijk.

F. Gebruik Istio

Gebruik Istio zorgvuldig.

Istio (en andere servicegaas) zijn relatief ontluikende technologieën die zijn ontwikkeld door bedrijven (waaronder Google) die op grote schaal containers hebben gerund. Servicemasten plaatsen triviaal een universele (in het geval van Istio, Envoy) proxy in elke pod in elke implementatie in elke naamruimte in elk cluster.

Het resultaat is een consistent beheersubstraat dat losse koppeling van beheer mogelijk maakt (we zullen vandaag Stackdriver Trace gebruiken, maar er is een plan om te migreren naar Jaeger, we rollen onze Prometheus-monitoring uit) en controlediensten (we weten dat al onze diensten veilig zijn, we leiden 10% van het verkeer naar de kanarie-builds van services A, B en C).

Ik adviseer "zorgvuldig", omdat deze technologieën nieuw zijn, ruwe randen hebben en zich snel ontwikkelen. Maar de voordelen (flexibiliteit, behendigheid, toekomstbestendig) van de methodologie bieden u waarschijnlijk veel zwaarder dan de kosten. Het belangrijkste is dat u service-mesh als uw model met Kubernetes gebruikt, zelfs als u nog geen van de service-mesh-technologieën wilt gebruiken.

Dat is alles Mensen!