Ansible en OpenShift - een krachtige combinatie voor deployment
Ansible en OpenShift zijn uitermate goed samen te gebruiken. In dit artikel zullen we kijken hoe we Ansible kunnen inzetten om een OpenShift cluster te beheren en applicaties uit te rollen op een OpenShift cluster. Traditioneel worden applicaties uitgerold vanuit OpenShift templates, Helm charts, pipelines en soortgelijke tools. In dit artikel zullen we de basis leggen voor het uitbreiden of vervangen van deze deployment methodes met Ansible.
Dit artikel gaat uit van basiskennis van zowel OpenShift / Kubernetes als Ansible.
Alles is YAML, YAML is alles
Alles in Ansible is YAML, alles in OpenShift (Kubernetes) is ook YAML. Twee voorbeelden:
-
play.yml
-
secret.yml
Het eerste voorbeeld is een Ansible playbook, het tweede voorbeeld is een Kubernetes (k8s) resource definitie voor een Secret. Het feit dat allebei de technologieën gebaseerd zijn op de dezelfde markup taal maakt het makkelijk om de twee te integreren.
Kubernetes API
K8S wordt aangestuurd met een REST API. Wanneer we het netwerkverkeer zouden
bekijken van een oc apply -f secret.yml
voor het tweede voorbeeld, of
wanneer we -v=8
of hoger meegeven aan het oc commando, dan zien we de
volgende informatie (geformatteerd voor leesbaarheid):
1Request Body: {
2 "apiVersion": "v1",
3 "kind":"Secret",
4 "metadata": {
5 "name": "helloworld",
6 "namespace": "example"
7 },
8 "stringData": {
9 "geheim": "Hello World"
10 },
11 "type":"Opague"}
12Request URI: https://api.crc.testing:6443/api/v1/namespaces/example/secrets
13Request Type: POST
Dit is een request voor het aanmaken van een nieuwe resource. Het aanpassen of verwijderen van bestaande resources gaat net iets anders (andere HTTP methodes, ander body formaat, uri voor specifieke resource), maar de theorie blijft hetzelfde. Een k8s resource wordt via een CRUD API aangemaakt, opgevraagd, aangepast of verwijderd.
Dit betekent dat we in theorie via de Ansible uri module alles zouden moeten kunnen doen, maar er zijn betere opties…
Ansible k8s module
In een basisinstallatie van Ansible wordt de k8s module beschikbaar gemaakt. Deze module kan gebruikt worden om Kubernetes resources aan te maken, aan te passen en te verwijderen. Zoals het een goede Ansible module betaamt wordt dit alles idem-potent gedaan. Dat wil zeggen, of een play(book) nou één of meerdere malen wordt uitgevoerd, het resultaat is hetzelfde.
Het onderstaande playbook maakt een nieuwe namespace aan, genaamd ‘voorbeeld’. Vanwege de idem-potentie kunnen we dit playbook ook draaien als de namespace al bestaat en zal er niks aan de namespace veranderen:
1- name: Create voorbeeld namespace
2 hosts:
3 - localhost
4 gather\_facts: false
5 become: false
6 tasks:
7 - name: Create namespace
8 k8s:
9 definition:
10 apiVersion: v1
11 kind: Namespace
12 metadata:
13 name: voorbeeld
Als we dit playbook analyseren dan zien we de volgende dingen:
- We voeren het playbook uit tegen
localhost
. Dit kan ook een ander systeem zijn, maar het is (meestal) niet het OpenShift cluster, maar de machine vanaf waar de Kubernetes API calls uitgevoerd worden. Als er geen expliciete Kubernetes authenticate opties aan de k8s module worden meegegeven wordt dekubeconfig
van deansible\_user
op de doelmachine gebruikt. - Omwille van de snelheid verzamelen we geen Ansible facts.
- Er zijn geen root privileges nodig, dus
become
staat opfalse
. - Van alle opties die met k8s module kunnen worden gebruikt gebruiken we er nu slechts één:
definition
. Voor andere bewerkingen zullen we meer opties gebruiken.
Ansible rollen gebruiken
In het bovenstaande voorbeeld hebben we één object aangemaakt, en nog met een vaste naam ook. Om schaalbaar te zijn willen we eigenlijk gebruik maken van Ansible variabelen, templates en rollen.
Het onderstaande voorbeeld transformeert het vorige voorbeeld naar een rol en voegt ook een secret toe aan de namespace:
-
create-ns-from-role.yml
-
roles/k8s_project/templates/namespace.yml.j2
-
roles/k8s_project/templates/secret.yml.j2
-
roles/k8s_project/tasks/main.yml
-
roles/k8s_project/defaults/main.yml
Het playbook (create-ns-from-role.yml
) heeft nu geen directe taken meer, maar
roept wel een rol op: k8s_project
.
In de rol k8s_project
hebben we drie hoofdelementen: tasks
, templates
en
defaults
.
-
defaults
In
roles/k8s_project/defaults/main.yml
definiëren we wat variabelen. Omdat we ervan uitgaan dat een gebruiker van onze rol andere waarden zal willen invullen, hebben we deze op het niveau vandefaults
gezet. Alle variabelen zijn geprefixed met onze rol-naam zodat de rol netjes naast andere rollen kan leven, zonder conflicten in variabele namen. -
templates
In de
templates
directory van de rol hebben we twee Jinja2 templates gemaakt. In het template voor het secret gebruiken we nu in plaats vanstringData
data
. Eendata
veld bevat dezelfde inhoud alsstringData
, maar dan in base64 encoding. In dit geval doen we de base64 encoding zelf met Ansible. Beide oplossingen zijn functioneel gelijk, de Kubernetes API transformeert stringData waardes zelf automatisch naar base64 encoded waardes onderdata
. -
tasks
In de taken van onze rol loopen we over beide templates, om ze aan de k8s module te geven. De constructie hier met een template lookup, gefilterd door het
from_yaml
filter, is er eentje die we vaker tegen zullen gaan komen. Detemplate
lookup zoekt, net zoals de module met dezelfde naam, altijd eerst in de templates directory van de rol van waaruit hij wordt opgeroepen.Het
from_yaml
filter zorgt ervoor dat de YAML formattering van de templates goed bewaard blijft.
Conclusie
Met weinig werk kan Ansible gebruikt worden om bestaande deployment oplossingen zoals OpenShift templates of Helm charts te vervangen, met de mogelijkheid om méér logica en flexibiliteit in te bouwen dan andere oplossingen bieden, zoals het automatisch aanpassen van deployment variabelen, het updaten van database schema’s of zelfs integreren met externe systemen zoals monitoring oplossingen.