En snabbkurs i Jenkins X och hur du testar det på ett lokalt Kubernetes-kluster
Alexandru Chiritescu
Alexandru is a Consultant at our Stockholm office. Earlier he was working as an Engineering Manager at Klarna Bank. He has lived and worked in three different countries: Romania, The Netherlands, and Sweden. Alexandru likes to read and learn and he loves seeing people being motivated and happy with their work.
I det här inlägget tittar jag närmare på versionen av Jenkins X som använder Tekton, så att du får en uppfattning om hur det övergripande flödet för utveckling, bygge, test och driftsättning ser ut med Jenkins X. Hur känns det att leverera din kod till produktion med en produkt från Jenkins-communityt som innehåller väldigt lite Jenkins?
Beräknad tid för att gå igenom alla steg i den här guiden: 60–90 minuter. Lästid: 15 minuter.
Gå till de olika avsnitten i bloggen:
Om Jenkins X och Tekton
Jenkins X-projektet har funnits i nästan två år nu, och ungefär en månad efter sin första födelsedag lanserade teamet den nya Jenkins X Pipeline Engine, som körs ovanpå Tekton.
Jenkins X är i princip Jenkins coolare kusin, ett efterlängtat Cloud Native-alternativ från Jenkins-communityt. Det är mycket styrt av tydliga principer och starkt inspirerat av metoderna som beskrivs i boken Accelerate – DevOps-metoder som har visat sig förbättra mjukvaruorganisationers resultat på ett hållbart sätt.
Beroende på vilken version du väljer när du installerar den ovanpå ett Kubernetes-kluster kan du använda versionen som innehåller en statisk Jenkins-master eller de nya serverless Jenkins X Pipelines, som använder Tekton i stället för ”Jenkins som underliggande CI/CD-motor för att tillhandahålla en modern, hög tillgänglig Cloud Native-arkitektur”
Tekton är i grund och botten en uppsättning Kubernetes Custom Resource Definitions (CRD:er) som används för att deklarera pipelines i CI/CD-stil i Kubernetes. Du kan läsa mer om dem i den officiella dokumentationen, men den kunskapen krävs inte för att kunna följa det här inlägget.
Verktyg du behöver
Kom igång med Jenkins X
Obs! Standardkonfigurationen för Jenkins X som vi följer i det här inlägget kräver ett GitHub-konto. Kontot används för att skapa några repositories (ett för varje miljö samt utvecklingsprojektet) och konfigurera hooks från dem till Tekton-resurserna som körs i det lokala Kubernetes-klustret.
Det första steget är att installera Jenkins X CLI på din lokala dator. Beroende på vilket operativsystem du använder finns flera sätt att göra det på. Eftersom jag använder macOS och har brew installerat kommer jag att göra det med brew:
brew tap jenkins-x/jx brew install jxNu när jx är installerat ska vi installera Jenkins X i ett Kubernetes-kluster. Om du inte råkar ha ett oanvänt Kubernetes-kluster till hands kan du ta det lugnt och använda Minikube, ett enkelt alternativ som kör ett Kubernetes-kluster med en nod på din dator. Som tur är har Jenkins X ett särskilt kommando för att installera Jenkins X i Minikube, och det installerar även Minikube och alla dess beroenden om du inte redan har dem.
När detta skrivs har Kubernetes 1.16 precis släppts, och det verkar som att Deployment-resurserna som används av Jenkins X använder den icke-stödda API-gruppen extensions/v1beta1. Därför rekommenderar jag att du anger vilken Kubernetes-version som ska installeras tills problemet är löst:
jx create cluster minikube --kubernetes-version=v1.15.4Jag rekommenderar också att du använder följande inställningar i stället för standardinställningarna när jx frågar efter minne, cpu och diskstorlek, så att det finns tillräckligt med resurser för att köra allt:
? memory (MB) 8192 ? cpu (cores) 6 ? disk-size (MB) 150GB ? Select driver: hyperkitVälj Serverless Jenkins X Pipelines with Tekton när du blir ombedd att välja Jenkins-installationstyp. Längre fram måste du skapa en API-token i ditt GitHub-konto och ange den under installationen. Installationen kan ta lite tid eftersom många Docker-avbildningar behöver laddas ned, så jag rekommenderar att du kör den med en snabb internetanslutning.
Obs! Om du valde hyperkit och är ansluten till ett VPN när du kör kommandot ovan kommer det troligen att misslyckas på grund av ett återkommande fel i Minikube. När du har kopplat från VPN:et och försöker igen (ta bort Minikube-klustret, .minikube och .jx) bör allt fungera utan problem. —
Om du ser ett utdata som liknar det nedan vet du att installationen har slutförts och att Jenkins X körs i ditt lokala kluster:
Jenkins X installation completed successfully ******************************************************** NOTE: Your admin password is: q0DVn0ylXXEn_MVH5x3- ********************************************************Your Kubernetes context is now set to the namespace: jxTo switch back to your original namespace use: jx namespace defaultOr to use this context/namespace in just one terminal use: jx shellFor help on switching contexts see: https://jenkins-x.io/developing/kube-context/To import existing projects into Jenkins: jx importTo create a new Spring Boot microservice: jx create spring -d web -d actuatorTo create a new microservice from a quickstart: jx create quickstartContext "minikube" modified.NAME HOSTS ADDRESS PORTS AGEchartmuseum chartmuseum.jx.192.168.64.8.nip.io 192.168.64.8 80 92sdeck deck.jx.192.168.64.8.nip.io 192.168.64.8 80 92sdocker-registry docker-registry.jx.192.168.64.8.nip.io 192.168.64.8 80 91shook hook.jx.192.168.64.8.nip.io 192.168.64.8 80 92snexus nexus.jx.192.168.64.8.nip.io 192.168.64.8 80 91stide tide.jx.192.168.64.8.nip.io 192.168.64.8 80 92sLägg märke till värdarna längst ned. Det här är några smarta URL:er som använder den utmärkta tjänsten nip.io, som i princip löser alla DNS-frågor i det formatet till IP-adressen i URL:en. Hädanefter kallar vi dessa poster för klustrets Ingress-resurser. I mitt fall är 192.168.64.8 den lokala IP-adressen för Minikube-klustret, och alla dessa DNS-poster är konfigurerade som Ingress-regler som pekar på var och en av tjänsterna som körs i mitt lokala Minikube-kluster.
Obs! I vissa fall kan tjänsten nip.io vara otillgänglig från ditt nätverk, vilket innebär att domännamnen i klustrets Ingress-resurser inte fungerar. En orsak till att dessa poster inte kan lösas lokalt är att din router har DNS Rebinding-kontroller aktiverade, vilket i praktiken ignorerar DNS-svar som returnerar privata IP-adresser. Ta dig tid att öppna deck-URL:en från din installation, i mitt fall http://deck.jx.192.168.64.8.nip.io. Om du inte får upp en enkel inloggningsdialog fungerar antingen inte nip.io för dig, eller så är det något fel på din deck-pod. Om din pod är felfri föreslår jag att du antingen kontrollerar routerinställningarna och letar efter inställningar för DNS rebinding-kontroller, eller lägger till en post i /etc/hosts för alla värdar i klustrets Ingress-resurser. Om du väljer alternativet /etc/hosts bör du vara medveten om att fler värdar behöver läggas till längre fram.
Om du listar de namespaces som har skapats kommer du troligen att se en lista som denna:
$ k get nsNAME STATUS AGEdefault Active 26mjx Active 24mjx-production Active 18mjx-staging Active 18mkube-node-lease Active 26mkube-public Active 26mkube-system Active 26mNamnespaces jx-production och jx-staging motsvarar de production- respektive staging-miljöer som Jenkins X skapar som standard. En uppsättning privata repo:n som motsvarar dessa miljöer skapades också i ditt GitHub-konto under installationsprocessen:
Jag berättar mer om dessa miljöer och repo:n lite senare, men nu skapar vi ett projekt att utveckla!
Skapa en ny applikation
Jenkins X erbjuder ett brett urval av applikationsmallar som hjälper dig att snabbt komma igång. Om du ändå tycker att något saknas kan du bidra med egna via en PR. I den här genomgången valde jag react-quickstart. Du kan göra samma sak med följande kommando:
jx create quickstart -f react-quickstartJag valde att döpa projektet till react-quickstart-jenkinsx och bad jx att skapa ett repo i mitt konfigurerade GitHub-konto. Nu har den första pipelinen startats åt dig. Jag föreslår att du tar en stund och kör jx get activity -f <repo_name> -w, där repo_name är namnet på det repo som du angav i kommandot jx create quickstart.
Du ser alla steg som körs i den aktuella pipelinen och får en uppfattning om vad Jenkins X har konfigurerat automatiskt åt dig. Men fastna inte för länge vid detta. Eftersom vi kör klustret lokalt behöver vi åtgärda några saker innan pipelinen kan slutföras.
Skapa en tunnel och uppdatera webhooks
Du lade säkert märke till Creating GitHub webhook i konsolens utdata och upptäckte snabbt att URL:en för hooken pekar på en privat IP-adress. Den är inte åtkomlig från GitHub, vilket innebär att webhooks i dina repo:n inte fungerar just nu. Nu löser vi det!
Ett enkelt sätt att göra det är att använda ngrok.io. Skapa ett konto på deras webbplats, det är gratis. Nästa steg är att konfigurera det:
Följ steg 1 till 3, så är du redo att köra.
Det vi vill göra här är att öppna en tunnel från vår lokala dator till en extern URL, men inte på vilket sätt som helst. Vi vill också att ngrok skriver om värden, eftersom Ingress-reglerna i vårt kluster förlitar sig på det för att skilja mellan de olika tjänsterna som vi vill komma åt. Allt detta kan vi göra med följande kommando, där <hook_host> är hook-värden från klustrets Ingress-resurser:
ngrok http -host-header=rewrite <hook_host>:80Nästa sak du bör se är ett utdata som liknar det nedan, nu när tunneln är klar. Lägg märke till posterna Forwarding:
Nu när den externa URL:en är igång är det dags att uppdatera webhooks i GitHub-repona. Det gör du genom att gå till sidan Settings -> Webhooks för varje repo: staging-repot, produktionsrepot och repot som skapades för själva projektet. Vi behöver redigera den befintliga webhooken för varje repo och uppdatera fältet Payload URL så att det använder URL:en för ngrok.io i stället för den för nip.io. Ta mitt produktionsrepo som exempel:
Klicka på Update webhook längst ned på sidan. När den har sparats expanderar du den senaste posten i avsnittet Recent Deliveries genom att klicka på den och väljer sedan Redeliver. Om allt gick bra ska det finnas en grön bock bredvid leveransen du just skickade igen. Kontrollera nu att alla tre repon har den uppdaterade webhooken och att den senaste leveransen är grön.
Förstå konfigurationen hittills
När vi har uppdaterat och skickat om alla webhooks bör flera pipelines ha börjat köras. Om allt går som det ska visar resultatet från jx get activities alla pipelines och deras steg som har körts hittills.
Du kan visualisera samma pipelines via Prow-dashboarden, som är tillgänglig på deck-URL:en som visas i klustrets Ingresses (för mig är det http://deck.jx.192.168.64.18.nip.io/). Du kan bli ombedd att ange användarnamn och lösenord: använd admin som användare, och lösenordet visas i konsolutdata från kommandot jx create cluster.
Det här är alla pipelines som har körts hittills: en för master-grenen i vårt projekt, en för staging-repots första PR och en för master-grenen i samma repo. Vid det här laget undrar du säkert hur alla dessa pipelines dök upp och vad eller vem som skapade dem. Det ska jag försöka förklara nedan. Följande diagram ger en mycket förenklad bild av vad som händer, med fokus på ändringarna i repona och miljönamnrymderna i klustret.
Skapade ett kluster med Jenkins X installerat
När vi skapar ett nytt kluster med Jenkins X skapar CLI:t alla resurser som behövs. Bland annat skapar CLI:t ett nytt lokalt kluster med Minikube, med flera namnrymder, inklusive en för staging-miljön och en för produktionsmiljön. I det här skedet är båda tomma. Andra namnrymder skapas också men visas inte här, inklusive namnrymden jx, som innehåller alla verktyg som behövs för att Jenkins X och pipelines ska kunna köras i klustret.
jx create cluster skapar också två nya repos i GitHub: ett för staging-miljön och ett för produktion. Namnen på repona genereras i följande format: environment-$prefix-$environmentName. $prefix genereras vanligtvis slumpmässigt, men du kan ange det med argumentet --default-environment-prefix till kommandot jx create cluster.
Inga pipelines har körts än, hela konfigurationen gjordes av CLI:t.
Skapade en ny applikation med hjälp av en tillgänglig quickstart
I nästa steg skapade jag en ny applikation att utveckla med Jenkins X och använde en av deras quickstart-mallar för att skapa en ny ReactJS-applikation. Detta görs också via Jenkins X CLI.
Ett nytt repo skapas lokalt och pushas till det konfigurerade GitHub-kontot. Innehållet i repot baseras på filerna i quickstart-mallen (varje quickstart är ett repo i det här projektet) och det build pack som matchar teknikerna som används i projektet. Det build pack som väljs för projektet är
javascript-paketet, och det kopierar några av sina filer, till exempel Dockerfile, till projektet för att skapa den första commiten. Dockerfile används för att köra applikationen i alla miljöer.Med den första commiten till applikationsrepot startas en första pipeline som bygger appen och skapar en Dockerfile för den här versionen av appen. Eftersom alla commits till
master-grenen i applikationsrepot automatiskt flyttas upp till staging som standard skapas också en ny gren och PR i staging-repot för att driftsätta version 0.0.1 till staging. Den första pipelinen väntar sedan här tills promotion-byggena körs eller tills den får timeout, beroende på vad som inträffar först.Den nya promotion-PR:en i staging-repot utlöser en annan pipeline som förbereder Helm-diagrammet för driftsättning till staging och publicerar det till
chart-museumi klustret. När detta är klart mergar den andra pipelinen PR:en tillmaster-grenen i staging-repot. Detta frigör den första pipelinen och utlöser en ny build för att driftsätta applikationen till staging.
Ett nytt repo skapas lokalt och pushas till det konfigurerade GitHub-kontot. Innehållet i repot baseras på filerna i quickstart-mallen (varje quickstart är ett repo i det här projektet) och det build pack som matchar teknikerna som används i projektet. Det build pack som väljs för projektet är javascript-paketet, och det kopierar några av sina filer, till exempel Dockerfile, till projektet för att skapa den första commiten. Dockerfile används för att köra applikationen i alla miljöer.
Med den första commiten till applikationsrepot startas en första pipeline som bygger appen och skapar en Dockerfile för den här versionen av appen. Eftersom alla commits till master-grenen i applikationsrepot automatiskt flyttas upp till staging som standard skapas också en ny gren och PR i staging-repot för att driftsätta version 0.0.1 till staging. Den första pipelinen väntar sedan här tills promotion-byggena körs eller tills den får timeout, beroende på vad som inträffar först.
Den nya promote-PR:en i staging-repositoriet startar en annan pipeline som förbereder Helm-diagrammet för driftsättning till staging och publicerar det i chart-museum i klustret. När detta är klart mergar den andra pipelinen PR:en till master-grenen i staging-repositoriet. Detta låser upp den första pipelinen och startar en ny build som driftsätter applikationen till staging.
I slutet av det här steget körs applikationen i staging-miljön. Vi kan enkelt hitta dess URL med kommandot jx get applications.
Implementera en mindre funktion och driftsätt den
Nu när det är lite tydligare hur det här fungerar kan vi testa att använda det för att implementera några funktioner i vår React-app och se hur vi kan använda Jenkins X för att leverera dessa funktioner till produktion.
Jag gör en liten ändring i huvudkomponenten i vårt projekt och lägger till en ny textrad på sidan: Added a tiny, but important change to our project.
Sedan skapar jag en ny gren som heter new-feature och pushar den till remote-repositoriet. Därefter skapar jag en PR från den grenen till master och väntar på att en ny pipeline ska starta. För att se hur pipelinen fortskrider och vilka steg den innehåller kör jag följande kommando:
jx get activities -f react-quickstart-jenkinsx/PR-1 -wSom du kanske har gissat startar varje push till en gren som har en pull request en ny pipeline, och pipelinens namn har följande format: <repo-owner>/<repo-name>/PR-<pull-request-number>
Om pipelinen slutförs utan problem bör resultatet se ut så här:
alexchiri/react-quickstart-jenkinsx/PR-1 #1 2m51s 2m41s Succeeded meta pipeline 2m51s 20s Succeeded Credential Initializer 5ftfw 2m51s 0s Succeeded Working Dir Initializer 8v64t 2m51s 1s Succeeded Place Tools 2m50s 1s Succeeded Git Source Meta Alexchiri React Quickstart Ch8zz 2m49s 6s Succeeded https://github.com/alexchiri/react-quickstart-jenkinsx.git Git Merge 2m43s 3s Succeeded Merge Pull Refs 2m40s 2s Succeeded Create Effective Pipeline 2m38s 5s Succeeded Create Tekton Crds 2m33s 2s Succeeded from build pack 2m28s 2m18s Succeeded Credential Initializer Tsg4g 2m28s 0s Succeeded Working Dir Initializer N72vt 2m28s 1s Succeeded Place Tools 2m27s 1s Succeeded Git Source Alexchiri React Quickstart Jenk Ndg74 2m26s 7s Succeeded https://github.com/alexchiri/react-quickstart-jenkinsx.git Git Merge 2m19s 3s Succeeded Build Npmrc 2m16s 2s Succeeded Build Npm Install 2m14s 38s Succeeded Build Npm Test 1m36s 4s Succeeded Build Container Build 1m32s 24s Succeeded Postbuild Post Build 1m8s 1s Succeeded Promote Make Preview 1m7s 18s Succeeded Promote Jx Preview 49s 39s Succeeded Preview 31s https://github.com/alexchiri/react-quickstart-jenkinsx/pull/1 Preview Application 31s http://react-quickstart-jenkinsx.jx-alexchiri-react-quickstart-jenkinsx-pr-1.192.168.64.18.nip.ioLägg märke till pipelinens sista steg: vi har till och med fått en Preview-miljö där vi kan testa ändringarna i en tillfällig miljö. Dessutom fick jag en kommentar på min PR, gjord av en Jenkins X-bot med mina autentiseringsuppgifter, med URL:en till Preview-miljön:
(skärmbild)
Om vi följer URL:en kan vi se funktionen vi implementerade i praktiken:
Jag tycker att implementationen ser bra ut, så nästa steg är att merga pull requesten och promota funktionen till staging. För att göra det behöver jag merga pull requesten och låta pipelines ta hand om resten.
Obs! Det avsedda sättet att merga pull requesten är att godkänna den i GitHub, med kommandon som boten känner igen, till exempel /lgtm, och låta pipelines utföra mergningen. För att kunna göra det skulle jag dock behöva en annan GitHub-användare som jag kan lägga till som granskare och använda för att godkänna pull requesten. Normalt arbetar ett team med ett projekt, vilket innebär att flera användare äger det och granskar pull requests. För att konfigurera dessa användare redigerar du helt enkelt filen OWNERS i projektets repository.
Kort efter mergningen startar en ny pipeline som släpper ändringarna till miljön staging, på samma sätt som version 0.0.1 först släpptes till staging när den första committen till repositoriet react-quickstart-jenkinsx gjordes.
I det här skedet kan du se vilka Preview-miljöer som fortfarande körs med jx get previews. Då märker du att Preview-miljön som skapades för vår första pull request fortfarande körs, trots att vår PR har mergats. Du kan antingen låta Jenkins X cron-jobb ta bort den, vilket körs var tredje timme, eller ta bort den manuellt med CLI:t:
jx delete previewNu har vi implementerat en ny funktion i vårt projekt, testat den i en Preview-miljö och sedan promotat den till staging-miljön. Låt oss säga att vi har genomfört ytterligare tester i staging och är nöjda med resultatet. Hur promota vi den till produktion?
Vi använder helt enkelt kommandot promote:
jx promote react-quickstart-jenkinsx --version 0.0.2 --env productionSom du säkert har gissat startade detta två nya builds: en för att skapa en pull request i produktionsrepositoriet med den nya versionen och en annan för att merga den och driftsätta den till produktionsmiljön. När det är klart kan vi komma åt vår applikation med den nya funktionen via produktions-URL:en. Du kan när som helst se vilka applikationer du hanterar och deras respektive URL:er för varje miljö genom att köra jx get applications. Resultatet blir ungefär så här:
APPLICATION STAGING PODS URL PRODUCTION PODS URLreact-quickstart-jenkinsx 0.0.2 1/1 http://react-quickstart-jenkinsx.jx-staging.192.168.64.18.nip.io 0.0.2 1/1 http://react-quickstart-jenkinsx.jx-production.192.168.64.18.nip.ioAnvänd produktions-URL:en så ser du samma ändringar driftsatta när pipelinen är klar. Nedan visas en förenklad bild av vad som hände när ändringarna promotades till produktion:
Obs! Om du vill städa upp din miljö och ta bort Jenkins X från Minikube-klustret kan du använda kommandot jx uninstall och följa instruktionerna som visas i CLI:t. Det avinstalleras snabbt från klustret!
Några avslutande tankar
Den här genomgången skrapar bara på ytan. Det finns många bra tillägg, som Prometheus för övervakning och KNative och Gloo för bättre hantering av applikationer och resurser, samt funktioner som Dev Pods som vi inte har tagit upp.
Jag är säker på att det kommer ännu fler, och att vi kommer att höra mycket mer om dessa och Jenkins X under de kommande åren.
I dagsläget känns Jenkins X fortfarande som att det befinner sig i ett tidigt skede. Det utvecklas intensivt, och dokumentationen skulle kunna förbättras avsevärt, särskilt för användare som inte använder standardkonfigurationen och standardinställningarna.
Med det sagt har det potential att bli ett mycket kraftfullt verktyg som främjar sunda arbetssätt och vanor i team. Samtidigt använder det beprövade metoder för CI/CD.
- Cloud
- CI/CD
Subscribe to our newsletter
Related blogs