Bygga en bra CI/CD-pipeline med GitHub Actions Det är inte längre en extrafunktion "för när det finns tid": i moderna team är det praktiskt taget ett krav för snabb och tillförlitlig implementering. Ändå är det ofta mycket mer komplicerat än det verkar att hitta ett komplett, generiskt och väl genomtänkt exempel som du kan anpassa till ditt företag.
I följande rader kommer vi att blanda den klassiska teorin om CI/CD med exempel på verkliga implementeringar med GitHub-åtgärder, återanvändbara pipelines, uppgifter, bash-skript, PowerShell PnP-modulerImplementeringar till Kubernetes, Google Cloud och Kinsta, tillsammans med bästa praxis för säkerhet, övervakning och skalbarhet. Tanken är att du kan ta dessa delar, anpassa dem till ditt sammanhang och undvika många av de typiska fallgroparna.
Varför du behöver en välbyggd CI/CD-pipeline
I nuvarande professionell utveckling är CI/CD kodens cirkulationssystemDen integrerar ändringar, kör tester, bygger artefakter och distribuerar nya versioner med minimal inblandning. Utan detta arbetsflöde blir varje distribution en långsam, felbenägen och manuell prövning.
Kontinuerlig integration (CI) fokuserar på att validera förändringar Så snart de laddats upp till arkivet körs enhetstester, linter-tester och statiska analyser för att upptäcka buggar så snabbt som möjligt. Ju snabbare du får feedback, desto snabbare kan du åtgärda dem och desto mindre smärtsam blir eventuell regression.
Kontinuerlig driftsättning (CD i betydelsen kontinuerlig driftsättning) eller Continuous Delivery (beroende på automatiseringsnivån) lägger till automatisering av releasedelen: bygga avbildningar, publicera paket, driftsätta till test-, staging- eller produktionsmiljöer, och till och med ändra trafik med hjälp av blågröna eller canary-strategier.
I företag med mycket äldre kodEn bra pipeline är en av de bästa hävstångarna för att modernisera ekosystemet: den låter dig introducera tester i äldre tjänster, automatisera uppgifter som tidigare gjordes manuellt och minska kostnaderna för att underhålla infrastrukturer som Jenkins eller Nexus som har blivit föråldrade.
Vad är GitHub Actions och varför passar det så bra med CI/CD?
GitHub Actions är den automatiseringsplattform som är inbyggd i GitHub. Det låter dig definiera arbetsflöden i YAML-filer i själva arkivet. Med det kan du kompilera, testa, analysera och distribuera din programvara utan att konfigurera externa CI-servrar.
Ett arbetsflöde är en uppsättning jobb och steg vilket utlöses av händelser som t.ex. push, pull_request, schedule (CRON), workflow_dispatch (manuell) eller till och med åtgärder vid problem. Varje jobb körs i en runner (till exempel ubuntu-latest) och består av steg som använder återanvändbara åtgärder eller kommandon run.
GitHub erbjuder en enorm marknadsplats för aktier där man har färdiga integrationer för nästan allt: Docker, Kubernetes, AWS, Azure, Google Cloud, SonarCloud, Slack, Jira, säkerhetsanalys, linters för tusen språk, etc. Detta minskar kraftigt tiden som krävs för att sätta upp avancerade pipelines.
Jämfört med lösningar som Jenkins eller ConcourseGitHub Actions har flera tydliga fördelar: det är en hanterad tjänst (du hanterar inga servrar), den är nära kopplad till koden, den använder en pay-as-you-go-modell och den stöds av en enorm community. Dessutom är många utvecklare redan bekanta med det från egna projekt, vilket avsevärt minskar inlärningskurvan.
Grundläggande komponenter i ett GitHub Actions-arbetsflöde
Allt börjar med en YAML-fil i .github/workflows/, till exempel ci.yml o build-test-deploy.ymlÄven om syntaxen kan växa avsevärt är grundstrukturen relativt enkel.
De viktigaste avsnitten i YAML är: name (arbetsflödesnamn), on (händelser som utlöser det), jobs (uppsättning logiska uppgifter), och inom varje jobb, runs-on (löpare), steps (steg), env (globala variabler) och if (villkor för att utföra steg eller jobb).
Jobb representerar arbetsblock som kan köras parallellt eller i en kedja med hjälp av needsInom varje jobb använder stegen åtgärder (uses:) eller kommandon (run:Ett typiskt exempel inkluderar: kodutcheckning, beroendeinstallation, linter-körning, tester och byggnation.
Hemligheter och miljövariabler De hanteras på databas-, organisations- eller miljönivå. I arbetsflöden refereras de med ${{ secrets.MI_SECRET }} och tillåta arbete med API-nycklar, distributionstokens eller molnuppgifter utan att exponera dem i arkivet.
YAML tillåter också att bygga exekveringsmatriser med strategy.matrix, mycket användbart för att testa din kod på olika versioner av Node, Python eller Java, eller till och med på olika operativsystem utan att skriva samma block flera gånger.
Designa en modern CI/CD-pipeline med hjälp av bästa praxis
En hälsosam pipeline är vanligtvis uppdelad i tydliga faserSnabbkontroller (lint, enhetstester), artefaktbyggande, release (version, etikettering, ändringslogg, publicering i artefaktförråd) och distribution i en eller flera miljöer.
Den kontinuerliga integrationsfasen bör vara så snabb som möjligt. Detta säkerställer att alla push- eller pull-förfrågningar får nästan omedelbar feedback. Vanligtvis körs de olika kontrollerna parallellt med separata arrayer eller jobb, vilket ger en något högre kostnad i utbyte mot att den totala väntetiden minskas.
Att frikoppla pipelinen från det konkreta språketDu kan använda ett uppgiftsverktyg som Task (liknande Make men med en mer användarvänlig syntax). På så sätt anropar GitHub Actions-arbetsflödet bara generiska uppgifter (task test, task lintetc.) och varje repository definierar hur de implementeras internt beroende på om det är Node, Java, Python, etc.
Versionshantering och artefakter spelar in under releasefasen.Här bygger du en Docker-avbildning, en jar/war-fil, ett npm-paket eller någon annan artefakt, laddar upp den till motsvarande register (Docker-registret, Maven, npm i Artefaktregistret, etc.), taggar commits och genererar GitHub-releaser eller ändringsloggar med verktyg som git-cliff eller frigöringsåtgärder.
Slutligen, driftsättningsfasen Flytta den artefakten till runtime-miljön: Kubernetes (GKE), Google App Engine, Cloud Functions, tjänster på Kinsta, dina egna servrar via SSH, etc. Här kan du länka ihop efterföljande steg, såsom funktionstester efter distribution eller Slack-notiser med releasedetaljer.
Exempel: Komplett pipeline med ESLint, tester och driftsättning på Kinsta
Ett mycket illustrativt exempel är att använda GitHub Actions För att validera en React-applikation med ESLint och enhetstester, och sedan distribuera den till Kinsta med hjälp av dess API. Allt är orkestrerat i ett enda CI/CD-arbetsflöde.
Den första delen av YAML definierar utlösaren och pipelinenamnet. Till exempel att den körs på varje push y pull_request till grenen mainoch till och med schemalagda med CRON-jobb (till exempel varje dag vid midnatt eller varje måndag kl. 8:00 UTC) med hjälp av händelsen schedule.
Det första jobbet i pipelinen kan kallas eslint och den ansvarar för att kontrollera kodens syntax. Den körs i ubuntu-latest och använder en array av Node-versioner (t.ex. 18.x, 20.x), med steg för att checka ut och konfigurera Node med actions/setup-node, cache npm-beroenden, installera med npm ci och kasta npm run lint.
Det andra jobbet, testsDet beror på eslint genom needs: eslintså den körs bara om syntaxkontrollen lyckas. Inuti upprepas mönstret: utcheckning, installation av beroenden och körning av npm run test på en specifik version av Node.
Det tredje jobbet, deployDen är kedjad efter båda jobben med needs: och använder ett steg med curl för att anropa Kinsta API. För att göra detta konfigureras API-nyckeln och applikations-ID:t som hemligheter i GitHub (KINSTA_API_KEY y APP_ID) och exponeras i jobbet via env för att skapa POST-begäran som utlöser distributionen.
Det är viktigt att förstå att det här driftsättningsjobbet Kinsta anser att enbart godkännandet av API:et är en framgång; men om distributionen senare misslyckas internt inom Kinsta kan GitHub-arbetsflödet fortfarande visa grön status. Detta bör man ha i åtanke för att undvika självbelåtenhet och för att komplettera processen med övervakning efter distributionen.
Avancerad cron-hantering och arbetsflödesschemaläggning
CRON-syntaxen i GitHub Actions Den är baserad på UNIX femfältsformat: minut, timme, månadsdag, månad och veckodag. Varje fält kan använda asterisker, intervall, listor och steg (*, 1-5, 1,15,30, */5), vilket möjliggör schemaläggning av underhållsuppgifter, säkerhetskopior, rengöringar eller regelbundna kontroller.
T.ex. 0 0 * * * kör arbetsflödet varje midnatt (UTC), medan 0 8 * * 1 Den gör detta varje måndag klockan 8:00. Detta kombineras sömlöst med de vanliga utlösande faktorerna push y pull_requestså att samma YAML kan reagera på både kodändringar och schemalagda körningar.
Den här funktionen är idealisk för uppgifter som inte är meningsfulla att släppa i varje commit.intensiva säkerhetsskanningar (t.ex. med OWASP Dependency Check i Java), beroendegranskningar, kontroller av testtäckning eller rensning av gamla artefakter i registret.
Återanvändning av arbetsflöden: skalning av CI/CD till hundratals databaser
När din organisation har dussintals eller hundratals databaserAtt kopiera och klistra in samma YAML överallt är ett recept för kaos. Varje förändring kräver att halva GitHub Enterprise modifieras, vilket gör det nästan omöjligt att upprätthålla konsekvens och bästa praxis.
Lösningen ligger i att utforma återanvändbara arbetsflöden centraliserad i ett CI/CD-"mall"-arkiv. Dessa arbetsflöden exponerar indata och utdata, och varje tjänst definierar bara en liten YAML som anropar dem, och skickar parametrar som artefakttyp (Docker, Java-bibliotek, npm-paket), distributionskörningstid (GKE, GAE, molnfunktion, etc.) eller uppgiftsobjekt som behöver köras.
Ett vanligt mönster är att separera tre stora återanvändbara arbetsflöden: en av build-check-task (kontinuerlig integration), en annan av build-release-dockerfile eller andra artefakter och en tredje utplacering (deploy-gke, deploy-gaeetc.), så att varje arkiv bygger sin pipeline genom att kombinera dem.
För att inkapsla delad logik kan även anpassade åtgärder definieras. en .github/actionsTill exempel för att konfigurera Gradle, Java, Node eller Task, för att hämta byggmetadata, för att publicera Docker-avbildningar, för att tagga versioner i Git med ett bash-skript eller för att skicka aviseringar till Slack. Den gyllene regeln är att tjänstedatabaser endast ska använda återanvändbara arbetsflöden, inte dessa åtgärder direkt, så att bakåtkompatibilitet blir mer hanterbar.
Snabb kontinuerlig integration med Task, matriser och statisk analys
Under bygg- eller kontrollfasen är det lämpligt att utlösa många saker parallellt.Enhetstester, statisk analys (PMD, Checkstyle, SpotBugs i Java; ESLint i JS/TS), skanning med SonarCloud, etc. Detta håller den totala pipelinetiden rimlig även i stora kodbaser.
Uppgiften (Taskfile.yml) fungerar som ett abstraktionslager på specifika kommandon, vilket gör att CI-arbetsflödet enkelt kan anropa task check, task test o task lintFör ett Java-projekt kan dessa uppgifter delegeras till Gradle med JUnit, PMD, Checkstyle och SpotBugs; för ett Node-projekt till Jest, ESLint och säkerhetsverktyg som npm audit eller liknande.
GitHub Actions lägger till array-delen För att köra samma uppgifter på olika versioner av körtiden: till exempel att testa ett Node-bibliotek på 16, 18 och 20, eller ett Python-projekt på 3.10 och 3.12. Det är lika enkelt som att deklarera en array med versioner och använda den i jobbkonfigurationen.
Den här metoden är särskilt användbar i organisationer som vill stödja flera stackar. (Java, Node, TypeScript, Python, etc.) utan att behöva skriva om pipeline-logiken för varje repository: Uppgiften anpassar sig till varje språk och de återanvändbara arbetsflödena förblir i stort sett desamma.
Utgivningsfas: versionshantering, taggning och publiceringsartefakter
När kontrollerna är godkända är det dags att bygga artefakten som faktiskt ska användas.Docker-avbildning, JAR-fil, npm-paket, vad som än är lämpligt. Detta involverar både språkverktygen och organisationens register och versionspolicy.
Vissa Java-projekt använder plugins som Gradle Axion. för att hantera versioner baserat på Git-taggar. I blandade sammanhang (Java, Node, etc.) kan det vara enklare att använda ett anpassat bash-skript som beräknar nästa version (till exempel med SemVer), skapar taggen, skickar den till fjärrkontrollen och genererar motsvarande version.
Verktyg som git-cliff De hjälper till att generera ändringsloggar Baserat på commit-meddelanden klassificeras ändringar efter typ (funktion, fix, felaktig funktion etc.). Genom att integrera dem i pipelinen säkerställs att varje utgåva kommer med en tydlig ändringslogg utan att någon behöver skriva den manuellt.
För att publicera artefakter kombineras lämpliga åtgärder och inloggningsuppgifter.Docker-register (Docker Hub, GitHub Container Registry, Artifact Registry), Maven-repositories, npm-register, etc. Återigen, autentiseringsuppgifter lagras som hemligheter och injiceras endast i jobb när det behövs.
Kontinuerlig distribution till Kubernetes, GCP, Kinsta och andra miljöer
Implementering är där CI/CD interagerar med infrastrukturenHär integreras GitHub Actions sömlöst med nästan vilken plattform som helst: Kubernetes, App Engine, Cloud Functions, traditionella servrar, plattformar som Kinsta, etc.
För Kubernetes (till exempel i GKE) är det vanliga mönstret Det är: autentisera med Google Cloud (med officiella åtgärder), konfigurera kubectl Inom klusterkontexten, använd Helm-manifest eller diagram och, om nödvändigt, utför en kontrollerad utrullning (t.ex. med canary eller blue-green) och verifiera status med kommandon från kubectl rollout status.
När det gäller App Engine eller Cloud FunctionsPipelinen bygger avbildningen eller artefakten, publicerar den till artefaktregistret och anropar sedan distributionskommandona. gcloud lämpligt, återigen med hjälp av hanterade inloggningsuppgifter som hemligheter och efemära löpare.
När distributionen utförs mot externa API:er som Kinstasvanligtvis räcker ett enda steg curl eller en specialiserad åtgärd som skickar begäran med autentiseringstoken och nödvändiga parametrar (app-ID, gren, etc.). Jobbet anses vara lyckat om API:et svarar korrekt på den nya versionsbegäran.
Distributionen åtföljs nästan alltid av en avisering. till Slack, Teams eller andra kommunikationsverktyg, med angivande av vilken tjänst som driftsattes, i vilken miljö, med vilken version, vem som utlöste den och länkar till arbetsflödesloggarna. I produktion fungerar detta även för granskning och spårbarhet.
Kvalitetskontroll: säkerhet, övervakning och loggar
Att automatisera byggande och driftsättning är bra, men saknar insyn När det gäller vad som händer kan pipelinen bli en svart låda. GitHub Actions erbjuder detaljerade loggar per körning, per jobb och per steg, vilket gör att du kan diagnostisera kompilerings-, test- eller distributionsfel.
För mer avancerade behov integreras externa observerbarhetstjänster. såsom Datadog, New Relic eller Splunk, som samlar in mätvärden för arbetsflöden, exekveringstider, felfrekvenser etc., vilket hjälper till att upptäcka flaskhalsar och prioritera pipeline-optimeringar.
Parallellt spelar säkerhet en nyckelrollhantering av krypterade hemligheter, minimikrav på åtkomstpolicyer, granskning av åtgärdsbehörigheter, integrering av kodsårbarhetsskannrar och beroenden (kodskanning, hemlighetsskanning, OWASP, etc.) i själva arbetsflödena.
Många team lägger även till tester efter driftsättning i den nyligen uppdaterade miljön: heltäckande funktionstester, prestandakontroller, grundläggande röktester och, om något går sönder, automatiserade återställningsmekanismer som återställer den tidigare stabila versionen.
Arbetsflödesstyrning: skyddade grenar och pull requests
Arbetssättet med branches och pull requests måste vara i linje med CI/CD så att allt blir begripligt. Det vanligaste är att skydda huvudgrenen (main o master) och kräva att alla ändringar går igenom PR och klarar pipeline-kontroller.
GitHub låter dig definiera regler för grenskydd Dessa policyer tvingar fram användningen av pull requests, blockerar direkta commits och kräver att vissa statuskontroller (specifika åtgärdsarbetsflöden) är gröna innan sammanslagningen tillåts. De kan också kräva minimala revisioner, godkännanderegler etc.
Den här modellen säkerställer att koden som når produktionskedjan Den har genomgått mänsklig granskning och alla automatiserade pipeline-kontroller, vilket drastiskt minskar risken för att glida igenom allvarliga fel eller sårbarheter.
I företag med flera miljöer (utveckling, mellanlagring, produktion) distribution till produktion är vanligtvis reserverad för sammanslagningar till huvudgrenen, medan andra grenar kan utlösa distributioner till tidigare miljöer för intern testning eller demonstrationer.
En väl utformad CI/CD-pipeline med GitHub Actions, sett över helheten. Det blir ryggraden i utvecklingen: integrera förändringar, köra omfattande testsviter, bygga och publicera artefakter, driftsätta till flera molnplattformar, övervaka med observationsverktyg och styra genom tydliga förgrenings- och pull request-regler. Med återanvändbara arbetsflöden, anpassade åtgärder, hjälpverktyg som Task, Rease Action och Git Cliff, samt robust hantering av hemligheter och behörigheter, är det möjligt att stödja allt från enkla Python-appar till komplexa Kubernetes-arkitekturer, samtidigt som leveranshastighet, kodkvalitet och säkerhet bibehålls utan att överbelasta teamet med manuella uppgifter.