Er zijn phishingmails in omloop die uit naam van TransIP worden verstuurd. Twijfel je over de echtheid van een e-mail van TransIP, klik dan niet op linkjes en neem contact met ons op via je controlepaneel of via support@transip.nl. Lees meer over phishing in onze Knowledge Base: https://www.transip.nl/knowledgebase/artikel/205-wat-is-phishing/
Hulpartikel overzicht

Hulpartikel

Kubernetes (yaml) objects maken

In een Kubernetes-cluster zijn objects entiteiten die gebruikt worden om de gewenste status van een cluster te beschrijven. Specifieker nog: een object beschrijft de gewenste status van een 'resource' binnen je Kubernetes-cluster, zoals een Deployment of Service. Hiermee geef je bijvoorbeeld aan wat voor applicaties er moeten draaien, met wat voor hardware resources en wat voor policies. Men gebruikt hiervoor bijna altijd .yaml-bestanden om JSON-data aan de Kubernetes API aan te bieden.

Binnen een dergelijk .yaml-bestand beschrijf je de gewenste specificatie van een object (de zogeheten object spec), bijvoorbeeld van een Deployment. In deze handleiding laten we zien hoe je een Kubernetes-object opbouwt. Hiervoor bespreken we een aantal van de meest voorkomende opties die je tegen kunt komen in verschillende type Kubernetes-objecten en geven we een voorbeeld van een Deployment-object.

Dit artikel is zo breed mogelijk ingestoken, maar er is per type resource een verschil in hoe bepaalde velden/keys in het .yaml-bestand wordt ingevuld. Wil je direct weten hoe de opmaak van een bepaald type resource zoals een Deployment of Service er uitziet? Neem dan een kijkje in de Kubernetes API documentatie voor een overzicht van resources en de opties die je kunt gebruiken om een object op te bouwen.


De opmaak van een Kubernetes-object

 

In deze paragraaf bespreken we in chronologische volgorde de meest gebruikte componenten waaruit een .yaml Kubernetes-object is opgebouwd. Let daarbij altijd op de indents (spaties/tabs) in de structuur van een object. De belangrijkste componenten die altijd aanwezig moeten zijn, zijn apiVersion, kind, metadata en spec:

apiVersion: 
kind: 
metadata: 
spec: 

In dit artikel kom je een aantal keer de term 'key' en 'value' tegen. Simpel gezegd is de key de naam van een item in een object, zoals hierboven 'apiVersion'. De value is de waarde die achter een key wordt ingevuld, bijvoorbeeld 'apps/v1'. Niet iedere key krijgt overigens een value, maar kan ook onderliggende keys inleiden.


ApiVersion

 

De apiVersion geeft aan welke versie van de Kubernetes API gebruikt wordt om het object aan te maken. Hiervoor gebruik je de syntax:

apiVersion: <groupname>/<version>

Als groupname en versie zul je in de praktijk meestal apps/v1 gebruiken. Dit is de standaard optie voor het maken van een object voor het hosten van applicaties zoals Nginx of MySQL en ziet er bijvoorbeeld als volgt uit:

apiVersion: apps/v1

Een overzicht van beschikbare groups en API versienummers vind je hier. Daarnaast is ook de legacy/core group nog beschikbaar via de groupname/versie 'api/v1'.


Kind

 

Kind vertelt wat voor type object je een object schema voor maakt. Een kind kan een van drie types zijn:

  • Objects (Deployment, Pod, Service, EndPoints, Ingress, PersistentVolume, etc) - Deze worden het vaakst gebruikt en staan voor (semi) permanente/persistent entiteiten.
  • Lists - (PodList, APIResourceList, etc) - Verzamelingen van resources van een of meer kinds.
  • Simple - (status, scale, etc.) specifieke acties op objecten of niet-permanente entiteiten (ListOptions, Policy, etc).

Enigszins verwarrend, maar de voorbeelden die je achter deze drie types kind ziet, worden ook 'Resources' genoemd, bijvoorbeeld in de Kubernetes API-documentatie.

apiVersion: <groupname>/<version>
kind: <object_type>

Stel dat je een Deployment wil maken voor een applicatie, dan ziet de kind er inclusief apiVersion bijvoorbeeld als volgt uit:

apiVersion: apps/v1
kind: deployment

Metadata

 

De metadata helpt een object een unieke identiteit te geven. Beschikbare opties zijn onderandere:

  • name: De naam van het object, bijvoorbeeld 'nginx-deployment'
  • UID: Optioneel een unieke UID, bijvoorbeeld 1234ab-1234-abcde-12345
  • namespace: Een namespace is een soort van verzamelnaam waaronder Deployments, Services, Persistent Volume e.d. vallen.
  • labels: Een combinatie van een 'key' en een 'value' om specifieke attributen toe te voegen die helpen met het identificeren van het object, zie het stukje over labels verderop in dit artikel voor meer informatie
  • annotations: In bepaalde gevallen kun je een 'annotatie' toevoegen aan een object. Dit is bijvoorbeeld het geval wanneer je een loadbalancer service aanmaakt. Zie voor meer informatie ook het stuk over annotaties verderop in deze paragraaf.
  • creationTimeStamp: Wanneer het object is aangemaakt, bijvoorbeeld met de waarde 2022-11-11T11:11:11Z (let op de T en Z)
  • resourceVersion: Een intern versienummer van het object. Deze wordt gebruikt door clients om te bepalen wanneer wijzigingen zijn doorgevoerd. Via een API call kun je een 'watch' request uitvoeren om wijzigingen te zien (in JSON data) die zijn uitgevoerd sinds het versienummer.

Een 'name' is de minimale vereiste voor het metdata veld, bijvoorbeeld (inclusief voorgaande opties):

apiVersion: <groupname>/<version>
kind: <object_type>
metadata:
  name: <deployment_name>

Wanneer je alle eerdergenoemde opties samenvoegd kan dit er bijvoorbeeld voor een Nginx-Deployment als volgt uitzien:

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: nginx-deployment
  uid: 12345ab-1234-abcde-12345
  labels:
    app: nginx
  annotations:
    nginx.org/proxy-connect-timeout: 30s
  creationTimestamp: 2022-11-11T11:11:11Z
  resourceVersion: "12345"

 

Labels

Labels zijn een type metadata die bestaan uit een key en een value. Labels gebruik je om eigenschappen van je object te omschrijven. Het aardige hiervan is dat je vrij bent om zelf labels te bedenken en in te vullen. De enige beperking is dat de 'key' van een label uniek moeten zijn per object.

De structuur van een label ziet er als volgt uit:

metadata:
  labels:
    key1: value1
    key2: value2

Je bent vrij in je keuze van labels, maar voor het gemak zetten we een aantal voorbeelden van veelgebruikte labels op een rij:

  • app: nameofapp, bijv. mysql.
    In plaats van 'app' kom je in de documentatie van Kubernetes de naam 'app.kubernetes.io/name' tegen, maar voor simpliciteit raden we aan 'app' te gebruiken.
  • instance: nameofapp-uniqueID, bijv. mysql-abcd
  • version: versienummer, bijv. 8.0
  • component: type component, bijv database
  • part-of: onderdeel van groter geheel, bijv. WordPress
  • managed-by: gebruikte beheertool, bijv. Helm
  • release: release tier of naam, bijv. stable of Jelly
  • environment: type omgeving, bijv dev of production
  • tier: de code tier, bijv backend
  • partition: gebruikersnaam, bijv klantA of klantB

Enkele van deze opties samengevoegd zien er bijvoorbeeld als volgt uit:

metadata:
  labels:
    app: mysql
    version: 8.0
    part-of: WordPress
    release: production

 

Annotations

Door een annotatie mee te geven kun je het gedrag van een applicatie beïnvloeden. Let wel dat lang niet alle objecten gebruik kunnen maken van Annotaties en dit doorgaans in de verdiepende documentatie van de makers van de betreffende applicatie is opgenomen, niet in de documentatie van Kubernetes zelf. Net als labels maken annotations gebruik van keys en values:

metadata:
  annotations: 
    key1: value1
    key2: value2

Welke annotaties je mee kunt geven verschilt per applicatie, maar een mooi voorbeeld hiervan is het aanmaken van een loadbalancer service. Door onder metadata een of meer annotations mee te geven kun je het gedrag van de loadbalancer aanpassen, bijvoorbeeld als volgt:

apiVersion: v1
kind: Service
metadata:
  name: example-loadbalancer
  annotations:
    service.beta.kubernetes.io/transip-loadbalancer-ptr: mail.jedeomein.nl
    service.beta.kubernetes.io/transip-loadbalancer-ssl-mode: on

Let op: naast bovenstaande code is ook het 'spec'-onderdeel nodig, zie de volgende paragraaf. Meer informatie over het specifiek maken van loadbalancer services als object, of via Kubectl vind je in ons artikel over Kubernetes-loadbalancers.


Spec

 

De Spec beschrijft de gewenste staat van het object, bijvoorbeeld wat voor container image gebruikt wordt, waar logbestanden worden weggeschreven, etc.

Er zijn zeer veel verschillende keys beschikbaar onder Spec. In deze paragraaf bespreken we de meest voorkomende spec-opties voor workload- en service-resources. Let wel dat niet alle keys in het overzicht hieronder door alle type resources gebruikt kunnen worden of vereist zijn. Raadpleeg daarvoor altijd de documentatie van het betreffende type object/resource.

Workload resources:

Kubernetes maakt onderscheid in verschillende type resources. Hieronder volgt een voorbeeld van keys die je het meest tegenkomt bij workload resources zoals Deployments, StatefulSets en Pods.

spec: 
  replicas: 
  strategy:
    type:
  selector: 
    matchLabels:
      app:
  template: 
    metadata:
      labels:
        app:
    spec:
      containers:
      - name: 
        image: 
        resources:
          limits: 
            memory: 
          requests:
            cpu: 
            memory: 
        ports: 
        - containerPort: 
          name:
        volumeMounts:
        - mountPath:
          name: 
      volumes: 
      - name:
        persistentVolumeClaim: 
        claimName: 

Op het eerste gezicht kan het spec-blok intimiderend overkomen, maar veel items zijn optioneel, of hebben zelf geen value omdat ze een of meer andere keys inleiden (bijvoorbeeld hierboven de 'selector').

Let op: Als een key een onderdeel is van een bovenliggende structuur/tree dan wordt die in het overzicht hieronder met punten onderscheiden worden, bijvoorbeeld: selector.matchlabels.app

  • spec: De eerste 'spec:' vermelding opent het spec-component en moetaanwezig zijn in een Kubernetes-object. Je vult niets in achter 'spec:'
  • replicas: Het aantal pods dat actief moet zijn met de specificaties die in dit .yaml-bestand zijn opgenomen.
  • strategy: Bevat de keys en values met betrekking tot de rollout strategie. Deze key krijgt geen value en is samen met de bijbehorende keys optioneel. Als je geen rollout strategie specificeert worden RollingUpdates gebruikt. Hierbij worden wanneer nodig pods één voor één worden vervangen, bijvoorbeeld om een update uit te rollen. Een verdiepend artikel over de beschikbare opties/strategiën en de werking daarvan vind je hier.
  • strategy.type: Het type strategy, bijvoorbeeld RollingUpdate.
  • selector:Een selector is een fancy naam voor het mechanisme waarmee een client/user objecten kan selecteren aan de hand van labels. Dit is optioneel en bijvoorbeeld handig wanneer Kubernetes verbanden legt tussen resources. Stel dat je een verband wil leggen tussen een Deployment en een Service, dan doe je dat aan de hand van een selector. De key selector krijgt zelf geen value, maar leid andere keys in.
    Beschikbare opties zijn selector, selector.matchExpressions en selector.matchLabels. Verwarrend genoeg zijn de laatste twee 'sub'-keys van de selector key. Welke van deze opties je kiest, is afhankelijk van het type resource dat je aanmaakt (bijv een Deployment of Service) en vind je terug in de Kubernetes API-documentatie van de betreffende resource.
  • selector.matchLabels: Deze optie wordt veelal gebruikt om een workload resource object vanuit een andere object via een selector aan te preken, of omgekeerd. De key matchLabels krijgt zelf geen value, maar leid andere keys in.
  • selector.matchLabels.app: De naam van de applicatie waar je de matchLabel voor gebruikt, bijvoorbeeld nginx. Het is belangrijk dat als je naar deze applicatie verwijst vanuit een ander object dat de value die je hier opgeeft overeenkomt in de selectors van die andere objecten.
  • selector.matchExpressions: Een aanvullende lijst met conditionele voorwaarden, zie deze handleiding. De key matchExpressions krijgt zelf geen value, maar leid andere keys in.
  • template: Hieronder vind je een metadata-sectie die heel veel lijkt op de metadata die we in de eerdere paragraaf bespraken. Het enige verschil is dat de eerdergenoemde metadata aan de Deployments wordt meegegeven en de metadata onder 'template' aan de Pods. Daarnaast bevat de template ook een spec deel, zie hieronder.
  • template.metadata template.metadata.labels & template.metadata.labels.app: zie onder 'template'hierboven.
  • template.spec: Enigszins verwarrend, maar de eerdere key 'spec' heeft op zijn beurt een key genaamd 'spec'. In deze laatste staan alle gegevens met betrekking tot de pods die aangemaakt worden, bijv met betrekking tot de gebruikte container image en healthchecks. Spec krijg dan ook geen value maar leid andere keys in.
  • template.spec.containers: Deze key leid alle keys in die de specificaties van je containers beschrijven en krijgt zelf geen value. Alle onderliggende keys die containers beschrijven wijzen naar de specificaties van de container, niet naar die van de Node of Pod. Iedere unieke container wordt ingeleid met een - .
  • template.spec.containers.name: De naam van je container. Je bent vrij in je keuze, maar meestal komt deze overeen met de gebruikte applicatie, bijvoorbeeld 'nginx' of 'mysql'.
  • template.spec.containers.image: Hier specificeer je welke image gebruikt wordt. Dit kan enkel de naam zijn, bijvoorbeeld 'nginx' of 'mysql' maar kan ook de specifieke versie bevatten als volgt: image: nginx:1.22.1.
    Standaard worden de officiële images gebruikt die op Dockerhub aangeboden worden. Een overzicht daarvan vind je hier. Je bent vrij om Deployments te maken op basis van welke image dan ook die je in dit overzicht vindt. 
  • template.pec.containers.resources: Optionele mogelijkheid om te specificeren hoeveel resources zoals CPU en RAM een container nodig heeft. Deze specificaties hebben geen invloed op Pods of Nodes. De key resources krijgt zelf geen value.
  • template.spec.containers.resources.limits: Leidt de optie in om een maximum in te stellen op de resources die gebruikt worden door een container. Deze key krijgt geen value.
  • template.spec.containers.resources.limits.cpu: De maximum hoeveelheid CPU die een container kan gebruiken. Dit kan uitgedrukt worden in absolute aantallen (1, 2), in tienden (0.1 0.2) of in m/Mi (100m 2000Mi). Met een limiet van 1 beperk je de container tot 1 core, met 0.1 of 100m tot 100 milicpu, ongeacht het aantal cores. 1 core = 1000 milicpu dus 2000m stelt een max in van 2 cores. Voor meer informatie, zie Kubernetes Resources-documentatie.
  • template.spec.containers.resources.limits.memory: De maximum hoeveelheid geheugen die een container tot zijn beschikking heeft. Dit kan uitgedrukt worden in hoeveelheid E, P, T, G, M, k of Ei, Pi, Ti, Gi, Mi, Ki. 100M is bijvoorbeeld 100 megabyte.
  • template.spec.containers.resources.requests: Optioneel veld om aan te geven hoeveel resources een container minimaal tot zijn beschikking moet hebben. De key requests krijgt zelf geen value.
  • template.spec.containers.resources.requests.cpu: De minimale hoeveelheid CPU die een container tot zijn beschikking moet hebben. Als mogelijke value zijn dezelfde opties beschikbaar als hierboven onder limits.cpu zijn beschreven.
  • template.spec.containers.resources.requests.memory: De minimale hoeveelheid RAM die een container tot zijn beschikking moet hebben. Als mogelijke value zijn dezelfde opties beschikbaar als hierboven onder limits.ram zijn beschreven.
  • template.spec.containers.ports: De ports key leidt het blok in waarin je de portconfiguratie van je container configureert. Dit gaat enkel over de port die voor communicatie vanuit de Pod zelf wordt gebruikt, niet voor de Node waar die Pod op draait. Je kunt dus meerdere Pods op één Node hebben die dezelfde port-configuratie in dit onderdeel hebben. Deze key krijgt geen value.
  • template.spec.containers.ports.containerPort: De poort die door de container gebruikt wordt, bijvoorbeeld 80 voor Nginx. Door meerdere containerPort keys toe te voegen kun je meerdere poorten definiëren, bijvoorbeeld 80 en 443 voor respectievelijk HTTP en HTTPS.
  • template.spec.containers.ports.containerPort.name: Optioneel kun je een naam tussen quotes toevoegen, bijvoorbeeld "http".

    Let op: Hieronder volgen keys met betrekking tot volumeMounts en volumes. Deze zijn optioneel; een proces in een container ziet/krijgt namelijk automatisch een filesystem opgebouwd aan de hand van de inhoud van de container image (die je opgeeft onder spec.containers.image). Volumes zijn opties daar bovenop om aanvullende directories te mounten in de container. Hiervoor zijn bovendien aanvullende stappen nodig, naast de definities in bijvoorbeeld een Deployment- of Pod-object.
    Meer informatie over het gebruik van populaire type volumes zoals een Persistent Volume voegen we later toe in een aparte handleiding.

  • template.spec.containers.volumeMounts: De key volumeMounts bevat een overzicht van waar je binnen een container een volume mount. Het volume zelf is een directory op een schijf en wordt gedefinieerd in spec.volumes, zie iets verderop in dit overzicht. De key leidt andere keys in en krijgt zelf geen value.
  • template.spec.containers.volumeMounts.mountPath: De folder waar de onder spec.volumes gespecificeerde volume wordt gemount, bijvoorbeeld /data.
  • template.spec.containers.volumeMounts.name: De naam van het gemounte volume, bijvoorbeeld nginx-persistent-volume. Deze moet overeenkomen met de spec.volumes.name, zie iets verder in deze hierarchy.
  • template.spec.volumes: Een volume is een directorie op een schijf of in een andere container. Met de volumes key stel je die beschikbaar aan je pod. Op zijn beurt stelt (hierboven) de volumeMounts key en onderliggende structuur het volume beschikbaar aan een container. Een overzicht van alle beschikbare type volumes vind je hier. Twee van de belangrijkere type volumes zijn Persistent Volumes en Ephemeral Volumes. De eerste blijft behouden, ook wanneer een Pod wordt verwijderd, de tweede wordt samen met een Pod verwijderd. Deze key krijgt ook geen value.
  • template.spec.volumes.name: De naam van het volume dat je toevoegt, bijvoorbeeld 'nginx-persistent-volume'
  • template.spec.volumes.name.persistentVolumeClaim: Van de verschillende type volumes kom je persistentVolumeClaim in de praktijk het meeste tegen. Een Persistent Volume is niets anders dan een stuk storage in je Kubernetes-cluster dat losstaat van je Pods (op ons platform komt dit overeen met de schijfruimte van je node). Een persistentVolumeClaim is op zijn beurt een verzoek om een deel van die schijfruimte toe te voegen aan je object.

 

Service resources:

Pods worden van tijd tot tijd vervangen door nieuwe Pods. Om ervoor te zorgen dat aan de frontend kant daar niets van gemerkt wordt, maak je gebruik van service resources. Een service is een soort van policy waarmee je applicaties op Pods kunt aanspreken.

spec:
  type: 
  externalName: 
  selector:
    app: 
  ports:
  - protocol: 
    port: 
    targetPort: 
  • spec: Zie de eerste spec-toelichting onder workload resources.
  • type: Een optioneel onderdeel dat alleen gebruikt wordt bij een Service-object om het type service te omschrijven, bijvoorbeeld 'type: LoadBalancer'.
  • externalName:Een optionele key die gebruikt wordt bij Services om een DNS-naam aan de service te koppelen, bijv. nginx.voorbeeld.nl.
  • selector: Zie de selector-toelichting onder workload resources.
  • selector.app: Zie de selector.app-toelichting onder workload resources.
  • ports: De ports key direct onder de spec key (let op het inspringen/de indentation) kom je eigenlijk enkel tegen bij objecten die een service definiëren. Je gebruikt de ports key en de onderliggende keys om de poort(en) van een service te binden aan de poort(en) van een Pod. De ports key krijgt zelf geen value.
  • ports.protocol: Het protocol dat de betreffende service gebruikt, bijvoorbeeld TCP of UDP.
  • ports.port: De poort die door de betreffende service gebruikt wordt, bijvoorbeeld 80 voor Nginx.
  • ports.targetPort: De port-configuratie in Pods en andere workload resources hebben namen, zie spec.containers.ports.containerPort.name onder workload resources. Je refereert hiernaar door exact dezelfde naam op te geven als targetPort value (zie de volgende paragraaf voor een voorbeeld).

Een object maken en gebruiken binnen je cluster

 

Je hebt nu een scala aan veel voorkomende keys gezien die je tegen kunt komen in een Kubernetes .yaml object, maar hoe ziet dit er ingevuld uit en hoe gebruik je het? Dit laten we zien aan de hand van twee objecten: een Nginx Deployment resource en een Service resource voor Nginx.

 

Stap 1

Je maakt voor ieder object een afzonderlijke yaml file in een directorie naar keuze, bijvoorbeeld voor de Nginx-Deployment zelf:

nano nginx/deployment.yaml

Geef het bestand de volgende inhoud, waarbij we in dit voorbeeld geen opties hebben toegevoegd waar aanvullende stappen voor nodig zijn.

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: nginx-demo
  name: nginx-deployment
  labels:
    app: nginx
  creationTimestamp: 2022-02-12T11:11:11Z
  resourceVersion: "12345"
spec: 
  replicas: 3
  strategy:
    type: RollingUpdates
  selector: 
    matchLabels:
      app: nginx
  template: 
    metadata:
      labels:
        app: nginx
    spec: 
      containers:
      - name: nginx
        image: nginx:1.22.1
        resources:
          limits: 
            memory: 1G
          requests:
            cpu: 400m
            memory: 1G
        ports: 
        - containerPort: 80

Sla de wijzigingen op en sluit nano met ctrl + x > y > enter.


 

Stap 2

Definieer vervolgens het Service-object, bijvoorbeeld:

nano nginx/service.yaml

Geef het bestand de volgende inhoud:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: nginx-demo
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: nginx

Sla de wijzigingen op en sluit nano met ctrl + x > y > enter.


 

Stap 3

Beide configuraties neem je in gebruik op je Kubernetes-cluster door ze te 'applyen':

kubectl apply -f nginx/deployment.yaml
kubectl apply -f nginx/service.yaml

Let wel dat om je Nginx-deployment van buitenaf te benaderen je een loadbalancer service moet toevoegen. Hoe je dit doet, de status van je Deployment, Service, en Pods bekijkt, en de Deployment en Service verwijdert, leggen we uit in deze handleiding.

 

Heb je ook een goed idee?

Stuur jouw idee in! Met genoeg stemmen komt jouw idee op onze wishlist!

Heeft dit artikel je geholpen?

Maak een account aan of log in om een beoordeling achter te laten.

Reacties

Maak een account aan of log in om een reactie te plaatsen.

Kom je er niet uit?

Ontvang persoonlijke hulp van onze supporters

Neem contact op