Inhoudsopgave

1. Inleiding

Taking a look at the infrastructure in my first few days of working at Xoxoday, I quickly realized that the infrastructure was relatively nascent. The multiple loose ends I noticed were potential indicators of technical debt, strictly speaking in terms of Infrastructure setup. The loose ends included the design, architecture, tooling, monitoring, and logging, along with various processes & practices.

Considering the nature of business, Xoxoday is a user-facing web service that could typically be categorized under Software as a Service (SaaS). That puts a lot of pressure on specific technical requirements such as availability, uptime, reliability, robustness & scalability.

A typical e-commerce website such as Xoxoday with high global traffic necessitates that we adapt to the latest and unique design patterns, architecture, tools & practices. This is to ensure that we keep up with the quality of service expected by the user base and ideally exceed the same.

Ten slotte is een andere kritieke eis die voortvloeit uit privacy- en veiligheidsoverwegingen dat de meeste klanten zich zorgen maken over de locatie van de gegevens. De gebruikelijke verwachting is dat de gegevens blijven en nooit het door hen gewenste land of de door hen gewenste regio verlaten.

Hierdoor ontstond de behoefte om te overwegen meerdere productieomgevingen parallel in te zetten, atomaire implementaties onafhankelijk van elkaar. Wij noemen dit een polycloud, hoewel de term misschien discutabel is. Voor deze eis moesten we beschikken over de modernste automatisering, omdat we nu ons infrastructuurbeheer en -onderhoud in meerdere regio's moesten repliceren.

Daarom realiseerden we ons na rijp beraad al snel dat we het beste van de infrastructuurautomatiseringsprocessen en -praktijken nodig hadden, samen met een portfolio van moderne cloudgebaseerde technologieën om cloud-native te worden en onze gebruikers de beste service en ervaring te bieden.

Het voordeel voor ons was dat de ontwikkelaars hun diensten al hadden opgesplitst in microservices. Dat hielp ons om snel de nieuwste trends en praktijken op het gebied van infrastructuur over te nemen.

2. Behoefte aan automatisering

Serviceautomatisering in de cloud is de laatste jaren een hot topic geweest, wat heeft geleid tot de opkomst van vele uitstekende tools & technologieën. Onze behoeften werden bepaald door de aard van het bedrijf en zijn eisen. Voor ons waren de volgende factoren cruciaal:

  • Hoge beschikbaarheid
  • Auto-Scaling
  • Zelfgenezend

Bovendien biedt automatisering de mogelijkheid om infrastructuur als code te realiseren, zodat we met de infrastructuur kunnen communiceren terwijl we de fantastische voordelen van versiebeheersystemen benutten.

Dit was een grote paradigmaverschuiving omdat het ons in staat stelde proactief naar de infrastructuur te kijken en de reactieve (dwingende) interacties te verminderen. Het maakte rollbacks gemakkelijker en hielp ons efficiënt wijzigingen in de infrastructuur bij te houden. Automatisering betekende ook dat onze DevOps-teams op oneven uren met een gerust hart konden werken.

Een ander bijkomend voordeel van automatisering is dat het verschillende wegen opent voor modernisering en verbetering van de productiviteit van ontwikkelaars. In het volgende deel over continuous delivery gaan we dieper in op dit specifieke onderwerp.

3. Continue integratie, levering en implementaties

Releases kunnen een pijnlijke nachtmerrie worden als de juiste pipelines, tools en richtlijnen ontbreken. Dit betekende dat de kritische ruggengraat van DevOps de CI/CD-pijplijnen waren die ons hielpen bij het testen, integreren, bouwen en implementeren van onze code in productie.

We wilden meerdere productie-installaties op één dag kunnen uitvoeren en deze implementaties naadloos laten verlopen. Als het stuk ging, wilden we de updates naadloos en snel kunnen terugdraaien.

Zoals eerder vermeld, hadden onze ontwikkelaars fantastisch werk geleverd door de monolithische diensten af te breken in microservices, wat de deuren opende naar de native cloud-wereld. Toch kwam het met zijn eigen uitdagingen. De grootste uitdaging was het testen van de integratie.

Bovendien stelden onze architectuur en enkele uitstekende cloud-native tools ons in staat om softwareontwikkeling innovatief te benaderen. We ontwrichtten de traditionele conventies om ons aan te passen aan de nieuwe en opwindende wereld van microservices.

Beginnen met de gevestigde praktijk van het hebben van meerdere omgevingen stelde ons in staat om onze portfolio van functies te testen en nauwkeurig te onderzoeken voordat we deze in productie namen. Zodra ze klaar waren met hun specifieke functies, bugs of verbeteringen, openden onze ontwikkelaars een pull request naar de "dev" branch op git.

Zodra de PR was goedgekeurd, werden de commits samengevoegd op de dev branch. We hadden een handmatig trigger mechanisme voorzien om de ontwikkel tak uit te rollen naar de ontwikkelaars. (die we later zullen onderzoeken)

De codebase op deze tak werd uitgerold naar de ontwikkelaarsomgeving, een speciale omgeving voor ontwikkelaars om hun bleeding-edge features te testen. Er waren twee ontwikkelomgevingen, één voor de ontwikkelaars om hun features en microservices te testen en de andere voor integratietesten.

Zodra de codebase was getest, en het QA team het had goedgekeurd, werden de commits verder samengevoegd in de "staging of uat" tak. Vanaf hier werd de codebase ingezet (handmatig geactiveerd) op de Staging-omgeving, die we zo dicht mogelijk bij de productie wilden houden.

Er was nog een set ogen op Staging voordat werd overwogen welke functies en microservices naar productie zouden worden verscheept. We hadden een andere omgeving, de demo-omgeving, uitsluitend gereserveerd om onze diensten te demonstreren aan potentiële klanten die onze diensten wilden verkennen.

We onderzochten en analyseerden de best mogelijke tools voor CI/CD, en uiteindelijk kwamen we uit bij Github Actions. Kortom, Github Actions bood ons een geïntegreerde omgeving die goed samenwerkt met de GitHub-workflow en een minimale onboarding heeft voor de ontwikkelteams.

Samen met de strakke integratie voorzag het ons ook van de modernste CI/CD-mechanismen. Het is supersnel, betaalbaar, eenvoudig te configureren en aan te passen. En het had een supermakkelijke YAML-gebaseerde syntaxis om de jobs te definiëren, waardoor we de CI/CD-definitie met de codebase konden committen en volgen met de geweldigheid van git.

a. Continue integratie

We onderzochten een paar manieren om automatisch te bouwen, maar beseften al snel dat het beter is om de ontwikkelaars te laten bepalen wanneer er wordt gebouwd. Er kunnen vele redenen zijn voor of tegen automatische uitrol en handmatige uitrol.

Het is beter om de verwachtingen van de teams op elkaar af te stemmen en deze beslissing te verpakken op basis van gemak, want te veel automatisering heeft potentiële valkuilen.

Voor onze niet-productie omgevingen hadden we een handmatige trigger om de laatste builds te bouwen en uit te rollen in de respectievelijke omgevingen. In onze productieomgevingen werden builds automatisch getriggerd op een git tag push. Met Git tags konden we ons houden aan een versiebeheerschema en was het handig om de versies in productie terug te draaien als dat nodig was.

Laten we de unit tests en de functionele tests die de ontwikkelaars op hun commits uitvoerden buiten beschouwing, laten we ons richten op de infrastructurele kant van de dingen in onze CI/CD. De bouwtaak, eenmaal gestart, authenticeert in principe met ECR, beheert de image cache en voert het docker build commando uit om een container image te maken.

Deze container image wordt gepushed naar de respectievelijke ECR repository. Het is een eenvoudige opzet maar uiterst krachtig en flexibel omdat het ons in staat stelt de trigger over te dragen aan de ontwikkelaars terwijl het hele proces wordt geautomatiseerd.

b. Continue implementaties

We hadden een handmatige trigger voorzien voor de ontwikkelaars om de laatste builds uit te rollen op de respectievelijke omgevingen. We gebruikten Docker image tags om onderscheid te maken tussen de container images voor de individuele git branch en de omgeving.

Onze microservices draaiden op Kubernetes. Een typische deploy job doet het volgende:

  1. De configuratiebestanden & variabelen bijwerken: We verwijderen de bestaande configmaps en maken ze opnieuw aan, aangezien Kubernetes een bestaande configmap niet bijwerkt. Onze configuratiebestanden worden vastgelegd in een private git repository, en de gevoelige informatie wordt opgeslagen op AWS Secrets Manager. Met git kunnen we dus de configuratiebestanden volgen, wat het voor ons gemakkelijker maakt om de configmaps in kubernetes te verwijderen en opnieuw aan te maken.
  2. De implementatie & service op Kubernetes bijwerken (indien er wijzigingen zijn in de Yaml-bestanden)
  3. En doe tot slot een kubernetes rollout deployment omdat Kubernetes niet automatisch de deployments/pods bijwerkt alleen voor wijzigingen in de configuratiebestanden (configmaps).

We gebruikten de volgende bronnen van de GitHub-actiegemeenschap om ons te helpen gemakkelijk verbinding te maken, te authenticeren en te communiceren met EKS/ECR & Docker.

4. Architectuur

We hebben AWS gebruikt voor onze infrastructuurbehoeften. AWS biedt ons een rijk ecosysteem van diensten die onze vloot van microservices en bijbehorende backend en middleware efficiënt draaien en beheren.

These microservices are running atop Kubernetes managed by AWS EKS. AWS EKS offering saves us a lot of time and effort that Xoxoday would otherwise spend on managing the lifecycle of the Kubernetes cluster itself. That allows us to take advantage of the cloud native ecosystem while focusing on our services and working on them.

Kubernetes brengt ongeveer tien jaar ervaring in van het runnen van de wereldwijde infrastructuur van Google. Het biedt ons verschillende functies. Om er een paar te noemen: Self-healing, autoscaling, hoge beschikbaarheid en tegelijkertijd consolidatie en verhoging van de efficiëntie waarmee we onze onderliggende infrastructuur gebruiken. We gebruiken de ingress om onze diensten bloot te stellen aan de buitenwereld via een mix van Application en Classic Load Balancers en route53 DNS entry automation.

Deze diensten maken verbinding met onze backend, die gehost wordt in een mix van AWS managed services zoals managed Kafka, RDS & self-hosted EC2 instances. Wij maken veel gebruik van Terraform voor de geautomatiseerde installatie van EKS, een unieke combinatie van Terraform en AWS Launch Templates om de EC2-instanties te spawnen en automatisch te beheren.

Daarnaast wordt SaltStack gebruikt voor complexe manoeuvres van het beheer van de geautomatiseerde setup van de vloot van EC2 instances. Het stelt ons in staat het besturingssysteem en de diensten die erop draaien automatisch te beheren, bij te werken en te onderhouden. SaltStack heeft een robuuste functieset en een briljant ontworpen, flexibele & pluggable architectuur. Wij leveren dan automatisch de diensten en nemen de nieuw geconfigureerde backend instellingen (IP-adressen etc.) en vullen de kubernetes configuratiebestanden, updaten de configmaps en implementeren ze in de omgeving.

Hierdoor kunnen we de stateless services die in de Kubernetes-omgeving draaien, configureren en herconfigureren zodat ze automatisch worden voorzien en geconfigureerd met de dynamische veranderingen in de backend setup. Onze container images worden opgeslagen op AWS ECR omdat het ons een andere fantastische dienst biedt die naadloos integreert met onze gegeven set technologieën en architectuur.

5. Logging, monitoring, alarmering en APM

We zouden blind zijn als we niet zouden beschikken over de juiste feedbackmechanismen om te begrijpen wat er in onze infrastructuur gebeurt, vooral als we het hebben over een Polycloud-scenario.

a. Elasticsearch/Fluentd/Kibana

Wij gebruiken de unieke EFK-stack voor onze loggerelateerde zaken. Hiermee kunnen we een dynamische reeks microservices creëren en onderhouden die in containers en virtuele machines draaien, terwijl de logs in een gecentraliseerde pijplijn worden bewaard.

Dit geeft ons toegang tot logs voor instanties/containers die om verschillende redenen worden vernietigd. En dat maakt het gemakkelijker voor ons om op een verstandige manier toegang te krijgen tot meerdere problemen in productie en deze aan te pakken. Hier zijn andere elasticsearch-alternatieven die je kunt kiezen.

b. Grafana/Prometheus

Grafana dashboard, samen met de Prometheus time-series database, stelt ons in staat om verschillende details over onze infrastructuur te bewaren, zoals de CPU/RAM/Storage, enz. en houdt ons op de hoogte van de huidige status van de infrastructuur in near real-time.

Dat stelt ons in staat om waarschuwingsmechanismen te implementeren, waardoor het voor ons DevOps-team gemakkelijker wordt om incidenten in onze infrastructuur af te handelen. Ondanks alle voorbereidingen en het beste van de beste architectuur & ontwerp, kunnen er nog steeds dingen stuk gaan. De Grafana Prometheus systemen, samen met Alertmanager, maken het mogelijk om incidenten in productie te beperken.

Bovendien profiteert deze stack van Application Programming Management, dat ons een rijke verzameling meetgegevens verschaft die ons kritisch inzicht geven in de producten, hun gebruik en meer.

6. Verstoring van de ontwikkelomgeving

Since we were walking on the path of microservices, we had to manage over 40 microservices which when orchestrated together to form our web service www.xoxoday.com. This implies a lot of communication between these microservices, and the sheer number of them makes it impossible and impractical to run it locally on the developer’s machine.

Daarom moesten we creatief worden en teruggaan in de diepe wateren van de native-cloudwereld om een mogelijke oplossing te vinden. We zagen er veel, om er een paar te noemen:

- Telepresence

- Skaffold

- Kubefwd

Op dit moment is Kubefwd onze favoriet en de meest nuttige die aan onze behoeften voldoet, maar in de toekomst kunnen we de andere tools verkennen. Met Kubefwd kunnen we Kubernetes-diensten toegankelijk maken op het lokale werkstation via dezelfde DNS, alsof de machine van de lokale ontwikkelaar zich in het Kubernetes-cluster bevindt!

Dit betekent een geweldige productiviteitsimpuls die ontwikkelaars efficiënter maakt, terwijl de algemene ervaring wordt verbeterd en de tussentijd om een functie de wereld in te krijgen wordt verkort.

7. Conclusie

Na maandenlang onze infrastructuurbehoeften onder de loep te hebben genomen en afgestemd te hebben op de bedrijfsbehoeften, de toekomstige groei en de huidige trends in de infrastructuur en cloud-native wereld, zijn we eindelijk op een punt gekomen waarop we met vertrouwen kunnen uitkijken naar een aantal fantastische dagen die voor ons liggen.

Onze infrastructuur heeft niet alleen tien jaar lang evolutionaire sprongen gemaakt, maar is er ook in geslaagd de druk op DevOps-teams te verminderen en tegelijkertijd de productiviteit van de ontwikkelaars drastisch te verhogen. Eindelijk is onze setup goedkoper en doet meer, en doet het beter!

Met deze opzet kunnen we eenvoudig onze hele set van diensten, frontend en backend repliceren en zichzelf binnen enkele minuten automatisch instellen. Zo kunnen we meerdere atomaire, onafhankelijke productieomgevingen creëren, deze achteraf inrichten met onze CI/CD-pijplijnen en de complexe opstelling met gemak automatisch beheren en onderhouden.

Daarnaast is het meest cruciale voordeel van dit alles dat onze DevOps-teams klein kunnen blijven en lineair kunnen schalen, terwijl ze exponentiële wereldwijde schaal voor onze diensten bieden. En de kers op de taart is dat het DevOps-team rustige avonden en geweldige weekends kan hebben zonder reactief productieproblemen te hoeven bestrijden, omdat ons ontwerp en onze architectuur ons in staat stellen deze uitdagingen proactief aan te pakken.

Een van de fantastische dingen van onze opstelling is dat het geautomatiseerde karakter ons in staat stelt spot instances te gebruiken voor onze niet-productie en niet-kritische systemen. Dit helpt ons bij het optimaliseren en consolideren van de kosten, terwijl we over voldoende rekenkracht beschikken. Dit betekent zeer kosteneffectieve setups, en als AWS besluit onze spot instances te sluiten, geen probleem, binnen een paar minuten zullen we onze dedicated instances automatisch schalen en het beste van beide werelden maken!

De huidige trends in de infrastructuurwereld, vooral gezien de Cloud Native ontwikkelingen, maken het een spannend decennium voor DevOps; het voelt alsof we het nirvana naderen. Het grote aantal tools, oplossingen, diensten en ecosystemen dat opduikt kan soms overweldigend zijn. Toch, achteraf gezien, stevenen we af op een opwindend tijdperk van rotsvaste webdiensten die robuust en altijd beschikbaar zijn en tegelijk een fantastische ervaring bieden aan de gebruikers.

Pranav Salunke