[{"data":1,"prerenderedAt":875},["ShallowReactive",2],{"/en-us/blog/tags/ci/":3,"navigation-de-de":20,"banner-de-de":441,"footer-de-de":454,"CI-tag-page-de-de":664},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"content":8,"config":11,"_id":13,"_type":14,"title":15,"_source":16,"_file":17,"_stem":18,"_extension":19},"/en-us/blog/tags/ci","tags",false,"",{"tag":9,"tagSlug":10},"CI","ci",{"template":12},"BlogTag","content:en-us:blog:tags:ci.yml","yaml","Ci","content","en-us/blog/tags/ci.yml","en-us/blog/tags/ci","yml",{"_path":21,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"data":23,"_id":437,"_type":14,"title":438,"_source":16,"_file":439,"_stem":440,"_extension":19},"/shared/de-de/main-navigation","de-de",{"logo":24,"freeTrial":29,"sales":34,"login":39,"items":44,"search":378,"minimal":414,"duo":428},{"config":25},{"href":26,"dataGaName":27,"dataGaLocation":28},"/de-de/","gitlab logo","header",{"text":30,"config":31},"Kostenlose Testversion anfordern",{"href":32,"dataGaName":33,"dataGaLocation":28},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":35,"config":36},"Vertrieb kontaktieren",{"href":37,"dataGaName":38,"dataGaLocation":28},"/de-de/sales/","sales",{"text":40,"config":41},"Anmelden",{"href":42,"dataGaName":43,"dataGaLocation":28},"https://gitlab.com/users/sign_in/","sign in",[45,89,188,193,299,359],{"text":46,"config":47,"cards":49,"footer":72},"Plattform",{"dataNavLevelOne":48},"platform",[50,56,64],{"title":46,"description":51,"link":52},"Die umfassendste KI-basierte DevSecOps-Plattform",{"text":53,"config":54},"Erkunde unsere Plattform",{"href":55,"dataGaName":48,"dataGaLocation":28},"/de-de/platform/",{"title":57,"description":58,"link":59},"GitLab Duo (KI)","Entwickle Software schneller mit KI in jeder Phase der Entwicklung",{"text":60,"config":61},"Lerne GitLab Duo kennen",{"href":62,"dataGaName":63,"dataGaLocation":28},"/de-de/gitlab-duo/","gitlab duo ai",{"title":65,"description":66,"link":67},"Gründe, die für GitLab sprechen","10 Gründe, warum Unternehmen sich für GitLab entscheiden",{"text":68,"config":69},"Mehr erfahren",{"href":70,"dataGaName":71,"dataGaLocation":28},"/de-de/why-gitlab/","why gitlab",{"title":73,"items":74},"Erste Schritte mit",[75,80,85],{"text":76,"config":77},"Platform Engineering",{"href":78,"dataGaName":79,"dataGaLocation":28},"/de-de/solutions/platform-engineering/","platform engineering",{"text":81,"config":82},"Entwicklererfahrung",{"href":83,"dataGaName":84,"dataGaLocation":28},"/de-de/developer-experience/","Developer experience",{"text":86,"config":87},"MLOps",{"href":88,"dataGaName":86,"dataGaLocation":28},"/de-de/topics/devops/the-role-of-ai-in-devops/",{"text":90,"left":91,"config":92,"link":94,"lists":98,"footer":170},"Produkt",true,{"dataNavLevelOne":93},"solutions",{"text":95,"config":96},"Alle Lösungen anzeigen",{"href":97,"dataGaName":93,"dataGaLocation":28},"/de-de/solutions/",[99,125,148],{"title":100,"description":101,"link":102,"items":107},"Automatisierung","CI/CD und Automatisierung zur Beschleunigung der Bereitstellung",{"config":103},{"icon":104,"href":105,"dataGaName":106,"dataGaLocation":28},"AutomatedCodeAlt","/de-de/solutions/delivery-automation/","automated software delivery",[108,112,116,121],{"text":109,"config":110},"CI/CD",{"href":111,"dataGaLocation":28,"dataGaName":109},"/de-de/solutions/continuous-integration/",{"text":113,"config":114},"KI-unterstützte Entwicklung",{"href":62,"dataGaLocation":28,"dataGaName":115},"AI assisted development",{"text":117,"config":118},"Quellcodeverwaltung",{"href":119,"dataGaLocation":28,"dataGaName":120},"/de-de/solutions/source-code-management/","Source Code Management",{"text":122,"config":123},"Automatisierte Softwarebereitstellung",{"href":105,"dataGaLocation":28,"dataGaName":124},"Automated software delivery",{"title":126,"description":127,"link":128,"items":133},"Sicherheit","Entwickle schneller, ohne die Sicherheit zu gefährden",{"config":129},{"href":130,"dataGaName":131,"dataGaLocation":28,"icon":132},"/de-de/solutions/security-compliance/","security and compliance","ShieldCheckLight",[134,139,144],{"text":135,"config":136},"Application Security Testing",{"href":137,"dataGaName":138,"dataGaLocation":28},"/solutions/application-security-testing/","Application security testing",{"text":140,"config":141},"Schutz der Software-Lieferkette",{"href":142,"dataGaLocation":28,"dataGaName":143},"/de-de/solutions/supply-chain/","Software supply chain security",{"text":145,"config":146},"Software Compliance",{"href":147,"dataGaName":145,"dataGaLocation":28},"/solutions/software-compliance/",{"title":149,"link":150,"items":155},"Bewertung",{"config":151},{"icon":152,"href":153,"dataGaName":154,"dataGaLocation":28},"DigitalTransformation","/de-de/solutions/visibility-measurement/","visibility and measurement",[156,160,165],{"text":157,"config":158},"Sichtbarkeit und Bewertung",{"href":153,"dataGaLocation":28,"dataGaName":159},"Visibility and Measurement",{"text":161,"config":162},"Wertstrommanagement",{"href":163,"dataGaLocation":28,"dataGaName":164},"/de-de/solutions/value-stream-management/","Value Stream Management",{"text":166,"config":167},"Analysen und Einblicke",{"href":168,"dataGaLocation":28,"dataGaName":169},"/de-de/solutions/analytics-and-insights/","Analytics and insights",{"title":171,"items":172},"GitLab für",[173,178,183],{"text":174,"config":175},"Enterprise",{"href":176,"dataGaLocation":28,"dataGaName":177},"/de-de/enterprise/","enterprise",{"text":179,"config":180},"Kleinunternehmen",{"href":181,"dataGaLocation":28,"dataGaName":182},"/de-de/small-business/","small business",{"text":184,"config":185},"den öffentlichen Sektor",{"href":186,"dataGaLocation":28,"dataGaName":187},"/de-de/solutions/public-sector/","public sector",{"text":189,"config":190},"Preise",{"href":191,"dataGaName":192,"dataGaLocation":28,"dataNavLevelOne":192},"/de-de/pricing/","pricing",{"text":194,"config":195,"link":197,"lists":201,"feature":286},"Ressourcen",{"dataNavLevelOne":196},"resources",{"text":198,"config":199},"Alle Ressourcen anzeigen",{"href":200,"dataGaName":196,"dataGaLocation":28},"/de-de/resources/",[202,235,258],{"title":203,"items":204},"Erste Schritte",[205,210,215,220,225,230],{"text":206,"config":207},"Installieren",{"href":208,"dataGaName":209,"dataGaLocation":28},"/de-de/install/","install",{"text":211,"config":212},"Kurzanleitungen",{"href":213,"dataGaName":214,"dataGaLocation":28},"/de-de/get-started/","quick setup checklists",{"text":216,"config":217},"Lernen",{"href":218,"dataGaLocation":28,"dataGaName":219},"https://university.gitlab.com/","learn",{"text":221,"config":222},"Produktdokumentation",{"href":223,"dataGaName":224,"dataGaLocation":28},"https://docs.gitlab.com/","product documentation",{"text":226,"config":227},"Best-Practice-Videos",{"href":228,"dataGaName":229,"dataGaLocation":28},"/de-de/getting-started-videos/","best practice videos",{"text":231,"config":232},"Integrationen",{"href":233,"dataGaName":234,"dataGaLocation":28},"/de-de/integrations/","integrations",{"title":236,"items":237},"Entdecken",[238,243,248,253],{"text":239,"config":240},"Kundenerfolge",{"href":241,"dataGaName":242,"dataGaLocation":28},"/de-de/customers/","customer success stories",{"text":244,"config":245},"Blog",{"href":246,"dataGaName":247,"dataGaLocation":28},"/de-de/blog/","blog",{"text":249,"config":250},"Remote",{"href":251,"dataGaName":252,"dataGaLocation":28},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":254,"config":255},"TeamOps",{"href":256,"dataGaName":257,"dataGaLocation":28},"/de-de/teamops/","teamops",{"title":259,"items":260},"Vernetzen",[261,266,271,276,281],{"text":262,"config":263},"GitLab-Services",{"href":264,"dataGaName":265,"dataGaLocation":28},"/de-de/services/","services",{"text":267,"config":268},"Community",{"href":269,"dataGaName":270,"dataGaLocation":28},"/community/","community",{"text":272,"config":273},"Forum",{"href":274,"dataGaName":275,"dataGaLocation":28},"https://forum.gitlab.com/","forum",{"text":277,"config":278},"Veranstaltungen",{"href":279,"dataGaName":280,"dataGaLocation":28},"/events/","events",{"text":282,"config":283},"Partner",{"href":284,"dataGaName":285,"dataGaLocation":28},"/de-de/partners/","partners",{"backgroundColor":287,"textColor":288,"text":289,"image":290,"link":294},"#2f2a6b","#fff","Perspektiven für die Softwareentwicklung der Zukunft",{"altText":291,"config":292},"the source promo card",{"src":293},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":295,"config":296},"Lies die News",{"href":297,"dataGaName":298,"dataGaLocation":28},"/de-de/the-source/","the source",{"text":300,"config":301,"lists":303},"Unternehmen",{"dataNavLevelOne":302},"company",[304],{"items":305},[306,311,317,319,324,329,334,339,344,349,354],{"text":307,"config":308},"Über",{"href":309,"dataGaName":310,"dataGaLocation":28},"/de-de/company/","about",{"text":312,"config":313,"footerGa":316},"Karriere",{"href":314,"dataGaName":315,"dataGaLocation":28},"/jobs/","jobs",{"dataGaName":315},{"text":277,"config":318},{"href":279,"dataGaName":280,"dataGaLocation":28},{"text":320,"config":321},"Geschäftsführung",{"href":322,"dataGaName":323,"dataGaLocation":28},"/company/team/e-group/","leadership",{"text":325,"config":326},"Team",{"href":327,"dataGaName":328,"dataGaLocation":28},"/company/team/","team",{"text":330,"config":331},"Handbuch",{"href":332,"dataGaName":333,"dataGaLocation":28},"https://handbook.gitlab.com/","handbook",{"text":335,"config":336},"Investor Relations",{"href":337,"dataGaName":338,"dataGaLocation":28},"https://ir.gitlab.com/","investor relations",{"text":340,"config":341},"Trust Center",{"href":342,"dataGaName":343,"dataGaLocation":28},"/de-de/security/","trust center",{"text":345,"config":346},"AI Transparency Center",{"href":347,"dataGaName":348,"dataGaLocation":28},"/de-de/ai-transparency-center/","ai transparency center",{"text":350,"config":351},"Newsletter",{"href":352,"dataGaName":353,"dataGaLocation":28},"/company/contact/","newsletter",{"text":355,"config":356},"Presse",{"href":357,"dataGaName":358,"dataGaLocation":28},"/press/","press",{"text":360,"config":361,"lists":362},"Kontakt",{"dataNavLevelOne":302},[363],{"items":364},[365,368,373],{"text":35,"config":366},{"href":37,"dataGaName":367,"dataGaLocation":28},"talk to sales",{"text":369,"config":370},"Support",{"href":371,"dataGaName":372,"dataGaLocation":28},"/support/","get help",{"text":374,"config":375},"Kundenportal",{"href":376,"dataGaName":377,"dataGaLocation":28},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":379,"login":380,"suggestions":387},"Schließen",{"text":381,"link":382},"Um Repositories und Projekte zu durchsuchen, melde dich an bei",{"text":383,"config":384},"gitlab.com",{"href":42,"dataGaName":385,"dataGaLocation":386},"search login","search",{"text":388,"default":389},"Vorschläge",[390,393,398,400,405,410],{"text":57,"config":391},{"href":62,"dataGaName":392,"dataGaLocation":386},"GitLab Duo (AI)",{"text":394,"config":395},"Code Suggestions (KI)",{"href":396,"dataGaName":397,"dataGaLocation":386},"/de-de/solutions/code-suggestions/","Code Suggestions (AI)",{"text":109,"config":399},{"href":111,"dataGaName":109,"dataGaLocation":386},{"text":401,"config":402},"GitLab auf AWS",{"href":403,"dataGaName":404,"dataGaLocation":386},"/de-de/partners/technology-partners/aws/","GitLab on AWS",{"text":406,"config":407},"GitLab auf Google Cloud",{"href":408,"dataGaName":409,"dataGaLocation":386},"/de-de/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":411,"config":412},"Warum GitLab?",{"href":70,"dataGaName":413,"dataGaLocation":386},"Why GitLab?",{"freeTrial":415,"mobileIcon":420,"desktopIcon":425},{"text":416,"config":417},"Kostenlos testen",{"href":418,"dataGaName":33,"dataGaLocation":419},"https://gitlab.com/-/trials/new/","nav",{"altText":421,"config":422},"GitLab-Symbol",{"src":423,"dataGaName":424,"dataGaLocation":419},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":421,"config":426},{"src":427,"dataGaName":424,"dataGaLocation":419},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"freeTrial":429,"mobileIcon":433,"desktopIcon":435},{"text":430,"config":431},"Erfahre mehr über GitLab Duo",{"href":62,"dataGaName":432,"dataGaLocation":419},"gitlab duo",{"altText":421,"config":434},{"src":423,"dataGaName":424,"dataGaLocation":419},{"altText":421,"config":436},{"src":427,"dataGaName":424,"dataGaLocation":419},"content:shared:de-de:main-navigation.yml","Main Navigation","shared/de-de/main-navigation.yml","shared/de-de/main-navigation",{"_path":442,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"title":443,"button":444,"config":449,"_id":451,"_type":14,"_source":16,"_file":452,"_stem":453,"_extension":19},"/shared/de-de/banner","GitLab Duo Agent Platform ist jetzt in öffentlicher Beta!",{"text":445,"config":446},"Beta testen",{"href":447,"dataGaName":448,"dataGaLocation":28},"/de-de/gitlab-duo/agent-platform/","duo banner",{"layout":450},"release","content:shared:de-de:banner.yml","shared/de-de/banner.yml","shared/de-de/banner",{"_path":455,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"data":456,"_id":660,"_type":14,"title":661,"_source":16,"_file":662,"_stem":663,"_extension":19},"/shared/de-de/main-footer",{"text":457,"source":458,"edit":464,"contribute":469,"config":474,"items":479,"minimal":652},"Git ist eine Marke von Software Freedom Conservancy und unsere Verwendung von „GitLab“ erfolgt unter Lizenz.",{"text":459,"config":460},"Quelltext der Seite anzeigen",{"href":461,"dataGaName":462,"dataGaLocation":463},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":465,"config":466},"Diese Seite bearbeiten",{"href":467,"dataGaName":468,"dataGaLocation":463},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":470,"config":471},"Beteilige dich",{"href":472,"dataGaName":473,"dataGaLocation":463},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":475,"facebook":476,"youtube":477,"linkedin":478},"https://x.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[480,503,558,588,622],{"title":46,"links":481,"subMenu":486},[482],{"text":483,"config":484},"DevSecOps-Plattform",{"href":55,"dataGaName":485,"dataGaLocation":463},"devsecops platform",[487],{"title":189,"links":488},[489,493,498],{"text":490,"config":491},"Tarife anzeigen",{"href":191,"dataGaName":492,"dataGaLocation":463},"view plans",{"text":494,"config":495},"Vorteile von Premium",{"href":496,"dataGaName":497,"dataGaLocation":463},"/de-de/pricing/premium/","why premium",{"text":499,"config":500},"Vorteile von Ultimate",{"href":501,"dataGaName":502,"dataGaLocation":463},"/de-de/pricing/ultimate/","why ultimate",{"title":504,"links":505},"Lösungen",[506,511,514,516,521,526,530,533,536,541,543,545,548,553],{"text":507,"config":508},"Digitale Transformation",{"href":509,"dataGaName":510,"dataGaLocation":463},"/de-de/topics/digital-transformation/","digital transformation",{"text":512,"config":513},"Sicherheit und Compliance",{"href":137,"dataGaName":138,"dataGaLocation":463},{"text":122,"config":515},{"href":105,"dataGaName":106,"dataGaLocation":463},{"text":517,"config":518},"Agile Entwicklung",{"href":519,"dataGaName":520,"dataGaLocation":463},"/de-de/solutions/agile-delivery/","agile delivery",{"text":522,"config":523},"Cloud-Transformation",{"href":524,"dataGaName":525,"dataGaLocation":463},"/de-de/topics/cloud-native/","cloud transformation",{"text":527,"config":528},"SCM",{"href":119,"dataGaName":529,"dataGaLocation":463},"source code management",{"text":109,"config":531},{"href":111,"dataGaName":532,"dataGaLocation":463},"continuous integration & delivery",{"text":161,"config":534},{"href":163,"dataGaName":535,"dataGaLocation":463},"value stream management",{"text":537,"config":538},"GitOps",{"href":539,"dataGaName":540,"dataGaLocation":463},"/de-de/solutions/gitops/","gitops",{"text":174,"config":542},{"href":176,"dataGaName":177,"dataGaLocation":463},{"text":179,"config":544},{"href":181,"dataGaName":182,"dataGaLocation":463},{"text":546,"config":547},"Öffentlicher Sektor",{"href":186,"dataGaName":187,"dataGaLocation":463},{"text":549,"config":550},"Bildungswesen",{"href":551,"dataGaName":552,"dataGaLocation":463},"/de-de/solutions/education/","education",{"text":554,"config":555},"Finanzdienstleistungen",{"href":556,"dataGaName":557,"dataGaLocation":463},"/de-de/solutions/finance/","financial services",{"title":194,"links":559},[560,562,564,566,569,571,574,576,578,580,582,584,586],{"text":206,"config":561},{"href":208,"dataGaName":209,"dataGaLocation":463},{"text":211,"config":563},{"href":213,"dataGaName":214,"dataGaLocation":463},{"text":216,"config":565},{"href":218,"dataGaName":219,"dataGaLocation":463},{"text":221,"config":567},{"href":223,"dataGaName":568,"dataGaLocation":463},"docs",{"text":244,"config":570},{"href":246,"dataGaName":247,"dataGaLocation":463},{"text":239,"config":572},{"href":573,"dataGaName":242,"dataGaLocation":463},"/customers/",{"text":249,"config":575},{"href":251,"dataGaName":252,"dataGaLocation":463},{"text":262,"config":577},{"href":264,"dataGaName":265,"dataGaLocation":463},{"text":254,"config":579},{"href":256,"dataGaName":257,"dataGaLocation":463},{"text":267,"config":581},{"href":269,"dataGaName":270,"dataGaLocation":463},{"text":272,"config":583},{"href":274,"dataGaName":275,"dataGaLocation":463},{"text":277,"config":585},{"href":279,"dataGaName":280,"dataGaLocation":463},{"text":282,"config":587},{"href":284,"dataGaName":285,"dataGaLocation":463},{"title":300,"links":589},[590,592,594,596,598,600,602,606,611,613,615,617],{"text":307,"config":591},{"href":309,"dataGaName":302,"dataGaLocation":463},{"text":312,"config":593},{"href":314,"dataGaName":315,"dataGaLocation":463},{"text":320,"config":595},{"href":322,"dataGaName":323,"dataGaLocation":463},{"text":325,"config":597},{"href":327,"dataGaName":328,"dataGaLocation":463},{"text":330,"config":599},{"href":332,"dataGaName":333,"dataGaLocation":463},{"text":335,"config":601},{"href":337,"dataGaName":338,"dataGaLocation":463},{"text":603,"config":604},"Sustainability",{"href":605,"dataGaName":603,"dataGaLocation":463},"/sustainability/",{"text":607,"config":608},"Vielfalt, Inklusion und Zugehörigkeit",{"href":609,"dataGaName":610,"dataGaLocation":463},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":340,"config":612},{"href":342,"dataGaName":343,"dataGaLocation":463},{"text":350,"config":614},{"href":352,"dataGaName":353,"dataGaLocation":463},{"text":355,"config":616},{"href":357,"dataGaName":358,"dataGaLocation":463},{"text":618,"config":619},"Transparenzerklärung zu moderner Sklaverei",{"href":620,"dataGaName":621,"dataGaLocation":463},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":623,"links":624},"Nimm Kontakt auf",[625,628,630,632,637,642,647],{"text":626,"config":627},"Sprich mit einem Experten/einer Expertin",{"href":37,"dataGaName":38,"dataGaLocation":463},{"text":369,"config":629},{"href":371,"dataGaName":372,"dataGaLocation":463},{"text":374,"config":631},{"href":376,"dataGaName":377,"dataGaLocation":463},{"text":633,"config":634},"Status",{"href":635,"dataGaName":636,"dataGaLocation":463},"https://status.gitlab.com/","status",{"text":638,"config":639},"Nutzungsbedingungen",{"href":640,"dataGaName":641,"dataGaLocation":463},"/terms/","terms of use",{"text":643,"config":644},"Datenschutzerklärung",{"href":645,"dataGaName":646,"dataGaLocation":463},"/de-de/privacy/","privacy statement",{"text":648,"config":649},"Cookie-Einstellungen",{"dataGaName":650,"dataGaLocation":463,"id":651,"isOneTrustButton":91},"cookie preferences","ot-sdk-btn",{"items":653},[654,656,658],{"text":638,"config":655},{"href":640,"dataGaName":641,"dataGaLocation":463},{"text":643,"config":657},{"href":645,"dataGaName":646,"dataGaLocation":463},{"text":648,"config":659},{"dataGaName":650,"dataGaLocation":463,"id":651,"isOneTrustButton":91},"content:shared:de-de:main-footer.yml","Main Footer","shared/de-de/main-footer.yml","shared/de-de/main-footer",{"allPosts":665,"featuredPost":853,"totalPagesCount":873,"initialPosts":874},[666,694,718,742,765,785,808,832],{"_path":667,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":668,"content":676,"config":687,"_id":690,"_type":14,"title":691,"_source":16,"_file":692,"_stem":693,"_extension":19},"/de-de/blog/ci-deployment-and-environments",{"title":669,"description":670,"ogTitle":669,"ogDescription":670,"noIndex":6,"ogImage":671,"ogUrl":672,"ogSiteName":673,"ogType":674,"canonicalUrls":672,"schema":675},"Deployment mit GitLab CI an verschiedene Umgebungen: So funktioniert es","Erfahre, wie du GitLab CI für automatische Deployments in mehrere Umgebungen einrichtest, inklusive AWS S3-Integration und sicherer Variablenverwaltung.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662033/Blog/Hero%20Images/intro.jpg","https://about.gitlab.com/blog/ci-deployment-and-environments","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Deployment mit GitLab CI an verschiedene Umgebungen: So funktioniert es\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ivan Nemytchenko\"},{\"@type\":\"Person\",\"name\":\"Cesar Saavedra\"}],\n        \"datePublished\": \"2021-02-05\",\n      }",{"title":669,"description":670,"authors":677,"heroImage":671,"date":680,"body":681,"category":682,"tags":683,"updatedDate":686},[678,679],"Ivan Nemytchenko","Cesar Saavedra","2021-02-05","In diesem ausführlichen Artikel wollen wir dir zeigen, wie du GitLab CI für eine automatisierte Kompilierung und Bereitstellung nutzen kannst. Als Ausgangspunkt haben wir das folgende Szenario gewählt: Du bist der (die) glückliche Besitzer(in), Redakteur(in) und alleinige Entwickler(in) eines imaginären Nachrichtenportals. \n\nDa du deinen Projekt-Code bereits auf GitLab.com hostest, ist dir bewusst, dass du mit GitLab [CI/CD-Tests](https://docs.gitlab.com/ee/ci/testing/) durchführen kannst. Jetzt aber möchtest du wissen, ob das Tool auch für deine [Bereitstellung](/de-de/blog/how-to-keep-up-with-ci-cd-best-practices/) verwendet werden kann - und was für Optionen dir dafür zur Verfügung stehen.\n\nUm nicht von den Details spezifischer Tech-Stacks abgelenkt zu werden, gehen wir in unserem Beispiel davon aus, dass die App nur aus HTML-Dateien besteht. Es gibt keinen serverseitigen Code, keine komplizierte Kompilierung der JavaScript-Assets.\n\nAls Zielplattform wählen wir [Amazon S3](https://aws.amazon.com/s3/) - ebenfalls eine einfache Lösung.\n\n> **Achtung:** Ziel des Artikels ist es nicht, dir möglichst viele kleinteilige Bausteine zu bieten, die du dann mit Kopieren und Einfügen in deinen Code integrierst. Vielmehr möchten wir dir die Prinzipien und Funktionalitäten von [GitLab CI](/de-de/solutions/continuous-integration/) vermitteln, so dass du sie einfacher auf deinen Tech-Stack anwenden kannst.\n\n## Inhaltsverzeichnis\n- [Der Anfang der Geschichte](#der-anfang-der-geschichte)\n- [Die erste automatisierte Bereitstellung](#die-erste-automatisierte-bereitstellung)\n  - [Wie man Geheimes geheim hält](#wie-man-geheimes-geheim-hält)\n  - [Wie du nicht geheime Variablen spezifizierst und nutzt](#wie-du-nicht-geheime-variablen-spezifizierst-und-nutzt)\n- [Wie Teams GitLab CI für die Bereitstellung nutzen können](#wie-teams-gitlab-ci-für-die-bereitstellung-nutzen-können)\n  - [Wie du einen separaten Ort für das Testen von Code einrichtest](#wie-du-einen-separaten-ort-für-das-testen-von-code-einrichtest)\n- [Einführung: Umgebungen (environments)](#einführung-umgebungen-environments)\n- [Fehlerbehebung bei der Bereitstellung](#fehlerbehebung-bei-der-bereitstellung)\n- [Slack-Benachrichtigungen für Bereitstellungen](#slack-benachrichtigungen-für-bereitstellungen)\n- [Skalierbarkeit von Teamarbeit](#skalierbarkeit-von-teamarbeit)\n  - [Wie du mit Notfällen umgehst](#wie-du-mit-notfällen-umgehst)\n  - [Es wird Zeit, Review Apps zu verwenden](#es-wird-zeit-review-apps-zu-verwenden)\n  - [Bereitstellung auf verschiedenen Plattformen](#bereitstellung-auf-verschiedenen-plattformen)\n- [Fünf Kernpunkte](#fünf-kernpunkte)\n\nLass uns ganz am Anfang beginnen. Da, wo es noch keine kontinuierliche Integration (continuous integration, CI) gibt.\n\n## Der Anfang der Geschichte\n\n**Deployment**: Was verstehen wir unter dem Begriff „Bereitstellung\"? In unserem Fall möchten wir, dass eine große Zahl an HTML-Dateien in deinem S3-Bucket - der bereits für statisches Webseiten-[Hosting](http://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html?shortFooter=true) konfiguriert wurde - erscheint.\n\nHier führen unzählige Wege nach Rom. In unserem Beispiel werden wir die [awscli](http://docs.aws.amazon.com/cli/latest/reference/s3/cp.html#examples)-Bibliothek von Amazon selbst verwenden.\n\nSo sieht der vollständige Befehl aus:\n\n```shell\naws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n![Manual deployment](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/13.jpg){: .center}\nDie Übertragung des Code mittels Push-Befehl in ein Repository und die eigentliche Bereitstellung sind zwei voneinander unabhängige Prozesse.\n{: .note .text-center}\n\nWichtiges Detail: Der [Befehl](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence) erwartet von dir, dass du `AWS_ACCESS_KEY_ID` und `AWS_SECRET_ACCESS_KEY` Umgebungs-Variablen bereitstellst. Das bedeutet, dass du gegebenenfalls die `AWS_DEFAULT_REGION` festlegen musst.\n\n{: .alert .alert-info}\n\nLass uns nun versuchen, diesen Prozess mit [GitLab CI](/de-de/solutions/continuous-integration/) zu automatisieren.\n\n## Die erste automatisierte Bereitstellung\n\nMit GitLab macht es keinen Unterschied, welche Befehle du verwendest. Du kannst GitLab so einrichten, dass es genau auf deine persönlichen Bedürfnisse zugeschnitten ist und wie ein lokales Terminal auf deinem Rechner funktioniert. \n\nSolange du von dort aus die Befehle ausführst, kannst du CI damit beauftragen, dasselbe für dich in GitLab zu tun. Platziere dein Script einfach in *.gitlab-ci.yml*,pushe deinen Code –und siehe da: CI erzeugt einen Job und führt deine Befehle aus.\n\nUm unser Ausgangsszenario ein wenig auszuschmücken, fügen wir ihm nun ein wenig Kontext hinzu: Unsere Webseite ist klein, sie hat täglich 20-30 Besucher und das Code-Repository besitzt nur einen einzigen Standard-Branch: `main`.\n\nUnser Ziel: Das Einrichten einer automatisierten Bereitstellung.\n\nLass uns damit anfangen, dass wir den oben erwähnten Befehl verwenden, um in der *.gitlab-ci.yml*\\-Datei einen Job zu spezifizieren:\n\n```yaml\ndeploy:\n  script: aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nHat leider nicht geklappt:\n![Failed command](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/fail1.png){: .shadow}\n\nEs ist unsere Aufgabe dafür zu sorgen, dass eine ausführbare `aws`\\-Datei vorliegt. Um `awscli` installieren zu können, benötigen wir `pip`, ein Tool zur Installation von Python-Paketen. Unser Vorschlag: Spezifiziere dafür ein Docker-Image mit vorinstalliertem Python. Das nämlich sollte `pip` beinhalten.\n\n```yaml\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n![Automated deployment](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/14.jpg){: .center}\nYou push your code to GitLab, and it is automatically deployed by CI.\n  {: .note .text-center}\n\nDu pushst deinen Code zu GitLab und dadurch wird dieser automatisch von CI bereitgestellt. Damit hast du dein erstes Ziel einer automatisierten Kompilierung und Bereitstellung erreicht. \n\nDie Installation von `awscli` verlängert die benötigte Zeit, den Job auszuführen. Das aber soll uns im Augenblick nicht stören. Wenn du den Prozess beschleunigen musst, kannst du jederzeit nach einem [Docker](https://hub.docker.com/explore/)-Image mit vorinstalliertem `awscli` suchen oder selbst ein solches Image erstellen.\n{: .alert .alert-warning}\n\nWir sollten außerdem die folgenden Gitlab-CI-Environment-Variablen nicht vergessen, die du dir gerade aus der [AWS](https://console.aws.amazon.com/)-Konsole gezogen hast: \n\n```yaml\nvariables:\n  AWS_ACCESS_KEY_ID: \"AKIAIOSFODNN7EXAMPLE\"\n  AWS_SECRET_ACCESS_KEY: \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\nDas sollte zwar an sich funktionieren,aber es ist dennoch eine gute Idee, geheime Schlüssel zu schützen \\- sogar in einem privaten Repository. Suchen wir also mal nach einer Lösung.\n\n### Wie man Geheimes geheim hält\n\nEs gibt in GitLab einen eigenen Ort für geheime Variablen: **Settings > CI/CD > Variables**\n\n![Picture of Variables page](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/add-variable-updated.png)\n\nAlles, was du dort ablegst, wird in GitLab-CI-Umgebungs-Variablen verwandelt.\n\nWenn du nun das Kontrollkästchen für Maskenvariablen (*mask variables*) markierst, obfuskierst du die Variablen im Job-Log. Das bedeutet, dass du den Zugriff Dritter auf diese Daten erheblich erschwerst. Als Nächstes setzt du ein Häkchen im Kontrollkästchen „Variable schützen” (*Protect variable*). Dadurch wird die entsprechende Variable nur noch über Pipelines exportiert, die auf geschützten Branches und Tags laufen. Nur Nutzer(innen) mit „Owner”- oder „Maintainer”-Status haben Zugriff auf diesen Bereich. \n\nWir könnten Umgebungs-Variablen aus unserer GitLab-CI\\-Konfiguration entfernen. Stattdessen aber wollen wir sie zu einem anderen Zweck verwenden.\n\n### Wie du nicht geheime Variablen spezifizierst und nutzt\n\nWenn deine Konfiguration wächst, kann es nützlich sein, einige der Parameter zu Beginn der Konfiguration als Variablen zu belassen. Das gilt umso mehr, wenn du sie an mehr als einer Stelle verwendest. Obwohl das in unserer Situation nicht der Fall ist, wollen wir den S3-Bucket-Namen als [**Variable**](https://docs.gitlab.com/ee/ci/variables/) verwenden, um das Prinzip zu verdeutlichen:\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nSoweit so gut:\n\n![Successful build](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/build.png){: .shadow.medium.center}\n\nIn unserem hypothetischen Szenario ist es dir gelungen, mehr Besucher auf deine Seite zu bekommen. Daher unterstützt dich jetzt  ein(e) Entwickler(in).\n\nWerfen wir deswegen einen Blick darauf, wie Teamarbeit den GitLab-CI-Workflow verändert.\n\n## Wie Teams GitLab CI für die Bereitstellung nutzen können\n\nDa nun zwei Mitarbeiter(innen) am gleichen Repository arbeiten, ist es nicht mehr sinnvoll, die `main`\\-Branch für die Bereitstellung zu nutzen. Deswegen entscheidest du dich dafür, zwei separate Branches zu erzeugen: Eines für neue Features und das andere für neue Artikel. Am Endes willst du beide dann in `main` zusammenführen. \n\nDabei gibt es aber leider ein Problem – deine aktuelle CI-Konfiguration interessiert sich nicht für Branches. Sobald du etwas zu GitLab pushst, wird es auch für S3 bereitgestellt. \n\nZum Glück lässt sich dieses Problem recht einfach beheben. Füge lediglich `only: main` zu deinem `deploy`\\-Job hinzu.\n\n![Automated deployment of main branch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/15-updated.png){: .center}\nDu willst deiner Produktions-Website zwar nicht jede Branch hinzufügen, aber es wäre durchaus gut, wenn du dir deine Änderungen an Feature-Branches per Vorschau ansehen könntest.\n{: .note .text-center}  \n\n### Wie du einen separaten Ort für das Testen von Code einrichtest\n\nDein Entwickler, nennen wir ihn Patrick, erinnert dich daran, dass es ein Feature namens [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/) gibt. Es scheint ideal dafür zu sein, dir eine Vorschau dessen zu bieten, woran du gerade arbeitest.\n\nUm Websites auf GitLab Pages zu [hosten](/blog/gitlab-pages-setup/), sollte deine CI-Konfiguration drei einfache Voraussetzungen erfüllen:\n\n* Der *Job* sollte als `pages` angelegt werden  \n* Es sollte einen `artifacts`\\-Bereich mit einem öffentlichen Ordner geben  \n* Du solltest alles, was du hosten willst, in den `public-`Ordner legen\n\nDie Inhalte des öffentlichen Ordners werden an folgendem Ort gehostet: `http://\u003Cusername>.gitlab.io/\u003Cprojectname>/`\n{: .alert .alert-info}\n\nNach der Anwendung der [Beispielkonfiguration für plain-html-Websites](https://gitlab.com/pages/plain-html/blob/master/.gitlab-ci.yml), sieht die vollständige CI-Konfiguration so aus:\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\nWir haben zwei Jobs spezifiziert. Ein Job stellt die Website für deine Kunden auf S3 bereit (`deploy`). Die andere (`pages`) stellt die Website auf GitLab Pages bereit. Aus diesem Grund nennen wir sie jeweils „Produktionsumgebung” und „Prüfungsumgebung” *(Staging Environment*).\n\n![Deployment to two places](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/16-updated.png){: .center}\nAlle Branches, mit Ausnahme von main, werden auf GitLab Pages bereitgestellt.\n{: .note .text-center}\n\n## Einführung: Umgebungen (environments)\n\nGitLab bietet [Support für Umgebungen](https://docs.gitlab.com/ee/ci/environments/) (einschließlich dynamischer und statischer Umgebungen). Dazu musst du lediglich die zutreffende Umgebung für den jeweiligen Deployment-Job festlegen:\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  environment: staging\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\nGitLab trackt deine CI-Bereitstellungen. So weißt du jederzeit, was aktuell auf deinen Servern bereitgestellt wird:\n\n![List of environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/envs-updated.png){: .shadow.center}\n\nGitLab bietet eine vollständige Aufzeichnung deiner Bereitstellungen für alle deine aktuellen CI-Umgebungen:\n\n![List of deployments to staging environment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/staging-env-detail-updated.png){: .shadow.center}\n\n![Environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/17-updated.png){: .center}\n\nNun, da wir alles automatisiert und eingerichtet haben, können wir uns den neuen Herausforderungen stellen, die uns erwarten.\n\n## Fehlerbehebung bei der Bereitstellung\n\nUnd da ist es schon wieder passiert: Du hast deine Feature-Branch gepusht, um sie in der „Staging-Umgebung” in der Vorschau zu sehen und nur eine Minute später hat Patrick seine Branch gepusht. Die Folge: Die Staging-Umgebung wurde mit seinem Beitrag überschrieben. Wie ärgerlich\\!\\! Das passiert heute schon zum dritten Mal\\!\n\nVorschlag: \u003Ci class=\"far fa-lightbulb\" style=\"color:#FFD900; font-size:.85em\" aria-hidden=\"true\">\u003C/i>\nWarum verwenden wir nicht Slack, um uns über CI-Bereitstellungen auf dem Laufenden zu halten? So können wir verhindern, dass wir uns bei der Bereitstellung gegenseitig in die Quere kommen.\n\n> Lerne, wie man [GitLab in Slack](https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html) integriert.\n\n## Slack-Benachrichtigungen für Bereitstellungen\n\nDas Einrichten von Slack-Benachrichtigungen ist ein recht unkomplizierter Vorgang. \n\nDer Gedanke dahinter ist, die eintreffende WebHook-URL von Slack zu nehmen …\n\n![image11](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/queue.jpg){: .center}\n\n… und sie in Settings \\> Integrations \\> Slack notifications zusammen mit deinem Slack-Benutzernamen einzutragen:\n\n![image12](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/slack-integration-arrow.png){: .center}\n\nDas einzige, worüber du auf dem Laufenden gehalten werden möchtest, sind Bereitstellungen. Deswegen kannst du die Häkchen aus allen Kontrollkästchen außer dem für „Deployment” in den obengenannten Einstellungen entfernen. Das war’s auch schon. Ab jetzt wirst du über jede erfolgte Bereitstellung informiert: \n\n![image13](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/slack.png){: .center} \n\n## Skalierbarkeit von Teamarbeit\n\nEinige Zeit später ist deine Website wirklich beliebt geworden und dein Team ist von zwei auf acht Mitarbeiter angewachsen. Diese arbeiten parallel an Entwicklungs-Jobs. So kommt es recht häufig vor, dass mehrere von ihnen aufeinander warten müssen, weil jemand gerade eine Vorschau in der Staging-Umgebung durchführt. Damit ist die Idee, jede Branch in Staging bereitzustellen, obsolet geworden.\n\n![Queue of branches for review on Staging](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/queue.jpg){: .center}\n\nEs ist an der Zeit, den Prozess ein letztes Mal zu modifizieren. Du und dein Team sind zu dem Entschluss gekommen, dass alle, die ihre Änderungen auf dem Staging-Server ansehen möchten, diese zuerst mit der Staging-Branch zusammenführen sollen. \n\nDazu bedarf es nur einer minimalen Änderung von  `.gitlab-ci.yml`:\n\n```yaml\nexcept:\n- main\n```\n\nEs wird zu:\n\n```yaml\nonly:\n- staging\n```\n\n![Staging branch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/18-updated.png){: .center}\nDie Mitarbeiter müssen nun ihre Feature-Branches zusammenführen, bevor sie diese auf dem Staging-Server als Vorschau betrachten können.\n{: .note .text-center}\n\nNatürlich erfordert dies zusätzliche Zeit und einen Mehraufwand für das Mergen. Aber alle stimmen überein, dass dies besser ist, als jedes Mal zu warten.\n\n### Wie du mit Notfällen umgehst\n\nDu kannst nicht alles kontrollieren. Manchmal geht einfach etwas schief. Nehmen wir ein Beispiel: Ein(e) Mitarbeiter(in) hat die Branches nicht korrekt zusammengeführt und das Ergebnis direkt in die Produktions-Umgebung gepusht \\- genau zu einem Zeitpunkt, als deine Website bei HackerNews ganz oben stand\\! Tausende Besucher haben so dein komplett zerschossenes Layout gesehen, statt deiner eigentlich so schönen Main-Page. \n\nZum Glück hat ein Team-Mitglied den **Rollback-Button** entdeckt. Damit konntest du die Website bereits eine Minute, nachdem das Problem entdeckt wurde, auf den alten Stand zurücksetzen.\n\n![List of environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/prod-env-rollback-arrow-updated.png){: .shadow.center}\nDer Rollback-Button erlaubt es, eine Webseite schnell auf den Ursprungszustand zurückzusetzen. \n{: .note .text-center}\n\nRollback führt alles zu dem alten Job mit dem vorigen commit zurück. \n\nTrotzdem stellt dich diese Lösung des Problems noch nicht zufrieden. Du entschließt dich, die automatische Bereitstellung in die Produktions-Umgebung auszuschalten und stattdessen zum manuellen CI-Deployment zurückzukehren. Dazu fügst du deinem Job `when: manual` hinzu.\n\nWie du bereits erwartet hast, erfolgen ab jetzt keine automatischen Bereitstellungen in die Produktion mehr. Um eine manuelle Bereitstellung durchzuführen, gehe zu **CI/CD \\> Pipelines**, und klicke auf den Button:\n\n![Skipped job is available for manual launch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/manual-pipeline-arrow-updated.png){: .shadow.center}\n\nSpringen wir nun in die Zukunft. Endlich ist dein Unternehmen zu einer Aktiengesellschaft herangewachsen. Inzwischen arbeiten hunderte Mitarbeiter(innen) an der Website. Das bedeutet, dass die Kompromisse aus der Vergangenheit nicht mehr praxistauglich sind.\n\n### Es wird Zeit, Review Apps zu verwenden\n\nDer nächste logische Schritt besteht darin, ein temporäres Objekt der Applikation über die Feature-Branch zum Prüfen zu booten. \n\nIn unserem Fall richten wir dazu einen weiteren S3-Bucket ein. Der einzige Unterschied besteht darin, dass wir die Inhalte unserer Website in einen „Ordner” mit dem Namen der Entwicklungs-Branch kopieren. Nun sieht die URL so aus:\n\n`http://\u003CREVIEW_S3_BUCKET_NAME>.s3-website-us-east-1.amazonaws.com/\u003Cbranchname>/`\n\nHier ist der Ersatz für den `pages`\\-Job, den wir zuvor benutzt haben:\n\n```yaml\nreview apps:\n  variables:\n    S3_BUCKET_NAME: \"reviewbucket\"\n  image: python:latest\n  environment: review\n  script:\n  - pip install awscli\n  - mkdir -p ./$CI_BUILD_REF_NAME\n  - cp ./*.html ./$CI_BUILD_REF_NAME/\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nEs ist interessant zu hinterfragen, woher wir diese `$CI_BUILD_REF_NAME`\\-Variable bekommen haben. GitLab CI definiert viele [Umgebungs-Variablen](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) vor, so dass du sie direkt in deinen Jobs verwenden kannst. \n\nBeachte, dass wir die `S3_BUCKET_NAME`\\-Variable im Job definiert haben. Damit kannst du Definitionen auf höchstem Level umschreiben.\n{: .alert .alert-info}\n\nHier ist eine visuelle Darstellung dieser Konfiguration:\n![Review apps]![How to use GitLab CI - update - 19 - updated](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/19-updated.png){: .illustration}\n\nWie genau die Review Apps implementiert werden, hängt von einer Vielzahl Faktoren ab, darunter dein Tech-Stack und dein Bereitstellungs-Prozess. Das ist sehr komplex und deswegen wollen wir in diesem Blogpost nicht näher darauf eingehen. \n\nImmerhin können wir mit Gewissheit behaupten, dass der Prozess sich nicht mehr ganz so einfach darstellen wird wie noch bei unserer statischen html-Website. An dieser Stelle sei nur ein Beispiel genannt: Du musst diese Objekte temporär anlegen. Wenn du sie nun mit der gesamten benötigten Software und allen Diensten automatisch hochfahren möchtest, ist das keine triviale Angelegenheit mehr. Dennoch ist es machbar, vor allem, wenn du Docker-Container verwendest \\- oder zumindest *Chef* oder *Ansible*. \n\nWir werden uns mit Docker-Bereitstellungen in einem zukünftigen Blogpost beschäftigen. Ich fühle mich ehrlich gesagt ein wenig schuldig, dass ich mich bei der Diskussion des Bereitstellungs-Prozesses nur auf das einfache Kopieren von html-Dateien beschränke und kein einziges wirklich anspruchsvolles Szenario durchgehe. Wenn du dringend mehr Informationen in diese Richtung benötigst, empfehle ich dir den englischsprachigen Artikel „[Building an Elixir Release into a Docker image using GitLab CI.](https://about.gitlab.com/blog/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/)\"\n\nIn diesem Artikel aber möchte ich nur noch einen letzten Punkt behandeln.\n\n### Bereitstellung auf verschiedenen Plattformen\n\nIm echten Leben müssen wir uns nicht auf S3 und GitLab Pages beschränken. Wir hosten unsere Apps und Pakete auf verschiedenen Diensten \\- gleiches gilt somit auch für unsere CI-Bereitstellungen. \n\nDarüber hinaus kann auch der Fall eintreten, dass du dich dazu entschließt, auf eine neue Plattform zu migrieren. In dem Fall müsstest du alle deine Bereitstellungs-Skripte neu schreiben. Um den Aufwand zu minimieren, kannst du ein ungemein wertvolles Tool namens `dpl` benutzen. \n\nIn den Beispielen oben haben wir `awscli` verwendet, um den Code an einen Beispiel-Dienst zu liefern (in unserem Fall Amazon S3). Unabhängig davon aber, welches Tool und welches Zielsystem du verwendest, bleibt das Prinzip dasselbe: Du führst einen Befehl mit bestimmten Parametern aus und identifizierst dich mit einem geheimen Schlüssel. \n\nDas `dpl`\\-Bereitstellungs-Tool nutzt dieses Prinzip und bietet ein einheitliches Interface für diese [Liste von Providern](https://github.com/travis-ci/dpl#supported-providers) an. \n\nSo sähe ein Produktions-Bereitstellungs-Job aus, wenn wir `dpl` nutzen:\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: ruby:latest\n  script:\n  - gem install dpl\n  - dpl --provider=s3 --bucket=$S3_BUCKET_NAME\n  only:\n  - main\n```\n\nWenn du an verschiedene Systeme bereitstellen möchtest oder öfter die Ziel-Plattform änderst, ergibt es Sinn, über die Nutzung von `dpl` nachzudenken, um deine Bereitstellungs-Skripte einheitlich zu halten.\n\n## Fünf Kernpunkte\n\n1. Eine Bereitstellung ist nichts weiter als ein Befehl (oder eine Kombination von Befehlen), die regelmäßig ausgeführt werden. Deswegen kannst du Bereitstellungen über GitLab CI laufen lassen. \n\n2. In den meisten Fällen wirst du einen oder mehrere geheime Schlüssel verwenden müssen, um die Befehle ausführen zu können. Speichere diese geheimen Schlüssel in **Settings \\> CI/CD \\> Variables**.\t\n\n3. Mit GitLab CI kannst du flexibel spezifizieren, an welche Branches du deployen willst.  \t\n\n4. Wenn du Bereitstellungen an verschiedene CI-Umgebungen durchführen möchtest, speichert GitLab die Bereitstellungen. Das erlaubt es dir, einen Rollback zu einer früheren Version durchzuführen.  \n\n5. Für kritische Aspekte deiner Infrastruktur kannst du statt der automatischen Bereitstellung auf eine manuelle umstellen.\n\n\u003Cstyle>\n\nimg.illustration {\n  padding-left: 12%;\n  padding-right: 12%;\n\n}\n@media (max-width: 760px) {\n  img.illustration {\n    padding-left: 0px;\n    padding-right: 0px;\n  }\n}\n\u003C/style>","engineering",[9,684,685],"CD","tutorial","2025-05-16",{"slug":688,"featured":6,"template":689},"ci-deployment-and-environments","BlogPost","content:de-de:blog:ci-deployment-and-environments.yml","Ci Deployment And Environments","de-de/blog/ci-deployment-and-environments.yml","de-de/blog/ci-deployment-and-environments",{"_path":695,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":696,"content":702,"config":712,"_id":714,"_type":14,"title":715,"_source":16,"_file":716,"_stem":717,"_extension":19},"/de-de/blog/demystifying-ci-cd-variables",{"ogTitle":697,"schema":698,"ogImage":699,"ogDescription":700,"ogSiteName":673,"noIndex":6,"ogType":674,"ogUrl":701,"title":697,"canonicalUrls":701,"description":700},"GitLab Umgebungsvariablen einfach erklärt ","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab-Umgebungsvariablen entmystifiziert\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Veethika Mishra\"}],\n        \"datePublished\": \"2021-04-09\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664679/Blog/Hero%20Images/blog-image-template-1800x945__24_.png","Wir zeigen dir, was sich hinter Umgebungsvariablen bei GitLab verbirgt. ✓ Definition ✓ Funktionsweise ✓ Typen ✓ Anwendung ➤ Jetzt Leitfaden lesen!","https://about.gitlab.com/blog/demystifying-ci-cd-variables",{"heroImage":699,"body":703,"authors":704,"updatedDate":706,"date":707,"title":697,"tags":708,"description":711,"category":682},"Es gibt viel Flexibilität bei der Definition und Verwendung von Variablen\nfür [CI/CD](https://about.gitlab.com/de-de/topics/ci-cd/). Variablen sind\nsehr nützlich für die Steuerung von Jobs und Pipelines und sie helfen dir zu\nvermeiden, Werte in der Konfigurationsdatei `.gitlab-ci.yml` festlegen zu\nmüssen. Dieser Blogbeitrag soll ein umfassenderes Bild vermitteln, indem er\nalle (oder die meisten) Informationen über die Definition und die Handhabung\nder Variablen zusammenfasst, um das Verständnis des Geltungsbereichs und der\nMöglichkeiten zu erleichtern. Die relevante Dokumentation in dem Beitrag\nverlinkt und ist aktuell nur in englischer Sprache verfügbar.\n\n\nIn [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) können mit Variablen Werte definiert und gespeichert werden, um Jobs anzupassen. Bei der Verwendung von Variablen müssen Werte nicht im Klartext gespeichert werden. In GitLab können CI/CD-Variablen unter **Einstellungen >> CI/CD >> Variablen** oder einfach in der Datei `.gitlab-ci.yml` definiert werden.\n\n\nVariablen sind nützlich, um Dienste von Drittanbietern für verschiedene Bereitstellungsumgebungen zu konfigurieren, z. B. `testing`, `staging`, `production` usw. Passe an, welche Dienste mit diesen Umgebungen verknüpft sind, indem du einfach die Variable änderst, die auf den API-Endpunkt zeigt, den die Dienste verwenden sollen. Verwende auch Variablen, um Jobs zu konfigurieren, und stelle sie dann als Umgebungsvariablen innerhalb der Jobs zur Verfügung, wenn diese ausgeführt werde.\n\n\n![GitLab liest die Datei .gitlab-ci.yml, um die referenzierte Variable zu scannen und sendet die Informationen an den GitLab Runner. Die Variablen werden auf dem Runner angezeigt und vom Runner ausgegeben.](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_processing.jpeg)\n\n\n## Die Beziehung zwischen Variablen und Umgebungen\n\n\nDer Prozess der Softwareentwicklung umfasst verschiedene Phasen, in denen ein Produkt getestet wird, bevor es an die Benutzer(innen) ausgeliefert wird. Zur Definition dieser Phasen werden [Umgebungen](https://docs.gitlab.com/ee/ci/environments/) verwendet, die von Team zu Team und zwischen Unternehmen unterschiedlich sein können.\n\n\nVariablen sind dagegen Datenwerte, die sich durch die Interaktion der Benutzer(innen) mit dem Produkt ändern können. Beispielsweise kann ihr Alter, ihre Vorlieben oder eine beliebige andere Eingabe den nächsten Schritt in der Aufgabenfolge des Produkts bestimmen.\n\n\nWir hören oft den Begriff [Umgebungsvariable](https://docs.gitlab.com/ee/administration/environment_variables.html). Dabei handelt es sich um Variablen, die in einer bestimmten Umgebung, aber außerhalb der Anwendung definiert sind. CI/CD-Variablen von GitLab bieten Entwickler(inne)n die Möglichkeit, Werte in ihrem Code zu konfigurieren. Variablen sind hilfreich, da sie sicherstellen, dass der Code flexibel ist. Mit CI/CD-Variablen von GitLab können Beutzer(innen) eine in einer bestimmten Umgebung bereitgestellte Anwendung ändern, ohne den Code zu ändern. Es ist einfach, Tests durchzuführen oder sogar Dienste von Drittanbietern zu integrieren, indem eine Umgebungsvariable außerhalb der Anwendung geändert wird.\n\n\n## Geltungsbereich der Variablen für CI/CD\n\n\n![Hierarchie für CI/CD-Variablen: 1) Variablen für die manuelle Ausführung, Auslösung und Planung von Pipelines, 2) Geschützte Variablen auf Projekt-, Gruppen- und Instanzebene, 3) Geerbte CI/CD-Variablen, 4) Job-Ebene, globale yml-definierte Variablen, 5) Bereitstellungsvariablen, 6) Vordefinierte CI/CD-Variablen](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_precedence.jpeg)\n\n\n### `.gitlab-ci.yml`-definierte Variablen\n\n\nVariablen, die in der Arbeitsumgebung verfügbar sein müssen, können zu GitLab hinzugefügt werden. Diese CI/CD-Variablen sind dazu gedacht, nicht-sensible Projektkonfigurationen wie z. B. die URL der Datenbank in der Datei `.gitlab-ci.yml` zu speichern. Verwende diese Variable in mehreren Jobs oder Skripten, wo immer der Wert benötigt wird. Wenn sich der Wert ändert, musst du die Variable nur einmal aktualisieren und die Änderung wird überall dort übernommen, wo die Variable verwendet wird.\n\n\n### Projekt-CI/CD-Variablen\n\n\nEinen Schritt über die Repository-spezifischen Anforderungen hinaus kannst du CI/CD-Variablen in den [Projekt-Einstellungen](https://docs.gitlab.com/ee/ci/variables/#for-a-project) definieren und für CI/CD-Pipelines verfügbar machen. Diese werden aus dem Repository heraus gespeichert (nicht in der Datei `.gitlab-ci.yml`), sind aber weiterhin in der CI/CD-Konfiguration und den Skripten verfügbar. Durch das Speichern der Variablen außerhalb der Datei `.gitlab-ci.yml` werden diese Werte auf einen reinen Projektgeltungsbereich beschränkt und nicht als Klartext im Projekt gespeichert.\n\n\n### CI/CD-Variablen für Gruppen und Instanzen\n\n\nEinige Variablen sind auf Gruppen- oder sogar Instanzebene relevant und können für alle Projekte in einer Gruppe oder Instanz nützlich sein. Definiere die Variablen in den [Gruppen- oder Instanzeinstellungen](https://docs.gitlab.com/ee/ci/variables/#for-a-group), sodass alle Projekte innerhalb dieser Bereiche die Variablen verwenden können, ohne den Wert zu kennen oder die Variablen für den untergeordneten Bereich erstellen zu müssen. Zum Beispiel kann ein gemeinsamer Wert, der in mehreren Projekten aktualisiert werden muss, leicht verwaltet werden, wenn er an einer einzigen Stelle aktualisiert wird. Alternativ können mehrere Projekte ein bestimmtes Passwort verwenden, ohne den Wert des Passworts selbst kennen zu müssen.\n\n\n## Jobs und Pipelines als Umgebungen\n\n\nDie CI/CD-Variablen von GitLab werden nicht nur als Umgebungsvariablen verwendet, sondern auch in der Konfigurationsdatei `.gitlab-ci.yml`, um das Verhalten der Pipeline unabhängig von der Umgebung zu konfigurieren. Die Variablen können in den Projekt-/Gruppen-/Instanzeinstellungen gespeichert und Jobs in Pipelines zur Verfügung gestellt werden.\n\n\nZum Beispiel:\n\n\n```  \n\njob:  \n  rules:  \n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH  \n  script:  \n  - echo \"This job ran on the $CI_COMMIT_BRANCH branch.\"  \n```\n\n\nDie Variable `($CI_COMMIT_BRANCH)` im Skriptabschnitt wird in dem Bereich des Jobs ausgeführt, in dem sie definiert wurde. Dieser Bereich ist die „Job-Umgebung“ – das heißt, wenn der Job gestartet wird, startet der GitLab-Runner einen Docker-Container und führt den Job in dieser Umgebung aus. Der Runner stellt diese Variable (und alle anderen vordefinierten oder benutzerdefinierten Variablen) dem Job zur Verfügung und kann ihren Wert bei Bedarf in der Protokollausgabe anzeigen.\n\n\nDie Variable wird jedoch **auch** im Abschnitt `if:` verwendet, um zu bestimmen, wann der Job ausgeführt werden soll. Dies ist an sich keine Umgebung, weshalb wir diese CI/CD-Variablen aufrufen. Sie können verwendet werden, um CI/CD-Jobs dynamisch zu konfigurieren, **sowie** als Umgebungsvariablen, wenn der Job ausgeführt wird.\n\n\n## Vordefinierte Variablen\n\n\nEine Reihe von Variablen werden [vordefiniert](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html), wenn eine GitLab-CI/CD-Pipeline gestartet wird. Benutzer(innen) können sofort auf Werte für Commit-, Projekt- oder Pipeline-Details zugreifen, ohne die Variablen selbst definieren zu müssen.\n\n\n## Benutzerdefinierte CI/CD-Variablen\n\n\n![Runner können zwei Arten von benutzerdefinierten CI/CD-Variablen erstellen: Typ und Datei.](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variable_types.jpeg)\n\n\nWenn eine CI/CD-Variable in den Einstellungen erstellt wird, gibt GitLab den Benutzer(innen) mehr Konfigurationsmöglichkeiten für die Variable. Verwende diese zusätzlichen Konfigurationsoptionen für eine strengere Kontrolle sensibler Variablen:\n\n\n**Geltungsbereich: Umgebung:** Wenn eine Variable nur in einer bestimmten Umgebung verwendet werden soll, konfiguriere sie so, dass sie nur in dieser Umgebung verfügbar ist. Du kannst beispielsweise festlegen, dass ein Bereitstellungstoken nur in der Umgebung `production` verfügbar ist.\n\n\n**Geschützte Variablen:** Ähnlich wie bei der Option „Geltungsbereich: Umgebung“ kann eine Variable so konfiguriert werden, dass sie nur verfügbar ist, wenn die Pipeline in einem geschützten Branch ausgeführt wird, z. B. in deinem Standard-Branch.\n\n\n**Variablentyp:** Für einige Anwendungen musst du die Konfiguration in Form einer Datei übergeben. Wenn du eine Anwendung hast, die diese Konfiguration erfordert, lege den Variablentyp einfach auf „Datei“ fest. Wenn die CI/CD-Variable auf diese Weise konfiguriert wird, schreibt der Runner die Variable in eine temporäre Datei und speichert den Pfad zu dieser Datei als Wert, wenn er sie in der Umgebung verfügbar macht. Als Nächstes können die Benutzer(innen) den Pfad zu der Datei an alle Anwendungen weitergeben, die sie benötigen.\n\n\nZusätzlich zu den genannten Methoden zur Definition und Verwendung von Variablen hat GitLab eine Funktion eingeführt, die vorgefertigte Variablen generiert, wenn eine Pipeline manuell ausgeführt werden muss. Vorgefertigte Variablen reduzieren die Fehlerwahrscheinlichkeit und erleichtern die Bedienung der Pipeline.\n\n\n**Maskierte Variablen:** [Maskierte Variablen](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable) sind CI-Variablen, die in Job-Protokollen **maskiert** wurden, um zu verhindern, dass der Wert der Variablen angezeigt wird. \n\n\n**Maskierte und versteckte Variablen:** Die in [GitLab 17.4](https://about.gitlab.com/releases/2024/09/19/gitlab-17-4-released/#hide-cicd-variable-values-in-the-ui) eingeführten [maskierten und versteckten Variablen](https://docs.gitlab.com/ee/ci/variables/#hide-a-cicd-variable) bieten die gleiche Maskierungsfunktion für Job-Protokolle und **verstecken den Wert** **in der Einstellungsoberfläche**. Wir empfehlen, keine dieser Variablen für sensible Daten (z. B. Geheimnisse) zu verwenden, da diese versehentlich offengelegt werden könnten.\n\n\n## Geheimnisse\n\n\nGeheimnisse sind sensible Zugangsdaten, die vertraulich behandelt werden sollten. Beispiele für Geheimnisse sind\n\n\n* Passwörter  \n\n* SSH-Schlüssel  \n\n* Zugriffstoken  \n\n* Alle anderen Arten von Zugangsdaten, deren Offenlegung für ein Unternehmen schädlich wäre.\n\n\nGitLab ermöglicht es seinen Benutzer(innen) derzeit mit Hilfe von HashiCorp Vault, Google Cloud Secret Manager und Azure Key Vault, [externe Geheimnisse für CI zu verwenden](https://docs.gitlab.com/ee/ci/secrets/), um Schlüssel, Token und andere Geheimnisse auf Projektebene sicher zu verwalten. So können Benutzer(innen) diese Geheimnisse aus Sicherheitsgründen von anderen CI/CD-Variablen trennen.\n\n\n### GitLab Geheimnismanager\n\n\nNeben der Unterstützung für externe Geheimnisse in CI arbeitet GitLab auch an der Einführung einer [nativen Lösung zur Verwaltung von Geheimnissen](https://gitlab.com/groups/gitlab-org/-/epics/10108), um Geheimnisse sicher und bequem in GitLab zu speichern. Diese Lösung wird Kund(inn)en auch dabei helfen, gespeicherte Geheimnisse in GitLab-spezifischen Komponenten und Umgebungen zu verwenden und den Zugriff auf Namensraum-Gruppen und Projektebene einfach zu verwalten. \n\n\n## Mehr lesen\n\n* [Nativer GitLab Geheimnismanager für mehr Sicherheit in der Software-Lieferkette](https://about.gitlab.com/blog/gitlab-native-secrets-manager-to-give-software-supply-chain-security-a-boost/) (nur in englischer Sprache verfügbar)\n\n\n***Haftungsausschlussklausel:** Dieser Blog enthält Informationen über kommende Produkte, Funktionen oder Funktionalitäten. Bitte beachte, dass die Informationen in diesem Blogbeitrag nur zu Informationszwecken dienen. Bitte verlasse dich nicht auf diese Informationen, wenn du etwas kaufen oder planen möchtest. Wie bei allen Projekten können sich die in diesem Blog und auf den verlinkten Seiten genannten Punkte ändern oder verzögern. Die Entwicklung, Freigabe und der Zeitplan von Produkten, Funktionen oder Funktionalitäten liegen im alleinigen Ermessen von GitLab.*\n",[705],"Veethika Mishra","2025-01-28","2021-04-09",[684,709,710,9,109,685],"features","inside GitLab","CI/CD-Variablen sind nützliche (und flexible) Tools zur Steuerung von Jobs und Pipelines. Wir verraten dir alles, was du über GitLab-Umgebungsvariablen wissen musst.",{"slug":713,"featured":6,"template":689},"demystifying-ci-cd-variables","content:de-de:blog:demystifying-ci-cd-variables.yml","Demystifying Ci Cd Variables","de-de/blog/demystifying-ci-cd-variables.yml","de-de/blog/demystifying-ci-cd-variables",{"_path":719,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":720,"content":727,"config":736,"_id":738,"_type":14,"title":739,"_source":16,"_file":740,"_stem":741,"_extension":19},"/de-de/blog/ensuring-compliance",{"title":721,"description":722,"ogTitle":721,"ogDescription":722,"noIndex":6,"ogImage":723,"ogUrl":724,"ogSiteName":673,"ogType":725,"canonicalUrls":724,"schema":726},"Mit GitLab Aufgabentrennung und Compliance sicherstellen","Nutze deine DevSecOps-Plattform, um die Compliance aufrechtzuerhalten, ohne die Entwicklungsgeschwindigkeit zu beeinträchtigen.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098232/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_479904468%20%281%29_4lmOEVlaXP0YC3hSFmOw6i_1750098232241.jpg","https://about.gitlab.com/blog/ensuring-compliance","Artikel","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Artikel\",\n        \"headline\": \"Mit GitLab Aufgabentrennung und Compliance sicherstellen\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Beatriz Barbosa\"},{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2022-04-04\",\n      }",{"title":721,"description":722,"authors":728,"heroImage":723,"date":731,"body":732,"category":733,"tags":734,"updatedDate":735},[729,730],"Beatriz Barbosa","Fernando Diaz","2022-04-04","In diesem Artikel erfährst du, wie du mit der DevSecOps-Plattform von GitLab die **Aufgabentrennung** und\n\ndie **kontinuierliche Compliance** sicherstellen kannst. Zunächst möchten wir jedoch zwei Schlüsselkonzepte klären:\n\n\n**Compliance** bedeutet, dass du die Richtlinien und Spezifikationen einhältst,\n\ndie entweder von deinem Unternehmen oder von einer Aufsichtsbehörde festgelegt wurden. Compliance trägt dazu bei, die\n\nUnternehmensethik, angemessene Benutzerrichtlinien, Sicherheitsstandards und vieles mehr für\n\ndie Sicherheit der Verbraucher(innen) aufrechtzuerhalten.\n\n\nDie Nichteinhaltung kann zu einer Reihe von Gerichts- und Anwaltskosten sowie Geldstrafen führen, daher ist es sehr wichtig, die Compliance aufrechtzuerhalten. DevSecOps-Teams müssen nicht nur die Compliance gewährleisten, sondern auch eine nachhaltige Entwicklungsgeschwindigkeit sicherstellen und die notwendige Einfachheit, Transparenz und Kontrolle bieten.\n\n\nDie **Aufgabentrennung** erfordert, dass mehrere Personen eine Aufgabe ausführen, um den Schutz vor Fehlern zu erhöhen und böswillige Aktivitäten zu verhindern. Die Aufgabentrennung stellt sicher, dass nur die Rollen, die für die Aufgabe am besten geeignet sind, diese auch ausführen können. Als Beispiel werden einige der folgenden\n\nAkteure und Akteurinnen betrachtet, die jeweils einen bestimmten Zweck erfüllen:\n\n\n- Ein(e) Entwickler(in) ist für die Entwicklung neuer Funktionen verantwortlich.\n\n-Ein(e) Beauftragte(r) für Compliance ist für die Erstellung und Durchsetzung der Nutzung einer Pipeline zuständig.\n\n- Ein(e) Anwendungssicherheitsingenieur(in) ist für die Genehmigung von Merge Requests mit Sicherheitslücken verantwortlich.\n\n\nUnter Berücksichtigung der oben genannten Rollen können wir sicherstellen, dass ein(e) Entwickler(in) eine laufende Pipeline nicht ändern kann.\n\nDiese Aufgabe kann nur von Beauftragten für Compliance durchgeführt werden, um sicherzustellen, dass nur konformer Code ohne Genehmigung gepusht werden kann.\n\n\nEin(e) Anwendungssicherheitsingenieur(in) ist dafür zuständig, Code mit Sicherheitslücken zu überprüfen und zu genehmigen, um sicherzustellen, dass eine ordnungsgemäße Risikominderung durchgeführt werden kann und in Zukunft keine Überraschungen mehr auftreten. In diesem Szenario können Entwickler(innen) Code erst dann zusammenführen, wenn die Compliance-\n\nund Sicherheitsanforderungen erfüllt sind.\n\n\n## Sicherheitsrichtlinien\n\nGitLab bietet **Sicherheitsrichtlinien**, die es Sicherheitsteams ermöglichen, die Ausführung von Sicherheitsscans gemäß einer Konfiguration zu fordern. So können Sicherheitsteams darauf vertrauen, dass die konfigurierten Scans nicht geändert oder deaktiviert wurden.\n\n\nSicherheitsrichtlinien können so festgelegt werden, dass sie bestimmte **Compliance Frameworks** erfüllen. Dies bedeutet, dass dein Projekt bestimmte Compliance-Anforderungen hat und zusätzliche Überwachung benötigt. Dieses Label kann unter **Sichern > Compliance Center > Frameworks** in deiner Hauptgruppe erstellt werden.\n\n\n![Compliance-Framework-Label (nur in englischer Sprache verfügbar)](https://about.gitlab.com/images/blogimages/compliance-04-2022/cf-step-2.png)\n\n\n**Hinweis:** Compliance-Label können nur Projekten innerhalb der Hauptgruppe zugewiesen werden, in der das Label erstellt wird.\n\n\nEs gibt drei Arten von Richtlinien (nur in englischer Sprache verfügbar): [Scan-Ausführungsrichtlinien](https://docs.gitlab.com/ee/user/application_security/policies/scan_execution_policies.html), [Merge-Request-Approvalrichtlinien](https://docs.gitlab.com/ee/user/application_security/policies/merge_request_approval_policies.html) und [Pipeline-Ausführungsrichtlinien](https://docs.gitlab.com/ee/user/application_security/policies/pipeline_execution_policies.html).\n\n\n* **Scan-Ausführungsrichtlinien:** Hier kannst du festlegen, dass Sicherheitsscans nach einem bestimmten Zeitplan oder zusammen mit der Projektpipeline ausgeführt werden.\n\n* **Merge-Request-Approvalrichtlinien:** Ergreife Maßnahmen auf der Grundlage von Scan-Ergebnissen, z. B. die Genehmigung durch das Sicherheitsteam, bevor ein Merge durchgeführt werden kann.\n\n* **Pipeline-Ausführungsrichtlinien:** Erzwinge CI/CD-Jobs für entsprechende Projekte.\n\n\nDiese Richtlinien können über den Richtlinien-Editor in wenigen einfachen Schritten konfiguriert werden.\n\n\n### Scan-Ausführung\n\n\n1. Gehe zu **Sicherheit & Compliance > Richtlinien**.\n\n\n2. Erstelle eine neue Richtlinie, indem du auf die Schaltfläche **Neue Richtlinie** klickst.\n\n\n3. Wähle **Scan-Ausführung** aus.\n\n\n4. Erstelle die Regel. Ich erstelle eine Regel, die erfordert, dass [SAST (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/user/application_security/sast/) konfiguriert ist, damit eine Pipeline ausgeführt werden kann.\n\n\n```yaml\n\nname: force_sast\n\ndescription: 'require sast to run'\n\nenabled: true\n\nrules:\n\n- type: pipeline branches: - main actions:\n\n- scan: sast\n\n```\n\n\n5. Reiche die Richtlinie ein, indem du einen Merge Request erstellst und dann den Merge ausführst.\n\n\nAlle Änderungen der Scan-Ausführungsrichtlinie werden über einen Hintergrundjob angewendet, der alle 10 Minuten ausgeführt wird.\n\nWarte bis zu 10 Minuten, bis alle für dieses Projekt festgelegten Richtlinienänderungen wirksam werden.\n\n\n6. Versuche, eine Pipeline auszuführen. Sie wird nur ausgeführt, wenn SAST in der YAML definiert ist.\n\n\n**Hinweis**: Du kannst SAST auch so einstellen, dass es nach einem Timer ausgeführt wird. Weitere Informationen findest du in der [Dokumentation (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/user/application_security/policies/scan-execution-policies.html) zu den\n\nScan-Ausführungsrichtlinien.\n\n\n### Merge-Request-Approval\n\n\n1. Gehe zu **Sichern > Richtlinien**.\n\n\n2. Erstelle eine neue Richtlinie, indem du auf die Schaltfläche **Neue Richtlinie** klickst.\n\n\n3. Wähle **Merge-Request-Approvalrichtlinien** aus.\n\n\n4. Definiere den Geltungsbereich der Richtlinie.\n\n\n5. Erstelle die Regel.\n\n\n![Aktualisierung der Aufgabentrennung – Bild 1 (nur in englischer Sprache verfügbar)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098241214.png)\n\n\n6. Füge die auszuführende Aktion hinzu.\n\n\n![Aktualisierung der Aufgabentrennung – Bild 2 (nur in englischer Sprache verfügbar)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098241215.png)\n\n\n**Hinweis:** Die Richtlinie wird gemäß den von dir festgelegten Regeln ausgewertet. Das bedeutet, dass eine Genehmigung erforderlich ist, wenn die Regeln ungültig sind oder nicht ausgewertet werden können. Um dies zu verhindern, kann das Feld für das Standard-Fallback-Verhalten auf `offen` geändert werden.\n\n\n![Aktualisierung der Aufgabentrennung – Bild 3 (nur in englischer Sprache verfügbar)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750098241217.png)\n\n\n1. Reiche die Richtlinie ein, indem du einen Merge Request erstellst und dann den Merge ausführst.\n\n\n2. Erstelle einen separaten Merge Request mit Sicherheitslücken.\n\n\nWie du Sicherheitslücken hinzufügen kannst, erfährst du im Abschnitt „Entwickler-Workflow“ des DevSecOps-Workshops von GitLab.\n\n\n3. Überprüfe, ob die Merge-Request-Approvalrichtlinien angewendet werden, indem du den Merge Request anzeigst.\n\n\n### Pipeline-Ausführungsrichtlinie\n\n\nUm eine Pipeline-Ausführungsrichtlinie einzurichten, musst du zunächst ein Projekt erstellen, das die CI-Dateien enthält, die du ausführen möchtest. Stelle sicher, dass nur das Sicherheitsteam und/oder der bzw. die Administrator(in) Zugriff haben, um die Aufgabentrennung zu gewährleisten. Ich habe das Projekt „Compliance und Bereitstellung“ erstellt, das die YAML enthält, die ich durchsetzen möchte.\n\n\n1. Gehe zu **Sichern > Richtlinien**.\n\n\n2. Erstelle eine neue Richtlinie, indem du auf die Schaltfläche **Neue Richtlinie** klickst.\n\n\n3. Wähle **Pipeline-Ausführungsrichtlinie** aus.\n\n\n4. Definiere den Geltungsbereich der Richtlinie.\n\n\n5. Füge die auszuführende Aktion hinzu.\n\n\n![Aktualisierung der Aufgabentrennung – Bild 4 (nur in englischer Sprache verfügbar)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image8_aHR0cHM6_1750098241219.png)\n\n\n6. Füge Bedingungen hinzu.\n\n\n7. Reiche die Richtlinie ein, indem du einen Merge Request erstellst und dann den Merge ausführst.\n\n\n8. Versuche, eine Pipeline auszuführen. Du siehst die richtlinienspezifischen Jobs und Phasen in deiner Pipeline.\n\n\n## Auditmanagement und Compliance-Dashboard\n\n\nEin weiterer wichtiger Teil der Compliance ist das Wissen, dass sie in deinen Gruppen/Projekten tatsächlich stattfindet. GitLab verfügt über Audit-Ereignisse und Konformitätsberichte, die dich bei Audits unterstützen.\n\n\nMit **Audit Events** können GitLab-Eigentümer(innen) und -Administrator(innen) wichtige Ereignisse nachverfolgen, wie z. B. wer bestimmte Aktionen durchgeführt hat und wann sie stattgefunden haben.\n\n\n![Audit Events (nur in englischer Sprache verfügbar)](https://about.gitlab.com/images/blogimages/compliance-04-2022/project-audit-events.png)\n\n\nAudit Events zeichnen verschiedene Ereignisse pro Gruppe und pro Projekt auf, die\n\nin der Dokumentation zu [Audit Events (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/administration/audit_events.html) eingesehen werden können.\n\nDu kannst über **Sicherheit & Compliance > Audit Events** auf Audit Events zugreifen.\n\nEinige Beispiele sind:\n\n\n- Benutzer(in) wurde mit seinen oder ihren Berechtigungen dem Projekt hinzugefügt\n\n- Änderung der Berechtigungen einer Benutzerin bzw. eines Benutzers, der/die einem Projekt zugewiesen ist\n\n- Projekt-CI/CD-Variable wurde hinzugefügt, entfernt oder ihr geschützter Status geändert\n\n- Benutzer(in) wurde mit seinen oder ihren Berechtigungen der Gruppe hinzugefügt\n\n- Gruppenname oder -pfad wurde geändert\n\n\nAudit Events können auch mittels Audit-Event-Streaming an einen HTTP-Endpunkt gesendet werden. In diesem [Video (nur in englischer Sprache verfügbar](https://youtu.be/zHwVF9-i7e4?t=52) erfährst du, wie\n\ndu das Streaming von Audit Events implementierst.\n\n\nDie **Einhaltung von Standards** gibt dir die Möglichkeit, die Merge-Request-Aktivität einer Gruppe anzuzeigen. Sie bietet eine allgemeine Ansicht für alle Projekte in der Gruppe.\n\n\n![Aktualisierung der Aufgabentrennung – Bild 5 (nur in englischer Sprache verfügbar)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750098241222.png)\n\n\nDu kannst den Bericht verwenden, um:\n\n- einen Überblick über die neuesten Merge Requests für jedes Projekt zu erhalten\n\n- zu sehen, ob und von wem Merge Requests genehmigt wurden\n\n- die Autor(inn)en von Merge Requests zu sehen\n\n- das neueste CI/CD-Pipeline-Ergebnis für jeden Merge Request zu sehen\n\n\nDer Bericht zur Einhaltung von Standards kann in der Hauptgruppe aufgerufen werden, indem du zu **Sichern > Compliance Center** gehst und die Registerkarte **Einhaltung von Standards** auswählst.\n\n\n---\n\n\nVielen Dank für deine Aufmerksamkeit! Weitere Informationen zur Aufgabentrennung in GitLab findest du unter [Kontinuierliche Software-Konformität mit GitLab](/solutions/compliance/)\n","security",[733,9,684,709],"2024-12-16",{"slug":737,"featured":6,"template":689},"ensuring-compliance","content:de-de:blog:ensuring-compliance.yml","Ensuring Compliance","de-de/blog/ensuring-compliance.yml","de-de/blog/ensuring-compliance",{"_path":743,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":744,"content":750,"config":759,"_id":761,"_type":14,"title":762,"_source":16,"_file":763,"_stem":764,"_extension":19},"/de-de/blog/getting-started-with-gitlab-understanding-ci-cd",{"title":745,"description":746,"ogTitle":745,"ogDescription":746,"noIndex":6,"ogImage":747,"ogUrl":748,"ogSiteName":673,"ogType":674,"canonicalUrls":748,"schema":749},"Erste Schritte mit GitLab: Grundlegendes zu CI/CD","In diesem Leitfaden für Einsteiger(innen) lernst du die Grundlagen der kontinuierlichen Integration und kontinuierlichen Lieferung kennen. Du erfährst, was CI/CD-Komponenten sind und wie du sie erstellst.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659525/Blog/Hero%20Images/blog-getting-started-with-gitlab-banner-0497-option4-fy25.png","https://about.gitlab.com/blog/getting-started-with-gitlab-understanding-ci-cd","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Erste Schritte mit GitLab: Grundlegendes zu CI/CD\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab\"}],\n        \"datePublished\": \"2025-04-25\",\n      }",{"title":745,"description":746,"authors":751,"heroImage":747,"date":753,"body":754,"category":755,"tags":756,"updatedDate":758},[752],"GitLab","2025-04-25","Stell dir einen Workflow vor, bei dem jede Codeänderung automatisch erstellt, getestet und für deine Benutzer(innen) bereitgestellt wird. Genau das macht [CI/CD (Kontinuierliche Integration/Kontinuierliche Lieferung)](https://about.gitlab.com/de-de/topics/ci-cd/)! Mit CI/CD kannst du Fehler frühzeitig erkennen, die Qualität des Codes sicherstellen und Software schneller und häufiger bereitstellen.\n\n## Inhaltsverzeichnis\n\n- [Was ist CI/CD?](#was-ist-cicd%3F)\n- [Vorteile von GitLab CI/CD](#vorteile-von-gitlab-cicd)\n- [Die Elemente von GitLab CI/CD](#die-elemente-von-gitlab-cicd)\n- [GitLab CI einrichten](#gitlab-ci-einrichten)\n- [Beispiele für die CI/CD-Konfiguration](#beispiele-für-die-cicd-konfiguration)\n- [GitLab Auto-DevOps](#gitlab-auto-devops)\n- [CI/CD-Katalog](#cicd-katalog)\n- [CI-Vorlagen](#ci-vorlagen)\n- [Entwicklung der nächsten Generation](#entwicklung-der-nächsten-generation)\n- [Reihe „Erste Schritte mit GitLab\"](#reihe-„erste-schritte-mit-gitlab“)\n\n### Was ist CI/CD?\n\n* **Kontinuierliche Integration** ist eine Entwicklungsmethode, bei der Entwickler(innen) häufig, nach Möglichkeit mehrmals am Tag, Codeänderungen in ein gemeinsames Repository integrieren. Jede Integration wird dann durch einen automatisierten Build- und Testprozess überprüft, so dass die Teams Probleme frühzeitig erkennen können.  \n* **Kontinuierliche Lieferung** erweitert CI, indem sie die Bereitstellungspipeline automatisiert und dafür sorgt, dass dein Code *immer* in einem einsatzfähigen Zustand ist. Du kannst deine Anwendung mit einem einzigen Klick oder automatisch in verschiedenen Umgebungen (z. B. Staging, Produktion) bereitstellen.  \n* **Kontinuierliche Bereitstellung** geht noch einen Schritt weiter, indem sie *jeden erfolgreichen Build* automatisch für die Produktion bereitstellt. Dies erfordert ein hohes Maß an Vertrauen in deine automatisierten Tests und deinen Bereitstellungsprozess.\n\n### Vorteile von GitLab CI/CD\n\nGitLab CI/CD ist ein leistungsstarkes, eingegliedertes System, das in GitLab integriert ist. Es bietet ein nahtloses Erlebnis für die Automatisierung deines gesamten Software-Entwicklungsprozesses. Mit GitLab CI/CD kannst du:\n\n* **Alles automatisieren:** Erstelle, teste und stelle deine Anwendungen mit Leichtigkeit bereit.  \n* **Bugs frühzeitig erkennen:** Erkenne und behebe Fehler, bevor sie die Produktion erreichen.  \n* **Schnelleres Feedback erhalten:** Du erhältst sofortige Rückmeldung zu deinen Code-Änderungen.  \n* **Die Zusammenarbeit verbessern:** Arbeite mit automatisierten Workflows effektiver im Team zusammen.  \n* **Die Bereitstellung beschleunigen:** Veröffentliche Software schneller und häufiger.  \n* **Risiken reduzieren:** Minimiere Fehler bei der Bereitstellung und vermeide Rollbacks.\n\n### Die Elemente von GitLab CI/CD\n\n* `.gitlab-ci.yml`**:** Diese [YAML-Datei (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/yaml/), die sich im Stammverzeichnis deines Projekts befindet, definiert deine CI/CD-Pipeline, einschließlich Phasen, Jobs und Runner.  \n* [**GitLab Runner** (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/runner/)**:** Dieser Agent führt deine CI/CD-Jobs auf deiner Infrastruktur aus (z. B. auf physischen Computern, virtuellen Maschinen, Docker-Containern oder Kubernetes-Clustern).  \n* [**Phasen** (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/yaml/#stages)**:** Phasen definieren die Reihenfolge der Ausführung deiner Jobs (z. B. Erstellen, Testen und Bereitstellen).  \n* [**Jobs** (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/yaml/#job-keywords)**:** Jobs sind einzelne Arbeitseinheiten innerhalb einer Phase (z. B. Code kompilieren, Tests ausführen und für das Staging bereitstellen).\n\n### GitLab CI einrichten\n\nDie ersten Schritte mit GitLab CI sind einfach. Hier ist ein einfaches Beispiel für eine `.gitlab-ci.yml`-Datei:\n\n```yaml\n\nstages:\n  - build\n  - test\n  - deploy\n\nbuild_job:\n  stage: build\n  script:\n    - echo \"Building the application...\"\n\ntest_job:\n  stage: test\n  script:\n    - echo \"Running tests...\"\n\ndeploy_job:\n  stage: deploy\n  script:\n    - echo \"Deploying to production...\"\n  environment:\n    name: production\n\n```\n\nDiese Konfiguration definiert drei Phasen: „build“, „test“ und „deploy“. Jede Phase enthält einen Job, der ein einfaches Skript ausführt.\n\n### Beispiele für die CI/CD-Konfiguration\n\nSehen wir uns einige realistischere Beispiele an.\n\n**Erstellen und Bereitstellen einer Node.js-Anwendung**\n\nDie folgende Pipelinedefinition beschreibt die Verwendung von npm, um eine Node.js-Anwendung zu erstellen und zu testen, und [dpl (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ci/examples/deployment/), um die Anwendung in Heroku bereitzustellen. In der Bereitstellungsphase der Pipeline werden die [GitLab-CI/CD-Variablen (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ci/variables/) verwendet, mit denen Entwickler(innen) vertrauliche Informationen (z. B. Zugangsdaten) speichern und sicher in CI/CD-Prozessen verwenden können. In diesem Beispiel wird ein API-Schlüssel für die Bereitstellung in Heroku unter dem variablen Schlüsselnamen '$HEROKU_API_KEY` gespeichert, den das dpl-Tool verwendet.\n\n```yaml\n\nstages:\n  - build\n  - test\n  - deploy\n\nbuild:\n  stage: build\n  image: node:latest\n  script:\n    - npm install\n    - npm run build\n\ntest:\n  stage: test\n  image: node:latest\n  script:\n    - npm run test\n\ndeploy:\n  stage: deploy\n  image: ruby:latest\n  script:\n    - gem install dpl\n    - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_API_KEY\n\n```\n\n**Bereitstellung in verschiedenen Umgebungen (Staging und Produktivumgebung)**\n\nGitLab bietet auch [Umgebungen (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ci/environments/) mit CI/CD. Mit dieser Funktion können Benutzer(innen) die Bereitstellung von CI/CD auf Infrastrukturziele verfolgen. Im folgenden Beispiel fügt die Pipeline Phasen mit einer Umgebungseigenschaft für eine Staging- und eine Produktivumgebung hinzu. Während die Phase „deploy_staging“ ihr Skript immer ausführt, erfordert die Phase „deploy_production“ eine manuelle Genehmigung, um eine versehentliche Bereitstellung in der Produktionsumgebung zu verhindern.\n\n```yaml\n\nstages:\n  - build\n  - test\n  - deploy_staging\n  - deploy_production\n\nbuild:\n  # ...\n\ntest:\n  # ...\n\ndeploy_staging:\n  stage: deploy_staging\n  script:\n    - echo \"Deploying to staging...\"\n  environment:\n    name: staging\n\ndeploy_production:\n  stage: deploy_production\n  script:\n    - echo \"Deploying to production...\"\n  environment:\n    name: production\n  when: manual  # Requires manual approval\n\n```\n\n### GitLab Auto-DevOps\n\n[GitLab Auto-DevOps (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/topics/autodevops/) vereinfacht CI/CD, indem es eine vordefinierte Konfiguration bereitstellt, mit der deine Anwendungen automatisch erstellt, getestet und bereitgestellt werden. Es nutzt bewährte Methoden und Branchenstandards, um deinen Workflow zu optimieren.\n\nSo aktivierst du Auto-DevOps:\n\n1. Gehe in deinem Projekt zu **Einstellungen > CI/CD > Allgemeine Pipelines**.  \n2. Aktiviere die Option **Auto-DevOps**.\n\nAuto-DevOps erkennt automatisch die Sprache und das Framework deines Projekts und konfiguriert die erforderlichen Build-, Test- und Bereitstellungsphasen. Du musst nicht einmal eine `.gitlab-ci.yml`-Datei erstellen.\n\n### CI/CD-Katalog\n\nDer [CI/CD-Katalog (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/faq-gitlab-ci-cd-catalog/) ist eine Liste von Projekten mit veröffentlichten [CI/CD-Komponenten (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/components/), die du zur Erweiterung deines CI/CD-Workflows nutzen kannst. Jeder kann ein Komponentenprojekt erstellen und es zum CI/CD-Katalog hinzufügen oder zu einem bestehenden Projekt beitragen, um die verfügbaren Komponenten zu verbessern. Die veröffentlichten Komponenten findest du im [CI/CD-Katalog](https://gitlab.com/explore/catalog) auf GitLab.com.\n\n> [Tutorial: So richtest du deine erste GitLab-CI/CD-Komponente ein (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/tutorial-how-to-set-up-your-first-gitlab-ci-cd-component/)\n\n### CI-Vorlagen\n\nDu kannst auch deine eigenen [CI-Vorlagen (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/examples/) erstellen, um CI/CD-Konfigurationen zu standardisieren und über mehrere Projekte hinweg wiederzuverwenden. Das fördert die Konsistenz und reduziert doppelte Arbeit.\n\nSo erstellst du eine CI-Vorlage:\n\n1. Erstelle eine `.gitlab-ci.yml`-Datei in einem eigenen Projekt oder Repository.  \n2. Definiere deine CI/CD-Konfiguration in der Vorlage. \n3. Verwende in der `.gitlab-ci.yml`-Datei deines Projekts das Schlüsselwort `include`, um die Vorlage einzuschließen.\n\n## Entwicklung der nächsten Generation\n\nGitLab CI/CD ist ein leistungsstarkes Tool, das deinen Workflow bei der Entwicklung verbessern kann. Wenn du die Konzepte von CI/CD verstehst, deine Pipelines konfigurierst und Funktionen wie Auto-DevOps, den CI/CD-Katalog und CI-Vorlagen nutzt, kannst du deinen gesamten Software-Entwicklungsprozess automatisieren und schneller und effizienter hochwertige Software liefern.\n\n> Willst du dein Wissen vertiefen? Registriere dich für die [englischsprachigen Kurse der GitLab University](https://university.gitlab.com/). Du kannst auch sofort mit der [kostenlosen Testversion von GitLab Ultimate](https://about.gitlab.com/de-de/free-trial/?hosted=saas) loslegen.\n\n## Reihe „Erste Schritte mit GitLab“\n\nWeitere Artikel in unserer Serie „Erste Schritte mit GitLab“:\n\n- [Benutzerverwaltung](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-how-to-manage-users/)\n- [Projekte in GitLab importieren (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/getting-started-with-gitlab-how-to-import-your-projects-to-gitlab/)  \n- [Projektmanagement](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-mastering-project-management/)\n- [Automatisiere Agile-Workflows mit dem gem gitlab-triage](https://about.gitlab.com/de-de/blog/automating-agile-workflows-with-the-gitlab-triage-gem/)\n","product",[109,9,684,757,755,685],"DevSecOps platform","2025-06-02",{"slug":760,"featured":91,"template":689},"getting-started-with-gitlab-understanding-ci-cd","content:de-de:blog:getting-started-with-gitlab-understanding-ci-cd.yml","Getting Started With Gitlab Understanding Ci Cd","de-de/blog/getting-started-with-gitlab-understanding-ci-cd.yml","de-de/blog/getting-started-with-gitlab-understanding-ci-cd",{"_path":766,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":767,"content":772,"config":779,"_id":781,"_type":14,"title":782,"_source":16,"_file":783,"_stem":784,"_extension":19},"/de-de/blog/getting-started-with-gitlab-working-with-ci-cd-variables",{"title":768,"description":769,"ogTitle":768,"ogDescription":769,"noIndex":6,"ogImage":747,"ogUrl":770,"ogSiteName":673,"ogType":674,"canonicalUrls":770,"schema":771},"Erste Schritte mit GitLab: Arbeiten mit CI/CD-Variablen","Erfahre, was CI/CD-Variablen sind, warum sie in DevSecOps wichtig sind und wie du sie am besten einsetzt.","https://about.gitlab.com/blog/getting-started-with-gitlab-working-with-ci-cd-variables","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Erste Schritte mit GitLab: Arbeiten mit CI/CD-Variablen\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab Team\"}],\n        \"datePublished\": \"2025-05-27\",\n      }",{"title":768,"description":769,"authors":773,"heroImage":747,"date":775,"body":776,"category":755,"tags":777,"updatedDate":778},[774],"GitLab Team","2025-05-27","*Willkommen zu unserer Serie „Erste Schritte mit GitLab“, in der wir Neueinsteiger(inne)n helfen, sich mit der DevSecOps-Plattform von GitLab vertraut zu machen.* \n\nIn einem früheren Artikel haben wir uns mit [GitLab CI/CD](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-understanding-ci-cd/) beschäftigt. Jetzt tauchen wir tiefer in die Welt der **CI/CD-Variablen** ein und erschließen ihr volles Potenzial.\n\n## Inhaltsverzeichnis\n\n- [Was sind CI/CD-Variablen?](#was-sind-cicd-variablen%3F)\n- [Warum sind CI/CD-Variablen wichtig?](#warum-sind-cicd-variablen-wichtig%3F)\n- [Geltungsbereiche von CI/CD-Variablen: Projekt, Gruppe und Instanz](#geltungsbereiche-von-cicd-variablen-projekt-gruppe-und-instanz)\n- [Definieren von CI/CD-Variablen](#definieren-von-cicd-variablen)\n- [Verwenden von CI/CD-Variablen](#verwenden-von-cicd-variablen)\n- [Vordefinierte CI/CD-Variablen](#vordefinierte-cicd-variablen)\n- [Bewährte Methoden](#bewährte-methoden)\n- [Entdecke die Leistungsfähigkeit von Variablen](#entdecke-die-leistungsfähigkeit-von-variablen)\n- [Reihe „Erste Schritte mit GitLab\"](#reihe-„erste-schritte-mit-gitlab“)\n\n### Was sind CI/CD-Variablen?\n\nCI/CD-Variablen sind dynamische Schlüssel-Wert-Paare, die du auf verschiedenen Ebenen in deiner GitLab-Umgebung definieren kannst (z. B. Projekt, Gruppe oder Instanz). Diese Variablen fungieren als Platzhalter für Werte, die du in deiner `.gitlab-ci.yml`-Datei verwenden kannst, um deine Pipelines anzupassen, vertrauliche Informationen sicher zu speichern und deine CI/CD-Konfiguration besser zu pflegen.\n\n### Warum sind CI/CD-Variablen wichtig?\n\nCI/CD-Variablen bieten zahlreiche Vorteile:\n\n* **Flexibilität** – Du kannst deine Pipelines leicht an verschiedene Umgebungen, Konfigurationen oder Bereitstellungsziele anpassen, ohne dein zentrales CI/CD-Skript zu ändern. \n* **Sicherheit** – Speichere vertrauliche Informationen wie API-Schlüssel, Passwörter und Token sicher und verhindere so, dass sie in deinem Code offengelegt werden.  \n* **Wartbarkeit** – Verwalte deine CI/CD-Konfiguration sauber und übersichtlich, indem du Werte in Variablen zentralisierst, was Aktualisierungen und Änderungen erleichtert. \n* **Wiederverwendbarkeit** – Definiere Variablen einmal und verwende sie in mehreren Projekten wieder, um die Konsistenz zu fördern und doppelte Arbeit zu vermeiden.\n\n### Geltungsbereiche von CI/CD-Variablen: Projekt, Gruppe und Instanz\n\nMit GitLab kannst du CI/CD-Variablen mit unterschiedlichen Geltungsbereichen definieren und so ihre Sichtbarkeit und Zugänglichkeit steuern:\n\n* **Variablen auf Projektebene** – Diese Variablen sind spezifisch für ein einzelnes Projekt und eignen sich ideal zum Speichern von projektspezifischen Einstellungen, wie zum Beispiel:\n  * Bereitstellungs-URLs: Definiere unterschiedliche URLs für Staging- und Produktivumgebungen. \n  * Datenbank-Zugangsdaten: Speichere Details zur Datenbankverbindung für Tests oder die Bereitstellung.  \n  * Feature-Flags: Aktiviere oder deaktiviere Funktionen in verschiedenen Phasen deiner Pipeline.  \n  * Beispiel: Du hast ein Projekt mit dem Namen „MyWebApp“ und möchtest die URL für die Bereitstellung speichern. Du erstellst eine Variable auf Projektebene mit dem Namen `DPROD_DEPLOY_URL` und dem Wert `https://mywebapp.com`.  \n* **Variablen auf Gruppenebene** – Diese Variablen werden von allen Projekten innerhalb einer GitLab-Gruppe gemeinsam genutzt. Sie sind nützlich für Einstellungen, die für mehrere Projekte gleich sind, wie z. B.:\n\n  * API-Schlüssel für gemeinsam genutzte Dienste: Speichere API-Schlüssel für Dienste wie AWS, Google Cloud oder Docker Hub, die von mehreren Projekten innerhalb der Gruppe genutzt werden.  \n  * Globale Konfigurationseinstellungen: Lege gemeinsame Konfigurationsparameter fest, die für alle Projekte in der Gruppe gelten.  \n  * Beispiel: Du hast eine Gruppe mit dem Namen „Web-Apps“ und möchtest einen API-Schlüssel für Docker Hub speichern. Du erstellst eine Variable auf Gruppenebene mit dem Namen `DOCKER_HUB_API_KEY` und dem entsprechenden API-Schlüsselwert.  \n* **Variablen auf Instanzebene** – Diese Variablen sind für alle Projekte auf einer GitLab-Instanz verfügbar. Sie werden in der Regel für globale Einstellungen verwendet, die für das gesamte Unternehmen gelten, wie z. B.:\n\n  * Standard-Token für die Registrierung von Runnern: Lege ein Standard-Token für die Registrierung neuer [Runner (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/runner/) fest.  \n  * Lizenzinformationen: Hier kannst du Lizenzschlüssel für GitLab-Funktionen oder Tools von Drittanbietern speichern.  \n  * Globale Umgebungseinstellungen: Lege Umgebungsvariablen fest, die für alle Projekte verfügbar sein sollen.  \n  * Beispiel: Du möchtest ein Standard-Docker-Image für alle Projekte in deiner GitLab-Instanz festlegen. Du erstellst eine Variable auf Instanzebene mit dem Namen `DEFAULT_DOCKER_IMAGE` und dem Wert `ubuntu:latest`.\n\n### Definieren von CI/CD-Variablen\n\nSo definierst du eine CI/CD-Variable:\n\n1. Klicke auf die Schaltflächen **Einstellungen > CI/CD** für dein Projekt, deine Gruppe oder deine Instanz.  \n2. Gehe zum Abschnitt **Variablen**.  \n3. Klicke auf **Variable hinzufügen**.  \n4. Gib den **Schlüssel** (z. B. `API_KEY`) und den **Wert** ein.  \n5. Aktiviere optional das Kontrollkästchen **Variable schützen**, wenn es sich um vertrauliche Informationen handelt. Dadurch wird sichergestellt, dass die Variable nur für Pipelines verfügbar ist, die auf geschützten Branches oder Tags ausgeführt werden.  \n6. Aktiviere optional das Kontrollkästchen **Variable maskieren**, um den Wert der Variable in den Job-Protokollen auszublenden und eine versehentliche Offenlegung zu verhindern.  \n7. Klicke auf **Variable speichern**.\n\n### Verwenden von CI/CD-Variablen\n\nUm eine CI/CD-Variable in deiner `.gitlab-ci.yml`-Datei zu verwenden, stellst du dem Variablennamen einfach `$` voran:\n\n```yaml\ndeploy_job:\n  script:\n    - echo \"Deploying to production...\"\n    - curl -H \"Authorization: Bearer $API_KEY\" https://api.example.com/deploy\n```\n\n### Vordefinierte CI/CD-Variablen\n\nGitLab stellt [vordefinierte CI/CD-Variablen (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ci/variables/predefined_variables/) bereit, die du in deinen Pipelines verwenden kannst. Diese Variablen liefern Informationen über die aktuelle Pipeline, den Job, das Projekt und mehr.\n\nEinige häufig verwendete vordefinierte Variablen sind:\n\n* `$CI_COMMIT_SHA`: Der Commit-SHA der aktuellen Pipeline.  \n* `$CI_PROJECT_DIR`: Das Verzeichnis, in dem das Projekt geklont wird.  \n* `$CI_PIPELINE_ID`: Die ID der aktuellen Pipeline.  \n*`$CI_ENVIRONMENT_NAME`: Der Name der Umgebung, in der bereitgestellt wird (falls zutreffend).\n\n### Bewährte Methoden\n\n* Verwalte vertrauliche Variablen sicher: Verwende geschützte und maskierte Variablen für API-Schlüssel, Passwörter und andere vertrauliche Informationen. \n* Vermeide das Hardcoding von Werten: Verwende Variablen zum Speichern von Konfigurationswerten, um deine Pipelines flexibler und wartbarer zu machen.  \n* Organisiere deine Variablen: Verwende aussagekräftige Namen und gruppiere verwandte Variablen, um sie besser zu organisieren.  \n* Verwende den richtigen Geltungsbereich: Wähle den richtigen Geltungsbereich (Projekt, Gruppe oder Instanz) für deine Variablen aus, je nach Verwendungszweck und Sichtbarkeit.\n\n### Entdecke die Leistungsfähigkeit von Variablen\n\nCI/CD-Variablen sind ein leistungsstarkes Tool zur Anpassung und Sicherung deiner GitLab-Pipelines. Wenn du verstanden hast, wie Variablen funktionieren und ihre unterschiedlichen Geltungsbereiche kennst, kannst du flexiblere, wartbarere und effizientere Workflows erstellen.\n\nWir hoffen, dass diese Informationen für dich hilfreich waren und du jetzt gut gerüstet bist, um die Möglichkeiten von GitLab für deine Entwicklungsprojekte zu nutzen.\n\n> Lege jetzt los mit CI/CD-Variablen mit einer [kostenlosen Testversion von GitLab Ultimate mit Duo Enterprise](https://about.gitlab.com/de-de/free-trial/).\n\n## Reihe „Erste Schritte mit GitLab“\nLies weitere Artikel in unserer Serie „Erste Schritte mit GitLab“:\n\n- [Benutzerverwaltung](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-how-to-manage-users/)\n- [Projekte in GitLab importieren (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/getting-started-with-gitlab-how-to-import-your-projects-to-gitlab/)  \n- [Projektmanagement](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-mastering-project-management/)\n- [Automatisiere Agile-Workflows mit dem gem gitlab-triage](https://about.gitlab.com/de-de/blog/automating-agile-workflows-with-the-gitlab-triage-gem/)\n- [Grundlegendes zu CI/CD](https://about.gitlab.com/de-de/blog/getting-started-with-gitlab-understanding-ci-cd/)\n",[755,685,9,684,109,709],"2025-06-10",{"slug":780,"featured":91,"template":689},"getting-started-with-gitlab-working-with-ci-cd-variables","content:de-de:blog:getting-started-with-gitlab-working-with-ci-cd-variables.yml","Getting Started With Gitlab Working With Ci Cd Variables","de-de/blog/getting-started-with-gitlab-working-with-ci-cd-variables.yml","de-de/blog/getting-started-with-gitlab-working-with-ci-cd-variables",{"_path":786,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":787,"content":793,"config":802,"_id":804,"_type":14,"title":805,"_source":16,"_file":806,"_stem":807,"_extension":19},"/de-de/blog/how-to-keep-up-with-ci-cd-best-practices",{"title":788,"description":789,"ogTitle":788,"ogDescription":789,"noIndex":6,"ogImage":790,"ogUrl":791,"ogSiteName":673,"ogType":674,"canonicalUrls":791,"schema":792},"CI/CD Best Practices für mehr Effizienz","Erfahre, was Continuous Integration/Continuous Delivery (CI/CD) bedeutet, wie du CI/CD Best Practices implementierst und warum sie wichtig sind.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749661856/Blog/Hero%20Images/ci-cd-demo.jpg","https://about.gitlab.com/blog/how-to-keep-up-with-ci-cd-best-practices","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"CI/CD Best Practices für mehr Effizienz\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2022-02-03\",\n      }",{"title":788,"description":789,"authors":794,"heroImage":790,"date":796,"body":797,"category":798,"tags":799,"updatedDate":801},[795],"Valerie Silverthorne","2022-02-03","Continuous Integration und Continuous Delivery [(CI/CD)](/de-de/topics/ci-cd/) stehen im Mittelpunkt jeder erfolgreichen DevOps-Praxis. Teams, die ihre Softwareentwicklung modern gestalten wollen, müssen mit den GitLab CI/CD Best Practices Schritt halten. \n\nIn diesem Artikel, erfährst du, was Continuous Integration/Continuous Delivery (CI/CD) bedeutet, wie du einige Best Practices implementierst und warum sie wichtig sind.\n\n## Was bedeutet CI/CD?\nCI/CD umfasst verschiedene Aspekte: Es ist ein technischer Prozess, eine Denkweise und eine Abfolge von Schritten. Im Kern steht die Automatisierung, die DevOps-Teams ermöglicht, die Code-Entwicklung zu optimieren.\n\nContinuous Integration (CI) erleichtert den Software-Build und die Integration des Quellcodes, verbessert die Versionskontrolle und fördert durch Automatisierung eine intensivere Zusammenarbeit. Nach der Integration folgt Continuous Delivery (CD), das automatisierte Tests und Deployments umfasst. CD verringert den manuellen Aufwand für Bereitstellung und Deployment erheblich und hilft Teams, die Verwaltungstools für den Lebenszyklus der Software deutlich zu reduzieren.\n\n### CI/CD- vs. CI/CD-Pipeline: Erklärung\nCI/CD (Continuous Integration/Continuous Delivery bzw. Continuous Deployment) und CI/CD-Pipeline sind eng miteinander verbundene Begriffe, die jedoch unterschiedliche Bedeutungen haben. \n\n**CI/CD steht für Continuous Integration und Continuous Delivery oder Continuous Deployment.** Es ist ein methodischer Ansatz in der Softwareentwicklung, der darauf abzielt, die Integration, das Testen und die Bereitstellung von Codeänderungen zu automatisieren. \n\n**Eine CI/CD-Pipeline ist die konkrete Umsetzung des CI/CD-Prinzips.** Sie besteht aus einer Reihe von automatisierten Schritten, die den gesamten Prozess der Softwareentwicklung und -bereitstellung abbilden. Eine typische CI/CD-Pipeline umfasst Stufen wie Code-Commit, Build, Test, Bereitstellung und Monitoring. Jede dieser Stufen ist so konzipiert, dass sie den Übergang von einer Entwicklungsphase zur nächsten automatisiert und beschleunigt. Eine CI/CD-Pipeline nutzt verschiedene Automatisierungswerkzeuge, um sicherzustellen, dass Codeänderungen nahtlos und effizient durch die einzelnen Phasen des Entwicklungszyklus fließen.\n\n## Best Practices: CI/CD-Pipeline\nUm mit CI/CD erfolgreich zu sein, sollte [kontinuierliche Integration](/de-de/solutions/continuous-integration/), Lieferung und Bereitstellung fest in deiner Arbeitsweise verankert sein, da sie die Basis moderner Softwareentwicklung bilden. DevOps zielt darauf ab, Software schneller als herkömmliche Methoden zu den Nutzer(innen) zu bringen. \n\nFragt man 10 Teams nach den DevOps CI/CD Best Practices, erhält man wahrscheinlich 10 verschiedene Antworten.\n\n**Dennoch gibt es einige allgemein anerkannte Tipps für DevOps CI/CD Best Practices:**\n\n**Einmaliger Build:** Vermeide es, für jede Stufe einen neuen Build zu erstellen, da dies zu Unregelmäßigkeiten führen kann. Nutze stattdessen dieselben Build-Artefakte in jeder Stufe der CI/CD-Pipeline. Das setzt einen Build voraus, der unabhängig von der Umgebung ist.\n\n**Tests optimieren:** Finde ein gutes Gleichgewicht zwischen Testabdeckung und Performance. Dauern die Tests zu lange, versuchen die Nutzer(innen) möglicherweise, den Prozess zu umgehen.\n\n**Fail Fast:** Auf der CI-Seite müssen die Entwickler, die den Code übertragen, so schnell wie möglich wissen, ob es Probleme gibt, damit sie den Code neu aufsetzen und beheben können, bevor er in Vergessenheit gerät. Die Idee des „Fail Fast“ hilft auch, den Kontextwechsel der Entwickler zu reduzieren. Das macht die DevOps-Profis zufriedener.\n\n**Regelmäßige Code-Commits:** Je regelmäßiger der Code übertragen wird, desto größer ist der Nutzen für die DevOps-Teams.\n\n**Schnelle Fehlerbehebung:** CI/CD ermöglicht es, fehlerhafte Builds schnell zu reparieren.\n\n**Bereinigte Pre-Production-Umgebungen:** Je länger Umgebungen in Gebrauch sind, desto schwieriger wird es, alle Konfigurationsänderungen und Aktualisierungen nachzuvollziehen, die vorgenommen wurden. Daher ist es ratsam, die Vorproduktionsumgebungen zwischen den einzelnen Einsätzen zu bereinigen.\n\n**Ständige Automatisierung:** Optimiere die CI/CD-Pipeline kontinuierlich, um einen Zustand der „kontinuierlichen Automatisierung“ zu erreichen.\n\n**Klare Prozesse:** Stelle sicher, dass die Release- und Rollback-Pläne gut dokumentiert sind und vom gesamten Team verstanden werden.\n\n**Frühzeitige Sicherheit:** CCI/CD ist eine Verschiebung des Schwerpunkts und bietet daher eine gute Gelegenheit, die Sicherheit früher in den Prozess zu integrieren. Somit gibt es auch CI/CD Pipeline Security Best Practices, die du beachten solltest.\n\n**Feedback-Schleifen einrichten:** Sorge dafür, dass das gesamte Team leicht Feedback erhalten und geben kann.\n\n## Best Practices für Continuous Delivery\nBest Practices für Continuous Delivery und Deployment sollten genauer betrachtet werden, da Continuous Integration oft mehr Aufmerksamkeit erhält. \n\n**Hier ist eine Übersicht der bewährten Praktiken für CD:**\n\n**Starte mit dem Vorhandenen:** Warte nicht auf eine neue Plattform. Es ist immer möglich, bestehende Systeme zu optimieren, um schneller und effizienter zu arbeiten.\n\n**Setze auf Einfachheit:** Die effektivste CD wird mit einem Minimum an Tools durchgeführt.\n\n**Behalte den Überblick:** Probleme und Merge-Anfragen können leicht außer Kontrolle geraten. Wenn möglich, nutze Meilensteine, um den Überblick zu behalten. Bonus: Meilensteine können auch bei der Planung von Agile-Sprints und -Releases hilfreich sein.\n\n**Automatisiere Bereitstellungen:** Setze auf Automatisierung beim User Acceptance Testing und in der Staging-Phase.\n\n**Release-Pipeline optimieren:** Automatisierung ist der Schlüssel zur effizienten Verwaltung der Release-Pipeline.\n\n**Überwachung einrichten:** Eine effektive Überwachung des Produktionsprozesses spart Zeit und Geld und liefert zudem wertvolle Daten für geschäftliche Entscheidungen.\n\n**Führe Continuous Deployment ein:** Sobald Continuous Delivery stabil läuft, führe ein „hands-free“-Deployment ein, das es ermöglicht, Änderungen automatisch in die Produktion zu überführen.\n\n## Optimierung der CI/CD-Pipeline\nEine CI/CD-Pipeline stellt die Abfolge von Schritten dar, die erforderlich sind, um eine neue Softwareversion bereitzustellen. Durch Überwachung und Automatisierung können diese Prozesse erheblich verbessert werden, insbesondere in den Phasen der Integration, des Testens, der Bereitstellung und des Deployments.\n\n**Die wesentlichen Bestandteile einer CI/CD-Pipeline umfassen:**\n\n**1. Planung**\n**2. Analyse**\n**3. Design**\n**4. Build**\n**5. Test**\n**6. Release**\n**7. Deployment**\n**8. Validierung**\n**9. Compliance**\n**10. Wartung**\n\nObwohl diese Schritte manuell durchgeführt werden können, entfaltet die CI/CD-Pipeline ihren vollen Nutzen erst durch Automatisierung.\n\n**Zur Verbesserung der CI/CD-Pipeline bieten sich folgende Maßnahmen an:**\n\n**Release-Strategie variieren:** Ein Canary-Release (oder [Canary Deployment](https://docs.gitlab.com/user/project/canary_deployments/)) könnte in Betracht gezogen werden. Dabei werden neue Funktionen zunächst nur einer ausgewählten Gruppe von Nutzern zur Verfügung gestellt.\n\n**Automatisierung ausweiten:** Erhöhe die Anzahl der automatisierten Tests – davon kann es nie genug geben.\n\n**Tools rationalisieren:** Weniger Tools führen zu weniger Übergaben und vereinfachten Abläufen. Eine integrierte [DevOps-Plattform](/de-de/solutions/devops-platform/), die CI/CD umfasst, kann hier besonders vorteilhaft sein.\n\n**Regelmäßige Softwarekompositionsanalysen:** Führe kontinuierlich Analysen der Softwarezusammensetzung durch, um sicherzustellen, dass das DevOps-Team kritische Probleme mit Open-Source-Software frühzeitig erkennt und verfolgt.\n\n## CI/CD: Metriken zur Erfolgsmessung\nUm zu erkennen, wie effektiv CI/CD-Praktiken sind, ist eine kontinuierliche Messung notwendig. Metriken sind entscheidend, um die Systemleistung zu verbessern und den Mehrwert zu identifizieren. Sie dienen auch als Basis zur Beurteilung der Auswirkungen von Optimierungen.\n\n### Zykluszeit\nDie Zykluszeit misst die Dauer vom Beginn der Arbeit am Code bis zur Bereitstellung einer funktionalen Anwendung. Durch die Messung der verschiedenen Entwicklungsphasen erhältst du wertvolle Einblicke in die gesamte Entwicklungsdauer und erkennst mögliche Engpässe im Prozess. \n\n### Time to Value\n„Time to Value“ beschreibt, wie lange es dauert, bis geschriebener Code veröffentlicht wird. Idealerweise sollten Integration, Testen, Lieferung und Deployment innerhalb von Minuten bis wenigen Stunden abgeschlossen sein. Dauert der Durchlauf durch die CI/CD-Pipeline Tage, ist eine Optimierung erforderlich, um den Wert zu realisieren.\n\n### Uptime\nUptime ist ein Maß für die Stabilität und Zuverlässigkeit des Systems und dafür, ob alles so funktioniert, wie es sollte. Sie ist eine der wichtigsten Aufgaben des Ops-Teams. Wenn die CI/CD-Strategie automatisiert ist, können die Ops-Leiter mehr Zeit auf die Systemstabilität und weniger Zeit auf Workflow-Probleme verwenden.\n\n### Fehlerquoten\nDie Fehlerquote bei Anwendungen ist eine alltägliche Erscheinung im Entwicklungsprozess. Ihre Verfolgung ist sehr wichtig, denn die Fehlerquoten können nicht nur auf Qualitätsprobleme hinweisen, sondern auch auf laufende Probleme mit der Leistung und der Uptime. Wenn die Uptime und die Fehlerquoten hoch erscheinen, kann dies ein Hinweis auf eine gängige CI/CD-Problematik zwischen Dev- und Ops-Teams sein. Betriebsziele sind ein wichtiger Indikator für den Prozesserfolg.\n\n### Infrastrukturkosten\nDie Infrastrukturkosten sind besonders bei Cloud-nativer Entwicklung entscheidend. Die Verwaltung einer CI/CD-Plattform kann teuer werden, wenn die Kosten nicht kontrolliert werden. Cloud-Anbieter berücksichtigen bei der Preisgestaltung die Ausgaben für Netzwerkausrüstung, Infrastrukturwartung und Personal.\n\n### Teambindung\nEntwickler(innen) und Mitarbeiter(innen) bleiben tendenziell länger im Unternehmen, wenn sie sich wertgeschätzt und zufrieden fühlen. Gute Zusammenarbeit und effektive Kommunikation innerhalb der Teams fördern die Teambindung. Andererseits kann eine niedrige Bindungsrate auf Unzufriedenheit hinweisen, was eine Analyse der internen Abläufe notwendig macht.\n\n## Vorteile der Einhaltung von CI/CD Best Practices\nWenn Best Practices befolgt werden, sind die Vorteile von CI/CD in der gesamten Organisation spürbar: Von HR bis zu den Betriebsabteilungen arbeiten die Teams besser und erreichen ihre Ziele. Die Etablierung von Metriken zur Bewertung der CI/CD-Performance kann über die Bereitstellung von Einblicken in die Entwicklung hinausgehen und sich auf viele Aspekte des Unternehmens auswirken.\n\nEine gut funktionierende CI/CD-Pipeline kann für DevOps-Teams ein entscheidender Faktor sein. \n\n**Dies sind einige der größten Vorteile einer guten CI/CD-Pipeline:**\n\n***Entwickler(innen) reparieren nichts, sie schreiben Code.*** Weniger Tools und Toolchains bedeuten weniger Zeitaufwand für Wartung und mehr Zeit, tatsächlich hochwertige Softwareanwendungen zu produzieren.\n\n***Code ist in Produktion.*** Anstatt in einer Warteschlange zu sitzen, gelangt der Code tatsächlich in die reale Welt. Dies führt auch zu glücklicheren Entwicklern.\n\n***Entwickler(innen) haben die Kapazität, sich auf die Lösung von Geschäftsproblemen zu konzentrieren.*** Ein optimierter CI/CD-Prozess gibt Entwickler(innen) Zeit, sich auf das Wesentliche zu konzentrieren und nicht auf die Ablenkungen durch fehlerhaften Code, verpasste Übergaben, Produktionsprobleme und mehr.\n\n***Innovation macht alles einfacher.*** In einer wettbewerbsorientierten Welt benötigen Unternehmen alle verfügbaren Tools, um sich zu behaupten. Ein gut aufgebauter CI/CD-Prozess erleichtert, beschleunigt und sichert die Softwareentwicklung, was bedeutet, dass DevOps-Teams die Zeit und Energie haben, außerhalb des Rahmens zu denken.\n\n***Talente kommen und bleiben.*** Der Arbeitsmarkt ist sehr wettbewerbsintensiv, und DevOps-Talente sind schwer zu beeindrucken. Nichts sagt „Wir nehmen unser DevOps-Team ernst“ mehr, als eine Organisation, die in die Technologie und Prozesse rund um CI/CD investiert.\n\n***Jeder und jede macht das, was er oder sie am besten kann.*** Dev, Ops, Sec und Test haben jeweils eine wichtige Rolle zu spielen und CI/CD hilft, die Verantwortlichkeiten klar zu definieren.\n\n## CI/CD-Deployment-Strategie\nDenke daran, dass es bei CI/CD darum geht, Kund(innen) eine Softwareanwendung schneller und in besserer Qualität zu liefern als zuvor. Unternehmen, die CI/CD einführen, erleben oft eine erhebliche Steigerung ihrer Produktivität. Der Schlüssel zum Erfolg liegt darin, eine Bereitstellungsstrategie zu entwickeln, die auf die spezifischen Bedürfnisse des Unternehmens zugeschnitten ist.\n\n**Hier sind einige Strategien, die zu einer erfolgreichen CI/CD-Implementierung beitragen:**\n\n**Häufige Releases festlegen:** Plane regelmäßige und häufige Veröffentlichungen, um die Vorteile von CI/CD voll auszuschöpfen.\n\n**Build-Prozess automatisieren:** Setze auf Automatisierung im Build-Prozess, um Konsistenz und Effizienz zu gewährleisten.\n\n**Tests parallel durchführen:** Führe Tests parallel aus und erstelle eine effiziente Bereitstellungspipeline.\n\n**Schnelles Scheitern und „Shift Left“-Mentalität:** Fördere eine Kultur des schnellen Scheiterns und verschiebe Tests und Qualitätskontrollen frühzeitig in den Entwicklungsprozess. Dies gibt den Entwickler(innen) die Tools und Fähigkeiten, um schneller und sicherer zu arbeiten.\n\n**Schnelles Feedback durch CI-Tools:** Verwende CI-Tools, die schnelles Feedback liefern, um Entwicklungszyklen zu verkürzen und die Qualität zu verbessern.\n\nDiese Strategien helfen dabei, die Vorteile von CI/CD voll auszuschöpfen und die Effizienz sowie die Qualität der Softwareentwicklung zu steigern.\n\n## Wie kann ich CI/CD in meiner Organisation implementieren?\nBevor eine Software implementiert wird, ist es entscheidend, die Unternehmensziele klar zu definieren. Dies gilt ebenso für die Einführung von CI/CD. Alle Beteiligten in der Entwicklung sollten frühzeitig in den Implementierungsprozess eingebunden werden. Entwickler(innen) sollten besonders berücksichtigt werden, da sie die Hauptnutzer(innen) der neuen Tools und Prozesse sein werden.\n\nFühre gründliche Recherchen durch, wenn du Software bewertest, die CI/CD unterstützt, und frage nach kostenlosen Testversionen, um deren Eignung zu prüfen.\n\nObwohl CI/CD darauf abzielt, die Softwarebereitstellung durch Automatisierung zu beschleunigen, ist es ratsam, den Implementierungsprozess mit einer „Langsam und stetig“-Einstellung zu beginnen. Eine langsame, sorgfältige Einführung hilft, Fehler in der fertigen Anwendung zu minimieren und die langfristige Effizienz zu sichern.\n\nKonsistenz im Integrationsprozess ist entscheidend. Führe regelmäßige Unit-Tests durch, löse Releases zunächst manuell aus und verfolge relevante Metriken. Bestimme dann, welche Prozesse automatisiert werden können und sollten, um die Effizienz weiter zu steigern.\n\n[Mit GitLab findest du jetzt die richtige Lösung, um die CI/CD Best Practices richtig umzusetzen.](/de-de/solutions/github/)","insights",[9,684,800],"DevOps","2025-04-16",{"slug":803,"featured":6,"template":689},"how-to-keep-up-with-ci-cd-best-practices","content:de-de:blog:how-to-keep-up-with-ci-cd-best-practices.yml","How To Keep Up With Ci Cd Best Practices","de-de/blog/how-to-keep-up-with-ci-cd-best-practices.yml","de-de/blog/how-to-keep-up-with-ci-cd-best-practices",{"_path":809,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":810,"content":816,"config":826,"_id":828,"_type":14,"title":829,"_source":16,"_file":830,"_stem":831,"_extension":19},"/de-de/blog/tutorial-automated-release-and-release-notes-with-gitlab",{"title":811,"description":812,"ogTitle":811,"ogDescription":812,"noIndex":6,"ogImage":813,"ogUrl":814,"ogSiteName":673,"ogType":725,"canonicalUrls":814,"schema":815},"GitLab-Tutorial: Releases & Versionshinweise automatisieren","Mit GitLab kannst du Release-Artefakte, Versionshinweise und Änderungsprotokolle, die benutzerbezogenen Software-Änderungen enthalten, automatisieren.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659978/Blog/Hero%20Images/automation.png","https://about.gitlab.com/blog/tutorial-automated-release-and-release-notes-with-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Tutorial: Releases und Versionshinweise mit GitLab automatisieren\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ben Ridley\"}],\n        \"datePublished\": \"2023-11-01\",\n      }",{"title":811,"description":812,"authors":817,"heroImage":813,"date":819,"body":820,"category":755,"tags":821,"updatedDate":825},[818],"Ben Ridley","2023-11-01","***Update 2025** - Die Änderungsprotokoll-API wurde weiterentwickelt und enthält jetzt geniale neue Funktionen, auf die wir in diesem Blog nicht eingehen, wie die Möglichkeit, benutzerdefinierte Änderungsprotokolle mit Vorlagenwerten aus deinem Commit-Verlauf bereitzustellen. [Mehr dazu erfährst du in der offiziellen Dokumentation zu Änderungsprotokollen (nur in englischer Sprache verfügbar).](https://docs.gitlab.com/user/project/changelogs/)*\n\nWenn du Software entwickelst, auf die sich Benutzer(innen) verlassen, ist eine effektive Kommunikation über Änderungen bei jeder Release unerlässlich. Indem du Benutzer(innen) über neue Funktionen sowie darüber informierst, was geändert oder entfernt wurde, stellst du sicher, dass sie die Vorteile der Software wirklich nutzen können und sie bei Upgrades keine unangenehmen Überraschungen erwarten.\n\nIn der Vergangenheit war das Erstellen von Versionshinweisen und die Pflege eines Änderungsprotokolls eine mühsame Aufgabe, bei der Entwickler(innen) die Änderungen extern überwachen oder eigene Release Manager den Verlauf der Zusammenführungen durcharbeiten mussten. Mit der Änderungsprotokoll-API von GitLab kannst du den umfassenden Verlauf, der in unserem Git-Repository gespeichert ist, heranziehen, um ganz einfach Versionshinweise zu erstellen und ein Änderungsprotokoll zu führen.\n\nIn diesem Tutorial sehen wir uns an, wie du Releases mit GitLab automatisieren kannst und finden heraus, wie man Release-Artefakte, Versionshinweise und ein umfassendes Änderungsprotokoll, das alle benutzerbezogenen Software-Änderungen enthält, erstellt.\n\n## Releases in GitLab\nZuerst wollen wir uns ansehen, wie Releases in GitLab funktionieren.\n\nIn GitLab ist eine Release eine bestimmte Version deines Codes, die durch ein Git-Tag identifiziert wird. Dieses enthält Details zu den Änderungen seit der letzten Release (und Versionshinweise) sowie zugehörige Artefakte, die aus dieser Version des Codes erstellt wurden, wie Docker-Images, Installationspakete und Dokumentation.\n\nDu kannst Releases in GitLab über die UI erstellen und nachverfolgen, indem du unsere Release-API aufrufst oder den Job `release` innerhalb einer CI-Pipeline aufrufst. In diesem Tutorial verwenden wir den Job `release` in einer CI/CD-Pipeline, sodass wir die Automatisierung, die wir in unserer Pipeline zum Testen, für Code-Scans und mehr verwenden, auch für automatisierte Releases nutzen können.\n\nUm unsere Releases zu automatisieren, müssen wir zunächst die folgende Frage beantworten: Wo bekommen wir für unsere Versionshinweise und unser Änderungsprotokoll Informationen zu den vorgenommenen Änderungen? Die Antwort: In unserem Git-Repository, in dem wir durch Commit-Nachrichten und den Merge-Commit-Verlauf eine umfassende Übersicht über die Entwicklungsaktivitäten haben. Sehen wir uns an, ob wir diesen umfassenden Verlauf nutzen können, um automatisch unsere Versionshinweise und Änderungsprotokolle zu erstellen.\n\n## Einführung in Commit-Trailer\n[Commit-Trailer](https://git-scm.com/docs/git-interpret-trailers) sind strukturierte Einträge in deinen Git-Commits, die erstellt werden, indem du einfach die Formatierungsnachrichten `\u003CHEADER>:\u003CBODY>` am Ende deines Commits einfügst. Das CLI-Tool `git` kann diese dann parsen und für die Verwendung in anderen Systemen extrahieren. Ein Beispiel, das du vielleicht schon einmal verwendet hast, ist `git commit --sign-off`, um ein Commit zu beenden. Dies wird implementiert, indem der Trailer `Signed-off-by: \u003CDein Name>` zum Commit hinzugefügt wird. Wir können hier beliebige strukturierte Daten hinzufügen, sodass dies eine tolle Möglichkeit ist, Informationen zu speichern, die für das Änderungsprotokoll nützlich sein könnten.\n\nWenn wir in unseren Commits den Trailer `Changelog: \u003Cadded/changed/removed>` verwenden, parst die Änderungsprotokoll-API von GitLab diese und verwendet sie, um automatisch ein Änderungsprotokoll für uns zu erstellen!\n\nSehen wir uns das in Aktion an, indem wir Änderungen an einer echten Codebase vornehmen, eine Release durchführen und dann Versionshinweise und Änderungsprotokoll-Einträge generieren.\n\n## Beispielprojekt\nFür diesen Blog verwende ich ein einfaches Python-Web-App-Repository. Nehmen wir an, dass Version 1.0.0 der Anwendung gerade veröffentlicht wurde und die aktuelle Version des Codes ist. Ich habe auch die Release 1.0.0 in GitLab erstellt, was ich manuell tun musste, da wir unsere automatisierte Release-Pipeline ja noch nicht erstellt haben:\n\n![Ein Screenshot der GitLab-UI, die eine Release für Version 1.0.0 zeigt](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/1-0-release.png)\n\n## Nehmen wir unsere Änderungen vor\nWir entwickeln rasend schnell und arbeiten daher schon daran, Version 2.0.0 unserer Anwendung heute zu veröffentlichen. Im Rahmen unserer Release 2.0.0 fügen wir eine neue Funktion zu unserer App hinzu: einen Chatbot! Wir werden auch die Quanten-Blockchain-Funktion entfernen, da wir diese nur für die erste Finanzierungsrunde benötigt haben. Außerdem fügen wir einen automatisierten Release-Job zu unserer CI/CD-Pipeline für unsere Release 2.0.0 hinzu.\n\nZuerst entfernen wir die nicht benötigten Funktionen. Ich habe einen Merge Request erstellt, der die notwendigen Änderungen enthält. Wir müssen sicherstellen, dass wir eine Commit-Nachricht haben, die den Trailer `Changelog: removed` enthält. Dazu gibt es mehrere Möglichkeiten: Wir können ihn unter anderem direkt in einen Commit einbauen oder einen interaktiven Rebase durchführen und über das CLI hinzufügen. Der einfachste Weg in unserem Fall ist meiner Meinung nach, bis zum Ende zu warten und dann die Schaltfläche `Edit commit message` in GitLab zu verwenden, um den Trailer folgendermaßen zum Merge-Commit hinzuzufügen:\n\n![Screenshot der GitLab-UI, der einen Merge Request zum Entfernen nicht verwendeter Funktionen zeigt](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/remove-unused-features-mr.png)\n\nMit dieser Methode kannst du auch den Titel des Merge-Commits auf einen prägnanteren Titel ändern. Ich habe den Titel meines Merge-Commit auf „Nicht verwendete Funktionen entfernen“ geändert, da dies im Eintrag im Änderungsprotokoll angezeigt wird.\n\nAls nächstes fügen wir einige neue Funktionen für die Version 2.0.0 hinzu. Hier müssen wir nur einen weiteren Merge Request öffnen, der unsere neuen Funktionen enthält, und dann den Merge-Commit bearbeiten, sodass er den Trailer `Changelog: added` enthält, und dann den Commit-Titel auf einen prägnanteren Titel ändern:\n\n![Screenshot der GitLab-UI, der einen Merge Request zum Hinzufügen neuer Funktionen zeigt](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/add-chatbot-mr.png)\n\nJetzt sind wir eigentlich bereit, 2.0.0 zu veröffentlichen. Aber dieses Mal möchten wir unsere Release nicht manuell erstellen. Deshalb fügen wir vor der Release einige Jobs zur Datei `.gitlab-ci.yml` hinzu, die die Release automatisch für uns durchführen und die entsprechenden Versionshinweise und Einträge ins Änderungsprotokoll erstellen, wenn wir unseren Code mit einer neuen Version wie z. B. `2.0.0` taggen.\n\n**Hinweis:** Wenn du Änderungsprotokoll-Trailer erzwingen möchtest, solltest du überlegen, etwas wie [Gefahr bei der Durchführung automatischer Überprüfungen für MR-Konventionen (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/development/dangerbot.html) zu verwenden.\n\n## Erstellen einer automatisierten Release-Pipeline\nDamit unsere Pipeline funktioniert, müssen wir ein Projektzugriffstoken erstellen, mit dem wir die GitLab-API aufrufen können, damit sie die Einträge im Änderungsprotokoll erstellt. [Erstelle ein Projektzugriffstoken im API-Bereich (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html#create-a-project-access-token) und [speichere das Token dann als CI/CD-Variable (nur in englischer Sprache verfügbar)]((https://docs.gitlab.com/ee/ci/variables/#define-a-cicd-variable-in-the-ui) mit dem Namen `CI_API_TOKEN`. Wir verweisen auf diese Variable, um uns bei der API zu authentifizieren.\n\nNun fügen wir zwei neue Jobs zu unserer Datei `gitlab-ci.yml` hinzu:\n```yaml\nprepare_job:\n  stage: prepare\n  image: alpine:latest\n  rules:\n  - if: '$CI_COMMIT_TAG =~ /^v?\\d+\\.\\d+\\.\\d+$/'\n  script:\n    - apk add curl jq\n    - 'curl -H \"PRIVATE-TOKEN: $CI_API_TOKEN\" \"$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/changelog?version=$CI_COMMIT_TAG\" | jq -r .notes > release_notes.md'\n  artifacts:\n    paths:\n    - release_notes.md\n\nrelease_job:\n  stage: release\n  image: registry.gitlab.com/gitlab-org/release-cli:latest\n  needs:\n    - job: prepare_job\n      artifacts: true\n  rules:\n  - if: '$CI_COMMIT_TAG =~ /^v?\\d+\\.\\d+\\.\\d+$/'\n  script:\n    - echo \"Creating release\"\n  release:\n    name: 'Release $CI_COMMIT_TAG'\n    description: release_notes.md\n    tag_name: '$CI_COMMIT_TAG'\n    ref: '$CI_COMMIT_SHA'\n    assets:\n      links:\n        - name: 'Container Image $CI_COMMIT_TAG'\n          url: \"https://$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA\"\n```\n\nIn der oben angeführten Konfiguration verwendet `prepare_job` die Befehle `curl` und `jq`, um den Endpunkt der Änderungsprotokoll-API von GitLab aufzurufen und übergibt dies dann an unser `release_job`, um die Release zu erstellen. Genauer gesagt sieht das so aus:\n- Wir verwenden das Projektzugriffstoken, dass wir zuvor erstellt haben, um die Änderungsprotokoll-API von GitLab aufzurufen, die dann die Versionshinweise erstellt. Wir speichern dies als Artefakt.\n- Wir verwenden die Variable `$CI_COMMIT_TAG` als Version. Dazu müssen wir eine semantische Versionierung für unsere Tags verwenden (beispielsweise so etwas wie `2.0.0`). Du wirst auch bemerkt haben, dass ich den Release-Job mit dem Abschnitt `rules` eingeschränkt habe, der auf ein semantisches Versions-Tag überprüft.\n\t- Damit die Änderungsprotokoll-API von GitLab funktioniert, ist eine semantische Versionierung erforderlich. Sie verwendet dieses Format, um die neueste Release zu finden und sie mit unserer aktuellen Release zu vergleichen.\n- Wir verwenden das offizielle Image `release-cli` von GitLab. „release-cli“ ist erforderlich, um das Schlüsselwort `release` in einem Job zu verwenden.\n- Wir verwenden das Schlüsselwort `release`, um eine Release in GitLab zu erstellen. Dies ist ein spezielles Job-Schlüsselwort, das für die Erstellung einer Release und das Ausfüllen der erforderlichen Felder reserviert ist.\n- Wir können eine Datei als Argument an die `description` der Release übergeben. In unserem Fall ist es die Datei, die wir in `prepare_job` erstellt haben und die als Artefakt an diesen Job übergeben wurde.\n- Wir haben auch unser Container-Image, das früher in der Pipeline erstellt wurde, als Release-Asset hinzugefügt. Du kannst alle Assets aus deinem Build-Prozess anhängen, die du möchtest, z. B. Binärdateien oder Dokumentationen, indem du eine URL zu dem Ort angibst, an den du sie zuvor in der Pipeline hochgeladen hast.\n\n## Durchführen einer automatisierten Release\nMit dieser Konfiguration müssen wir nur ein Tag in unser Repository übertragen, das unserem Versionsschema entspricht, um eine Release durchzuführen. Du kannst einfach ein Tag mit dem CLI pushen. Für dieses Beispiel wird die GitLab-UI verwendet, um ein Tag im main-Branch zu erstellen. Erstelle ein Tag, indem du in der Seitenleiste „Code“ -> „Tags“ -> „Neues Tag“ auswählst:\n![Screenshot der GitLab-UI, der zeigt, wie man ein Tag erstellt](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/create-2-tag.png)\n\nNach der Erstellung werden unsere Pipelines ausgeführt. Die Änderungsprotokoll-API von GitLab generiert automatisch Versionshinweise für uns als Markdown, der alle Änderungen zwischen dieser Release und der vorherigen Release enthält. Hier ist der Markdown, der in unserem Beispiel generiert wurde:\n\n```md\n## 2.0.0 (2023-08-25)\n\n### added (1 change)\n\n- [Add ChatBot](gl-demo-ultimate-bridley/super-devsecops-incorporated/simply-notes-release-demo@0c3601a45af617c5481322bfce4d71db1f911b02) ([merge request](gl-demo-ultimate-bridley/super-devsecops-incorporated/simply-notes-release-demo!4))\n\n### removed (1 change)\n\n- [Remove Unused Features](gl-demo-ultimate-bridley/super-devsecops-incorporated/simply-notes-release-demo@463d453c5ae0f4fc611ea969e5442e3298bf0d8a) ([merge request](gl-demo-ultimate-bridley/super-devsecops-incorporated/simply-notes-release-demo!3))\n```\n\nWie du sehen kannst, hat GitLab die Einträge für unsere Versionshinweise automatisch mit unseren Git-Commit-Trailern extrahiert. Außerdem werden hilfreiche Links zum Merge Request bereitgestellt, damit die Leser(innen) weitere Details und Diskussionen zu den Änderungen sehen können.\n\nUnd jetzt folgt unsere letzte Release:\n![GitLab-Release-UI, die ein Release für Version 2.0.0 zeigt](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/2-0-release.png)\n\n## Erstellen des Änderungsprotokolls\nAls nächstes möchten wir unser Änderungsprotokoll aktualisieren (das im Grunde ein gesammelter Verlauf aller deiner Versionshinweise ist). Du kannst dazu eine `POST`-Anfrage an den Änderungsprotokoll-API-Endpunkt senden, den wir zuvor verwendet haben.\n\nDu kannst dies auch als Teil deiner Release-Pipeline tun, wenn du möchtest. Dazu kannst du beispielswiese den folgenden Code in den Abschnitt `script` deines Vorbereitungsjobs einfügen:\n```sh\n'curl -H \"PRIVATE-TOKEN: $CI_API_TOKEN\" -X POST \"$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/changelog?version=$CI_COMMIT_TAG\"\n```\n\n**Beachte dabei, dass dies das Repository ändert.** Es wird ein Commit erstellt, um die neuesten Notizen zu einer Datei `CHANGELOG.md` hinzuzufügen:\n![Screenshot des Repositorys, der einen Commit zeigt, der die Änderungsprotokolldatei aktualisiert](https://about.gitlab.com/images/blogimages/2023-08-22-automated-release-and-release-notes-with-gitlab/changelog-api-commit.png)\n\nUnd das war’s auch schon! Indem wir den umfassenden Verlauf, den uns `git` bietet, mit praktischen Commit-Trailern nutzen, können wir die leistungsstarke API und die CI/CD-Pipelines von GitLab optimal einsetzen, um unsere Release-Prozesse zu automatisieren und Versionshinweise für uns zu erstellen.\n\n> Wenn du das Projekt erkunden möchtest, das wir für diesen Artikel verwendet haben, [findest du es unter diesem Link](https://gitlab.com/gitlab-learn-labs/sample-projects/release-automation-demo).\n",[822,9,109,800,823,824],"Tutorial","DevSecOps","Git","2025-06-05",{"slug":827,"featured":6,"template":689},"tutorial-automated-release-and-release-notes-with-gitlab","content:de-de:blog:tutorial-automated-release-and-release-notes-with-gitlab.yml","Tutorial Automated Release And Release Notes With Gitlab","de-de/blog/tutorial-automated-release-and-release-notes-with-gitlab.yml","de-de/blog/tutorial-automated-release-and-release-notes-with-gitlab",{"_path":833,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":834,"content":840,"config":847,"_id":849,"_type":14,"title":850,"_source":16,"_file":851,"_stem":852,"_extension":19},"/de-de/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"title":835,"description":836,"ogTitle":835,"ogDescription":836,"noIndex":6,"ogImage":837,"ogUrl":838,"ogSiteName":673,"ogType":674,"canonicalUrls":838,"schema":839},"Kontinuierliche Bereitstellung in fünf Umgebungen mithilfe von untergeordneten Pipelines","Erfahre, wie du die kontinuierliche Bereitstellung in verschiedenen Umgebungen – darunter temporäre, sofort einsatzbereite Sandboxes – mit einem minimalistischen GitLab-Workflow verwalten kannst.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097012/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_397632156_3Ldy1urjMStQCl4qnOBvE0_1750097011626.jpg","https://about.gitlab.com/blog/using-child-pipelines-to-continuously-deploy-to-five-environments","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Kontinuierliche Bereitstellung in fünf Umgebungen mithilfe von untergeordneten Pipelines\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Olivier Dupré\"}],\n        \"datePublished\": \"2024-09-26\",\n      }",{"title":835,"description":836,"authors":841,"heroImage":837,"date":843,"body":844,"category":682,"tags":845,"updatedDate":846},[842],"Olivier Dupré","2024-09-26","Manchmal brauchen DevSecOps-Teams die Möglichkeit, die kontinuierliche Bereitstellung über mehrere Umgebungen übergreifend zu verwalten, ohne dabei ihre Workflows zu verändern. Die [DevSecOps-Plattform von GitLab](https://about.gitlab.com/de-de/) macht dies mit einem minimalistischen Ansatz möglich, unter anderem für temporäre, sofort einsatzbereite Sandboxes. In diesem Artikel erfährst du, wie du die kontinuierliche Bereitstellung der Infrastruktur mit Terraform in verschiedenen Umgebungen ausführen kannst.\n\nDiese Strategie kann einfach auf andere Projekte umgesetzt werden, egal, ob es sich um Infrastructure as Code (IaC), die auf einer anderen Technologie wie [Pulumi](https://www.pulumi.com/) oder [Ansible](https://www.ansible.com/) basiert, um Quellcode in beliebigen Sprachen oder ein Monorepo handelt, bei dem viele Sprachen gemischt verwendet werden.\n\nDie letzte Pipeline, die du am Ende dieses Tutorials hast, stellt Folgendes bereit:\n\n* Eine temporäre **Review-Umgebung** für jeden Feature-Branch.\n* Eine **Integrationsumgebung**, die einfach zu löschen und vom Haupt-Branch aus bereitzustellen ist.\n* Eine **QA-Umgebung**, die ebenfalls von dem Haupt-Branch bereitgestellt wird, um Qualitätssicherungsschritte durchzuführen.\n* Eine **Staging-Umgebung**, die für jedes Tag bereitgestellt wird. Dies ist die letzte Runde vor der Produktion.\n* Eine **Produktionsumgebung**, die direkt nach der Staging-Umgebung folgt. Diese wird zur Demonstration manuell ausgelöst, kann aber auch kontinuierlich bereitgestellt werden.\n\n>Hier findest du die Legende für die Flussdiagramme in diesem Artikel:\n> * Runde Boxen sind die GitLab-Branches.\n> * Eckige Boxen sind die Umgebungen.\n> * Der Text auf den Pfeilen sind die Aktionen, die von einem Feld zum nächsten fließen sollen.\n> * Eckige Quadrate sind Entscheidungsschritte.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    A(main) -->|new feature| B(feature_X)\n\n    B -->|auto deploy| C[review/feature_X]\n    B -->|merge| D(main)\n    C -->|destroy| D\n\n    D -->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\n    D -->|tag| G(X.Y.Z)\n    F -->|validate| G\n\n    G -->|auto deploy| H[staging]\n    H -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\nBei jedem Schritt erfährst du das [Warum](#why) und das [Was](#what), bevor du zum [Wie](#how) übergehst. Dies wird dir helfen, dieses Tutorial vollständig zu verstehen und zu replizieren.\n\n## Warum\n\n* [Kontinuierliche Integration](https://about.gitlab.com/de-de/topics/ci-cd/#what-is-continuous-integration-ci) ist fast ein De-facto-Standard. Die meisten Unternehmen haben CI-Pipelines implementiert oder sind bereit, ihre Arbeitsweise zu standardisieren.\n\n* [Kontinuierliche Bereitstellung](https://about.gitlab.com/topics/ci-cd/#what-is-continuous-delivery-cd), wobei Artefakte in ein Repository oder eine Registry am Ende der CI-Pipeline gepusht werden, ist ebenfalls beliebt.\n\n* Kontinuierliche Bereitstellung, die weiter geht und diese Artefakte automatisch bereitstellt, ist allerdings weniger verbreitet. Wenn, dann wird sie vor allem im Bereich von Anwendungen implementiert. Wenn es um die kontinuierliche Bereitstellung von Infrastruktur geht, scheint das Bild weniger klar zu sein und es dreht sich vieles um das Management mehrerer Umgebungen. Im Gegensatz dazu scheint das Testen, Sichern und Überprüfen des Infrastruktur-Codes schwieriger zu sein. Dies ist eines der Felder, in denen DevOps noch nicht ausgereift ist. Ein anderer Anwendungsbereich ist, die Sicherheit im Vorfeld zu kontrollieren und Sicherheitsteams sowie – was noch wichtiger ist – Sicherheitsbedenken früher in den Lebenszyklus der Bereitstellung zu integrieren und so von DevOps auf ***DevSecOps*** upzugraden.\n\nAngesichts dessen wirst du in diesem Tutorial eine einfache und doch effiziente Möglichkeit erarbeiten, DevSecOps für deine Infrastruktur zu implementieren, indem du beispielsweise Ressourcen in fünf Umgebungen bereitstellst und dich schrittweise von der Entwicklung bis zur Produktion vorarbeitest.\n\n__Hinweis:__ Auch wenn ich einen FinOps-Ansatz und eine Reduktion der Umgebungen befürworte, gibt es manchmal gute Gründe, mehr als nur Entwicklung, Staging und Produktion aufrechtzuerhalten. Bitte passe die folgenden Beispiele an deine Bedürfnisse an.\n\n## Was\n\nDer Aufstieg der Cloud-Technologie hat die Nutzung von IaC vorangetrieben. Ansible und Terraform gehörten in diesem Bereich zu den Pionieren. OpenTofu, Pulumi, AWS CDK, Google Deploy Manager und viele andere folgten.\n\nIaC gilt als perfekte Lösung, um sich bei der Bereitstellung von Infrastruktur sicher zu fühlen. Du kannst sie testen, bereitstellen und immer wieder abspielen, bis du dein Ziel erreicht hast.\n\nLeider sehen wir oft, dass Unternehmen für jede ihrer Zielumgebungen mehrere Branches oder sogar Repositories unterhalten. Und hier beginnen die Probleme. Sie setzen einen Prozess nicht mehr durch. Sie stellen nicht mehr sicher, dass Änderungen in der Produktions-Codebase in früheren Umgebungen genauestens getestet wurden. Und sie beginnen, Drifts von einer Umgebung in die andere zu erleben.\n\nMir wurde klar, dass dieses Tutorial notwendig war, als auf einer Konferenz alle Teilnehmenden sagten, dass sie keinen Workflow haben, der durchsetzt, dass Infrastruktur genau getestet wird, bevor sie für die Produktion bereitgestellt wird. Und sie waren sich alle einig, dass sie manchmal den Code direkt in die Produktion patchen. Klar geht das schnell, aber ist es auch sicher? Wie meldet man an frühere Umgebungen zurück? Wie stellt man sicher, dass es keine Nebeneffekte gibt? Wie kontrolliert man, ob man das Unternehmen in Gefahr bringt, wenn neue Sicherheitslücken zu schnell in die Produktion gepusht werden?\n\nDie Frage, *warum* DevOps-Teams direkt in die Produktion implementieren, ist hier entscheidend. Liegt es daran, dass die Pipeline effizienter oder schneller sein könnte? Gibt es keine Automatisierung? Oder, noch schlimmer, gibt es *keine Möglichkeit, außerhalb der Produktion genau zu testen*?\n\nIm nächsten Abschnitt erfährst du, wie du Automatisierung für deine Infrastruktur implementieren und sicherstellen kannst, dass dein DevOps-Team effektiv testet, bevor etwas in eine Umgebung gepusht wird, die sich auf andere auswirkt. Du wirst sehen, wie dein Code gesichert und seine Bereitstellung durchgehend kontrolliert wird.\n\n## Wie\n\nWie bereits erwähnt, gibt es heutzutage viele Programmiersprachen für IaC, und wir können ganz einfach nicht *alle* in einem einzigen Artikel behandeln. Ich werde mich also auf einen grundlegenden Terraform-Code konzentrieren, der auf Version 1.4 läuft. Bitte fixiere dich nicht auf die Programmiersprache für IaC selbst, sondern auf den Prozess, den du für dein eigenes Ökosystem umsetzen kannst.\n\n### Der Terraform-Code\n\nBeginnen wir mit einem grundlegenden Terraform-Code.\n\nWir werden auf AWS bereitstellen, eine virtuelle private Cloud (VPC), die ein virtuelles Netzwerk ist. In dieser VPC werden wir ein öffentliches und ein privates Subnetz bereitstellen. Wie der Name schon sagt, handelt es sich um Subnetze der Haupt-VPC. Abschließend fügen wir eine EC2-Instanz (Elastic Cloud Compute; eine virtuelle Maschine) zum öffentlichen Subnetz hinzu.\n\nDies zeigt, wie vier Ressourcen bereitgestellt werden können, ohne zu komplex zu werden. Die Idee ist, sich auf die Pipeline zu konzentrieren, nicht auf den Code.\n\nHier ist das Ziel, das wir für dein Repository erreichen möchten.\n\n![Ziel für Repository](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750097033415.png)\n\nGehen wir Schritt für Schritt vor.\n\nZuerst deklarieren wir alle Ressourcen in der Datei `terraform/main.tf`:\n\n```terraform\nprovider \"aws\" {\n  region = var.aws_default_region\n}\n\nresource \"aws_vpc\" \"main\" {\n  cidr_block = var.aws_vpc_cidr\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n\nresource \"aws_subnet\" \"public_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_public_subnet_cidr\n\n  tags = {\n    Name = \"Public Subnet\"\n  }\n}\nresource \"aws_subnet\" \"private_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_private_subnet_cidr\n\n  tags = {\n    Name = \"Private Subnet\"\n  }\n}\n\nresource \"aws_instance\" \"sandbox\" {\n  ami           = var.aws_ami_id\n  instance_type = var.aws_instance_type\n\n  subnet_id = aws_subnet.public_subnet.id\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n```\n\nWie du sehen kannst, sind für diesen Code einige Variablen erforderlich, die wir also in der Datei `terraform/variables.tf` deklarieren:\n\n```terraform\nvariable \"aws_ami_id\" {\n  description = \"The AMI ID of the image being deployed.\"\n  type        = string\n}\n\nvariable \"aws_instance_type\" {\n  description = \"The instance type of the VM being deployed.\"\n  type        = string\n  default     = \"t2.micro\"\n}\n\nvariable \"aws_vpc_cidr\" {\n  description = \"The CIDR of the VPC.\"\n  type        = string\n  default     = \"10.0.0.0/16\"\n}\n\nvariable \"aws_public_subnet_cidr\" {\n  description = \"The CIDR of the public subnet.\"\n  type        = string\n  default     = \"10.0.1.0/24\"\n}\n\nvariable \"aws_private_subnet_cidr\" {\n  description = \"The CIDR of the private subnet.\"\n  type        = string\n  default     = \"10.0.2.0/24\"\n}\n\nvariable \"aws_default_region\" {\n  description = \"Default region where resources are deployed.\"\n  type        = string\n  default     = \"eu-west-3\"\n}\n\nvariable \"aws_resources_name\" {\n  description = \"Default name for the resources.\"\n  type        = string\n  default     = \"demo\"\n}\n```\n\nAuf der IaC-Seite sind wir damit auch schon fast fertig. Was fehlt, ist eine Möglichkeit, die Terraform-Zustände zu teilen. Für diejenigen, die es nicht wissen: Terraform funktioniert schematisch wie folgt:\n\n* `plan` überprüft die Unterschiede zwischen dem aktuellen Status der Infrastruktur und dem, was im Code definiert ist. Dann gibt es die Unterschiede aus.\n* `apply` wendet die Unterschiede im `plan` an und aktualisiert den Status.\n\nIn der ersten Runde ist der Status leer, dann wird er mit den Details (ID usw.) der von Terraform angewendeten Ressourcen gefüllt.\n\nDas Problem ist: Wo wird dieser Zustand gespeichert? Wie können wir ihn teilen, damit mehrere Entwickler(innen) am Code zusammenarbeiten können?\n\nDie Lösung ist ziemlich einfach: Nutze GitLab, um den Status über ein [Terraform-HTTP-Backend](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html) zu speichern und freizugeben.\n\nDer erste Schritt bei der Verwendung dieses Backends besteht darin, die einfachste Datei, nämlich `terraform/backend.tf` zu erstellen. Der zweite Schritt erfolgt in der Pipeline.\n\n```terraform\nterraform {\n  backend \"http\" {\n  }\n}\n```\n\nEt voilà! Wir haben einen minimalen Terraform-Code, um diese vier Ressourcen bereitzustellen. Wir werden die Variablenwerte zur Laufzeit bereitstellen, also machen wir das später.\n\n### Der Workflow\n\nDer Workflow, den wir jetzt implementieren werden, sieht folgendermaßen aus:\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    A(main) -->|new feature| B(feature_X)\n\n    B -->|auto deploy| C[review/feature_X]\n    B -->|merge| D(main)\n    C -->|destroy| D\n\n    D -->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\n    D -->|tag| G(X.Y.Z)\n    F -->|validate| G\n\n    G -->|auto deploy| H[staging]\n    H -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\n1. Erstelle einen **Feature-Branch**. Dadurch werden alle Scanner kontinuierlich auf dem Code ausgeführt, um sicherzustellen, dass er immer konform und gesichert bleibt. Dieser Code wird kontinuierlich in der temporären Umgebung `review/feature_branch` mit dem Namen des aktuellen Branches bereitgestellt. Dies ist eine sichere Umgebung, in der die Entwickler(innen) und IT-Betriebsteams ihren Code ohne Auswirkungen auf andere testen können. Hier setzen wir auch den Prozess durch, z. B. indem Code Reviews durchgesetzt und Scanner ausgeführt werden, damit die Qualität und Sicherheit des Codes akzeptabel sind und deine Assets nicht gefährdet werden. Die von diesem Branch bereitgestellte Infrastruktur wird automatisch zerstört, wenn der Branch geschlossen wird. So behältst du dein Budget unter Kontrolle.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    A(main) -->|new feature| B(feature_X)\n\n    B -->|auto deploy| C[review/feature_X]\n    B -->|merge| D(main)\n    C -->|destroy| D\n\u003C/pre>\n\n2. Nach der Genehmigung wird der Feature-Branch mit dem Main-Branch **zusammengeführt**. Dies ist ein [geschützter Branch](https://docs.gitlab.com/ee/user/project/protected_branches.html), in den niemand pushen kann. Dies ist obligatorisch, um sicherzustellen, dass jede Änderungsanfrage an die Produktion gründlich getestet wird. Dieser Branch wird auch kontinuierlich bereitgestellt. Das Ziel hier ist die Umgebung `integration`. Damit diese Umgebung etwas stabiler bleibt, wird das Löschen nicht automatisiert, sondern kann manuell ausgelöst werden.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main) -->|auto deploy| E[integration]\n\u003C/pre>\n\n3. Von dort aus ist eine manuelle Genehmigung erforderlich, um die nächste Bereitstellung auszulösen. Dadurch wird der Haupt-Branch in der Umgebung `qa` bereitgestellt. Hier habe ich eine Regel festgelegt, um das Löschen aus der Pipeline zu verhindern. Diese Umgebung sollte ziemlich stabil sein (schließlich ist es bereits die dritte Umgebung), und ich möchte das versehentliche Löschen verhindern. Du kannst die Regeln gerne an deine Prozesse anpassen.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main)-->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\u003C/pre>\n\n4. Um fortzufahren, müssen wir den Code **taggen**. Wir setzen hier auf [geschützte Tags](https://docs.gitlab.com/ee/user/project/protected_tags.html), um sicherzustellen, dass nur eine bestimmte Gruppe von Benutzer(inne)n in diese letzten beiden Umgebungen bereitstellen darf. Dadurch wird sofort eine Bereitstellung in der Umgebung `staging` ausgelöst.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main) -->|tag| G(X.Y.Z)\n    F[qa] -->|validate| G\n\n    G -->|auto deploy| H[staging]\n\u003C/pre>\n\n\n5. Schließlich landen wir bei `production`. Wenn es um Infrastruktur geht, ist es oft schwierig, sie schrittweise bereitzustellen (10 %, 25 % usw.), sodass wir gleich die gesamte Infrastruktur bereitstellen werden. Dennoch steuern wir diese Bereitstellung, indem dieser letzte Schritt manuell ausgelöst wird. Und um maximale Kontrolle über diese hochkritische Umgebung zu erzwingen, werden wir sie als [geschützte Umgebung](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) kontrollieren.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    H[staging] -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\n### Die Pipeline\n\nUm den oben genannten [Workflow](#the-workflow) zu implementieren, implementieren wir jetzt eine Pipeline mit zwei [Downstream-Pipelines](https://docs.gitlab.com/ee/ci/pipelines/downstream_pipelines.html).\n\n#### Die Haupt-Pipeline\n\nBeginnen wir mit der Haupt-Pipeline. Dies ist diejenige, die automatisch bei jedem **Push zu einem Feature-Branch**, jedem Zusammenführen zum Standard-Branch** oder jedem **Tag** ausgelöst wird. *Die Pipeline*, die eine echte **kontinuierliche Bereitstellung** in den folgenden Umgebungen durchführt: `dev`, `integration` und `staging`. Und das wird in der Datei `.gitlab-ci.yml` im Stamm deines Projekts deklariert.\n\n![Repository-Ziel](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097033417.png)\n\n```yml\nStages:\n  - test\n  - environments\n\n.environment:\n  stage: environments\n  variables:\n    TF_ROOT: terraform\n    TF_CLI_ARGS_plan: \"-var-file=../vars/$variables_file.tfvars\"\n  trigger:\n    include: .gitlab-ci/.first-layer.gitlab-ci.yml\n    strategy: depend             # Wait for the triggered pipeline to successfully complete\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nreview:\n  extends: .environment\n  variables:\n    environment: review/$CI_COMMIT_REF_SLUG\n    TF_STATE_NAME: $CI_COMMIT_REF_SLUG\n    variables_file: review\n    TF_VAR_aws_resources_name: $CI_COMMIT_REF_SLUG  # Used in the tag Name of the resources deployed, to easily differenciate them\n  rules:\n    - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n\nintegration:\n  extends: .environment\n  variables:\n    environment: integration\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nstaging:\n  extends: .environment\n  variables:\n    environment: staging\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_TAG\n\n#### TWEAK\n# This tweak is needed to display vulnerability results in the merge widgets.\n# As soon as this issue https://gitlab.com/gitlab-org/gitlab/-/issues/439700 is resolved, the `include` instruction below can be removed.\n# Until then, the SAST IaC scanners will run in the downstream pipelines, but their results will not be available directly in the merge request widget, making it harder to track them.\n# Note: This workaround is perfectly safe and will not slow down your pipeline.\ninclude:\n  - template: Security/SAST-IaC.gitlab-ci.yml\n#### END TWEAK\n\n```\n\nDiese Pipeline läuft nur in zwei Phasen: `test` und `environments`. Erstere wird benötigt, damit der *TWEAK* Scanner ausführen kann. Zweitere löst eine untergeordnete Pipeline mit einem anderen Satz von Variablen für jeden oben definierten Fall aus (Push zum Branch, Zusammenführen zum Standard-Branch oder Tag).\n\nWir fügen hier eine Abhängigkeit mit dem Schlüsselwort [strategy:depend](https://docs.gitlab.com/ee/ci/yaml/index.html#triggerstrategy) zu unserer untergeordneten Pipeline hinzu, sodass die Pipeline-Ansicht in GitLab erst aktualisiert wird, wenn die Bereitstellung abgeschlossen ist.\n\nWie du hier sehen kannst, definieren wir einen Basisjob, [hidden](https://docs.gitlab.com/ee/ci/jobs/#hide-jobs), und erweitern ihn um bestimmte Variablen und Regeln, um nur eine Bereitstellung für jede Zielumgebung auszulösen.\n\nNeben den [vordefinierten Variablen](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) verwenden wir zwei neue Einträge, die wir definieren müssen:\n1. [Die für jede Umgebung spezifischen Variablen](#the-variable-definitions): `../vars/$variables_file.tfvars`\n2. [Die untergeordnete Pipeline](#the-child-pipeline), definiert in `.gitlab-ci/.first-layer.gitlab-ci.yml`\n\nBeginnen wir mit dem kleinsten Teil, den Variablendefinitionen.\n\n### Die Variablendefinitionen\n\nWir werden hier zwei Lösungen mischen, um Terraform Variablen zur Verfügung zu stellen:\n\n* Die erste nutzt [.tfvars-Dateien](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files) für alle nicht sensiblen Eingaben, die in GitLab gespeichert werden sollten.\n\n![Lösung 1 zur Bereitstellung von Variablen für Terraform](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750097033419.png)\n\n* Die zweite verwendet [Umgebungsvariablen](https://developer.hashicorp.com/terraform/language/values/variables#environment-variables) mit dem Präfix `TF_VAR`. Diese zweite Möglichkeit, Variablen zu injizieren, die mit der GitLab-Fähigkeit verbunden sind, [Variablen zu maskieren](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable), [sie zu schützen](https://docs.gitlab.com/ee/ci/variables/#protect-a-cicd-variable) und [sie in Umgebungen zu übertragen](https://docs.gitlab.com/ee/ci/environments/index.html#limit-the-environment-scope-of-a-cicd-variable), ist eine leistungsstarke Lösung, um **Datenlecks sensibler Informationen zu verhindern**. (Wenn du das private CIDR deiner Produktion als sehr sensibel betrachtest, könntest du es so schützen, indem du sicherstellst, dass es nur für die Umgebung `production` verfügbar ist, für Pipelines, die gegen geschützte Branches und Tags ausgeführt werden, und dass sein Wert in den Protokollen des Jobs maskiert ist.)\n\n![Lösung 2 zur Bereitstellung von Variablen für Terraform](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750097033422.png)\n\nDarüber hinaus sollte jede Variablendatei über eine [Datei `CODEOWNERS`](https://docs.gitlab.com/ee/user/project/codeowners/) gesteuert werden, um festzulegen, wer sie ändern darf.\n\n```\n[Production owners] \nvars/production.tfvars @operations-group\n\n[Staging owners]\nvars/staging.tfvars @odupre @operations-group\n\n[CodeOwners owners]\nCODEOWNERS @odupre\n```\n\nDieser Artikel ist kein Terraform-Training, daher halten wir das kurz und zeigen hier einfach die Datei `vars/review.tfvars`. Die nachfolgenden Umgebungsdateien sind sich natürlich sehr ähnlich. Lege hier einfach die nicht-sensiblen Variablen und ihre Werte fest.\n\n```shell\naws_vpc_cidr = \"10.1.0.0/16\"\naws_public_subnet_cidr = \"10.1.1.0/24\"\naws_private_subnet_cidr = \"10.1.2.0/24\"\n```\n\n#### Die untergeordnete Pipeline\n\nHier wird die eigentliche Arbeit erledigt. Sie ist also etwas komplexer als die erste Pipeline. Es gibt aber auch hier keine Schwierigkeit, die wir nicht gemeinsam überwinden können!\n\nWie wir bei der Definition der [Haupt-Pipeline](#the-main-pipeline) gesehen haben, wird diese Downstream-Pipeline in der Datei `.gitlab-ci/.first-layer.gitlab-ci.yml` deklariert.\n\n![In Datei deklarierte Downstream-Pipeline](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750097033424.png)\n\nZerlegen wir sie in kleine Stücke. Am Ende sehen wir dann das große Ganze.\n\n##### Terraform-Befehle ausführen und den Code sichern\n\nZuerst wollen wir eine Pipeline für Terraform ausführen. GitLab ist Open Source. Unsere Terraform-Vorlage ist also auch Open Source. Du kannst sie einfach einbeziehen. Dies erreichst du mit folgendem Code-Schnipsel:\n\n```yml\ninclude:\n  - template: Terraform.gitlab-ci.yml\n```\n\nDiese Vorlage führt für dich die Terraform-Prüfungen für die Formatierung durch und validiert deinen Code, bevor er geplant und angewendet wird. Es ermöglicht dir auch, das zu zerstören, was du bereitgestellt hast.\n\nDa GitLab eine vereinheitlichte DevSecOps-Plattform ist, fügen wir dieser Vorlage automatisch zwei Sicherheitsscanner hinzu, um potenzielle Bedrohungen in deinem Code zu finden und dich zu warnen, bevor du ihn in den nächsten Umgebungen bereitstellst.\n\nJetzt, da wir unseren Code überprüft, gesichert, erstellt und bereitgestellt haben, folgen ein paar Tricks.\n\n##### Zwischenspeicher zwischen Jobs teilen\n\nWir werden Job-Ergebnisse zwischenspeichern, um sie in folgenden Pipeline-Jobs wiederzuverwenden. Dies ist einfach, denn du musst nur den folgenden Code hinzufügen:\n\n```yml\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n\n```\n\nHier definieren wir einen anderen Zwischenspeicher für jeden Commit und greifen bei Bedarf auf den Namen des Haupt-Branchs zurück.\n\nWenn wir uns die Vorlagen, die wir verwenden, genau ansehen, stellen wir fest, dass sie einige Regeln haben, die zu kontrollieren sind, wenn Jobs ausgeführt werden. Wir wollen alle Kontrollen (sowohl QA als auch Sicherheit) in allen Branchen ausführen. Wir werden diese Einstellungen also überschreiben.\n\n##### Kontrollen in allen Branches ausführen\n\nGitLab-Vorlagen sind eine leistungsstarke Funktion, bei der man auch nur einen Teil der Vorlage überschreiben kann. Hier wollen wir die Regeln einiger Jobs überschreiben, um immer Qualitäts- und Sicherheitskontrollen durchzuführen. Alles andere, was für diese Jobs definiert ist, bleibt wie in der Vorlage definiert.\n\n```yml\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - when: always\n\niac-sast:\n  rules:\n    - when: always\n```\n\nDa wir nun die Qualitäts- und Sicherheitskontrollen durchgesetzt haben, wollen wir unterscheiden, wie sich die Hauptumgebungen (Integration und Staging) im [Workflow](#the-workflow) und Review-Umgebungen verhalten. Beginnen wir mit der Definition des Verhaltens der Hauptumgebung. Wir werden dann diese Konfiguration für die Review-Umgebungen optimieren.\n\n##### CD für Integration und Staging\n\nWie zuvor definiert, möchten wir den Haupt-Branch und die Tags in diesen beiden Umgebungen bereitstellen. Wir fügen Regeln hinzu, um das sowohl bei den Jobs `build` als auch `deploy` zu kontrollieren. Dann wollen wir `destroy` nur für `integration` aktivieren, da wir definiert haben, dass `staging` zu kritisch ist, um mit einem einzigen Klick gelöscht zu werden. Das ist fehleranfällig, was wir nicht wollen.\n\nSchließlich verknüpfen wir den Job `deploy` mit dem Job `destroy`, damit wir die Umgebung direkt von der GitLab-GUI aus mit `stop` stoppen können.\n\nDie `GIT_STRATEGY` soll verhindern, dass der Code beim Zerstören aus dem Quell-Branch im Runner abgerufen wird. Dies würde fehlschlagen, wenn der Branch manuell gelöscht wurde. Daher verlassen wir uns auf den Zwischenspeicher, um alles zu erhalten, was wir zum Ausführen der Terraform-Anweisungen benötigen.\n\n```yml\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually\n  environment: \n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n```\n\nWie gesagt müssen diese Matches in `integration` und `staging` bereitstellen. Uns fehlt jedoch immer noch eine temporäre Umgebung, in der die Entwickler(innen) ihren Code ohne Auswirkungen auf andere erleben und validieren können. Hier findet die Bereitstellung in der Umgebung `review` statt.\n\n##### CD für Review-Umgebungen\n\nDie Bereitstellung in der Review-Umgebung unterscheidet sich nicht allzu sehr von der Bereitstellung in `integration` und `staging`. Wir werden also erneut die Möglichkeit von GitLab nutzen, hier nur Teile der Jobdefinition zu überschreiben.\n\nZuerst legen wir Regeln fest, um diese Jobs nur in Feature-Branches auszuführen.\n\nDann verknüpfen wir den Job `deploy_review` mit `destroy_review`. Dies ermöglicht es uns, die Umgebung **manuell** von der GitLab-Bedienoberfläche aus zu stoppen und – was noch wichtiger ist – es wird **automatisch die Zerstörung der Umgebung ausgelöst**, wenn der Feature-Branch geschlossen wird. Dies ist eine gute FinOps-Praxis, um dir zu helfen, deine Betriebsausgaben zu kontrollieren.\n\nDa Terraform eine Plandatei benötigt, um eine Infrastruktur zu zerstören (genau wie es eine solche Datei benötigt, um eine Infrastruktur aufzubauen), fügen wir eine Abhängigkeit von `destroy_review` zu `build_review` hinzu, um Artefakte abzurufen.\n\nSchließlich sehen wir hier, dass der Name der Umgebung auf `$environment` festgelegt ist. Es wurde in der [Haupt-Pipeline](#the-main-pipeline) auf `review/$CI_COMMIT_REF_SLUG` gesetzt und mit der Anweisung `trigger:forward:yaml_variables:true` an diese untergeordnete Pipeline weitergeleitet.\n\n```yml\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n```\n\nZusammenfassend können wir also sagen, dass wir jetzt eine Pipeline haben, die Folgendes kann:\n\n* Temporäre Review-Umgebungen bereitstellen, die automatisch gelöscht werden, wenn der Feature-Branch geschlossen wird\n* Den **Standard-Branch** kontinuierlich auf `integration` bereitstellen\n* Die **Tags** kontinuierlich auf `staging` bereitstellen\n\nFügen wir nun eine zusätzliche Ebene hinzu, auf der wir diesmal mit einem manuellen Auslöser in den Umgebungen `qa` und `production` bereitstellen werden.\n\n##### Kontinuierliche Bereitstellung in QA und Produktion\n\nDa nicht jedes Unternehmen kontinuierlich in der Produktion bereitstellen möchte, fügen wir den nächsten beiden Bereitstellungen eine manuelle Validierung hinzu. Aus einer reinen **CD**-Perspektive würden wir diesen Auslöser nicht hinzufügen, aber betrachte dies als Gelegenheit, zu lernen, wie man Jobs von anderen Auslösern aus ausführt.\n\nBisher haben wir eine [untergeordnete Pipeline](#the-child-pipeline) aus der [Haupt-Pipeline](#the-main-pipeline) gestartet, um alle Bereitstellungen auszuführen.\n\nDa wir andere Bereitstellungen aus dem Standard-Branch und den Tags ausführen möchten, fügen wir eine weitere Ebene für diese zusätzlichen Schritte hinzu. Hier gibt es nichts Neues. Wir wiederholen einfach genau das, was wir nur für die [Haupt-Pipeline](#the-main-pipeline) gemacht haben. Auf diese Weise kannst du so viele Ebenen bearbeiten, wie du brauchst. Ich habe schon einmal bis zu neun Umgebungen gesehen.\n\nWir wollen hier nicht über die Vorteile diskutieren, die es mit sich bringt, weniger Umgebungen zu haben. Der hier verwendete Prozess macht es jedenfalls sehr einfach, die gleiche Pipeline von der Anfangsphase bis zur endgültigen Lieferung zu implementieren, während deine Pipeline-Definition einfach und in kleine, einfach zu wartende Teile aufgeteilt bleibt.\n\nUm hier Variablenkonflikte zu vermeiden, verwenden wir nur neue Variablennamen, um den Terraform-Status und die Eingabedatei zu identifizieren.\n\n```yml\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Andernfalls schlagen alle Pipelines fehl, wenn eine Pipeline-Zeitüberschreitung vor der Bereitstellung auf die 2. Ebene erreicht wurde.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n```\n\n**Ein wichtiger Trick ist hier die Strategie, die für die neue Downstream-Pipeline verwendet wird.** Wir belassen `trigger:strategy` auf ihrem Standardwert. Andernfalls würde die [Haupt-Pipeline](#the-main-pipeline) warten, bis deine [Pipeline der zweiten Ebene](#the-grand-child-pipeline) abgeschlossen ist. Bei einem manuellen Auslöser kann dies sehr lange dauern und das Lesen und Verstehen deines Pipeline-Dashboards erschweren.\n\nDu hast dich wahrscheinlich schon gefragt, was der Inhalt der Datei `.gitlab-ci/.second-layer.gitlab-ci.yml` ist, die wir hier anführen. Wir gehen im nächsten Abschnitt darauf ein.\n\n##### Vollständige Pipeline-Definition auf der ersten Ebene\n\nWenn du eine vollständige Ansicht dieser ersten Ebene möchtest (gespeichert in `.gitlab-ci/.first-layer.gitlab-ci.yml`), erweitere einfach den Abschnitt unten.\n\n```yml\nvariables:\n  TF_VAR_aws_ami_id: $AWS_AMI_ID\n  TF_VAR_aws_instance_type: $AWS_INSTANCE_TYPE\n  TF_VAR_aws_default_region: $AWS_DEFAULT_REGION\n\ninclude:\n  - template: Terraform.gitlab-ci.yml\n\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n  - cleanup\n  - 2nd_layer       # Use to deploy a 2nd environment on both the main branch and on the tags\n\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\niac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\n###########################################################################################################\n## Integration env. and Staging. env\n##  * Auto-deploy to Integration on merge to main.\n##  * Auto-deploy to Staging on tag.\n##  * Integration can be manually destroyed if TF_DESTROY is set to true.\n##  * Destroy of next env. is not automated to prevent errors.\n###########################################################################################################\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually\n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n###########################################################################################################\n\n###########################################################################################################\n## Dev env.\n##  * Temporary environment. Lives and dies with the Merge Request.\n##  * Auto-deploy on push to feature branch.\n##  * Auto-destroy on when Merge Request is closed.\n###########################################################################################################\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n###########################################################################################################\n\n###########################################################################################################\n## Second layer\n##  * Deploys from main branch to qa env.\n##  * Deploys from tag to production.\n###########################################################################################################\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n###########################################################################################################\n```\n\nIn dieser Phase stellen wir bereits sicher in drei Umgebungen bereit. Das ist meine persönliche Idealempfehlung. Wenn du jedoch mehr Umgebungen benötigst, füge diese deiner CD-Pipeline hinzu.\n\nDu hast sicherlich schon bemerkt, dass wir eine Downstream-Pipeline mit dem Stichwort `trigger:include` einbinden. Dazu gehört die Datei `.gitlab-ci/.second-layer.gitlab-ci.yml`. Da wir fast die gleiche Pipeline ausführen wollen, ist ihr Inhalt offensichtlich sehr ähnlich zu dem, den wir oben detailliert beschrieben haben. Der Hauptvorteil bei der Definition dieser [Pipeline der zweiten Ebene](#the-grand-child-pipeline) ist, dass sie allein besteht, was die Definition von Variablen und Regeln erleichtert.\n\n### Die Pipeline der zweiten Ebene\n\nDiese Pipeline der zweiten Ebene ist eine brandneue Pipeline. Daher muss es die Definition der ersten Ebene nachahmen mit:\n\n* [Aufnahme der Terraform-Vorlage](#run-terraform-commands-and-secure-the-code).\n* [Durchsetzung von Sicherheitskontrollen](#run-controls-on-all-branches). Bei der Terraform-Validierung handelt es sich um Duplikate der ersten Ebene. Sicherheitsscanner können jedoch Bedrohungen finden, die noch nicht vorhanden waren, als die Scanner zuvor ausgeführt wurden (z. B. wenn du einige Tage nach der Bereitstellung im Staging in der Produktion bereitstellst).\n* [Überschreiben von Build- und Bereitstellungs-Jobs, um spezifische Regeln festzulegen](#cd-to-review-environments). Beachte bitte, dass die Phase `destroy` nicht mehr automatisiert ist, um zu schnelle Löschvorgänge zu verhindern.\n\nWie oben erläutert, wurden `TF_STATE_NAME` und `TF_CLI_ARGS_plan` von der [Haupt-Pipeline](# the-main-pipeline) zur [untergeordneten Pipeline](#the-child-pipeline) bereitgestellt. Wir brauchten einen weiteren Variablennamen, um diese Werte von der [untergeordneten Pipeline](#the-child-pipeline) hierher, also an die [Pipeline der zweiten Ebene](#the-grand-child-pipeline), zu übergeben. Deshalb werden sie in der untergeordneten Pipeline mit dem Postfix `_2` versehen und der Wert wird während des `before_script` hier zurück in die entsprechende Variable kopiert.\n\nDa wir oben bereits jeden Schritt aufgeschlüsselt haben, können wir hier direkt auf die breite Ansicht der globalen Definition der zweiten Ebene zoomen (gespeichert in `.gitlab-ci/.second-layer.gitlab-ci.yml`).\n\n```yml\n# Use to deploy a second environment on both the default branch and the tags.\n\ninclude:\n  template: Terraform.gitlab-ci.yml\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n\nfmt:\n  rules:\n    - when: never\n\nvalidate:\n  rules:\n    - when: never\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: always\n\n###########################################################################################################\n## QA env. and Prod. env\n##  * Manually trigger build and auto-deploy in QA\n##  * Manually trigger both build and deploy in Production\n##  * Destroy of these env. is not automated to prevent errors.\n###########################################################################################################\nbuild:  # terraform plan\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment:\n    name: $TF_STATE_NAME_2\n    action: prepare\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - when: manual\n\ndeploy: # terraform apply\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment: \n    name: $TF_STATE_NAME_2\n    action: start\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG && $TF_AUTO_DEPLOY == \"true\"\n    - if: $CI_COMMIT_TAG\n      when: manual\n###########################################################################################################\n```\n\nEt voilà. **Wir sind bereit.** Du kannst die Art und Weise ändern, wie du deine Jobausführungen kontrollierst, indem du bspw. die Möglichkeit von GitLab nutzt, [einen Job zu verzögern](https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay), bevor du ihn in der Produktion bereitstellst.\n\n## Probiere es selbst\n\nWir haben endlich unser Ziel erreicht. Wir sind jetzt in der Lage, **Bereitstellungen in fünf verschiedenen Umgebungen** zu kontrollieren, wobei nur die **Feature-Branches**, der **Haupt-Branch** und **Tags** verwendet werden.\n* Wir verwenden Open-Source-Vorlagen von GitLab intensiv wieder, um Effizienz und Sicherheit in unseren Pipelines zu gewährleisten.\n* Wir nutzen GitLab-Vorlagen, um nur die Blöcke zu überschreiben, die eine benutzerdefinierte Kontrolle benötigen.\n* Wir haben die Pipeline in kleine Teile aufgeteilt und kontrollieren die Downstream-Pipelines so, dass sie genau dem entsprechen, was wir brauchen.\n\nAb hier gehört die Bühne ganz dir. Du kannst beispielsweise die Haupt-Pipeline einfach aktualisieren, um Downstream-Pipelines für deinen Software-Quellcode mit dem Schlüsselwort [trigger:rules:changes](https://docs.gitlab.com/ee/ci/yaml/#ruleschanges) auszulösen. Und verwende je nach den aufgetretenen Änderungen eine andere [Vorlage](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/). Aber das ist eine andere Geschichte.",[109,9,684,757,685],"2024-11-05",{"slug":848,"featured":6,"template":689},"using-child-pipelines-to-continuously-deploy-to-five-environments","content:de-de:blog:using-child-pipelines-to-continuously-deploy-to-five-environments.yml","Using Child Pipelines To Continuously Deploy To Five Environments","de-de/blog/using-child-pipelines-to-continuously-deploy-to-five-environments.yml","de-de/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"_path":854,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":855,"content":861,"config":867,"_id":869,"_type":14,"title":870,"_source":16,"_file":871,"_stem":872,"_extension":19},"/de-de/blog/basics-of-gitlab-ci-updated",{"title":856,"description":857,"ogTitle":856,"ogDescription":857,"noIndex":6,"ogImage":858,"ogUrl":859,"ogSiteName":673,"ogType":674,"canonicalUrls":859,"schema":860},"Grundlagen der GitLab-CI-Pipeline: Aufgaben sequenziell parallel oder ohne Reihenfolge ausführen","Neu in der Continuous Integration? Erfahre, wie du deine erste CI-Pipeline mit GitLab erstellst.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662061/Blog/Hero%20Images/cicdcover.png","https://about.gitlab.com/blog/basics-of-gitlab-ci-updated","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Grundlagen der GitLab-CI-Pipeline: Aufgaben sequenziell parallel oder ohne Reihenfolge ausführen\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Itzik Gan Baruch\"}],\n        \"datePublished\": \"2020-12-10\",\n      }",{"title":856,"description":857,"authors":862,"heroImage":858,"date":864,"body":865,"category":682,"tags":866,"updatedDate":686},[863],"Itzik Gan Baruch","2020-12-10","Nehmen wir an, dass du nichts über [kontinuierliche Integration\n(CI)](/topics/ci-cd/) and [why it's\nneeded](/blog/how-to-keep-up-with-ci-cd-best-practices/) weißt\nund darüber, warum sie im Lebenszyklus der Softwareentwicklung benötigt\nwird.\n\n\n## Inhaltsverzeichnis\n\n- [Der erste Test in CI](#der-erste-test-in-ci)\n\n- [Ergebnisse von Builds zum Herunterladen\nbereitstellen](#ergebnisse-von-builds-zum-herunterladen-bereitstellen)\n\n- [Aufträge der Reihe nach ausführen](#aufträge-der-reihe-nach-ausführen)\n\n- [Welches Docker Image muss verwendet\nwerden?](#welches-docker-image-muss-verwendet-werden%3F)\n\n- [Umgang mit komplexen Szenarien](#umgang-mit-komplexen-szenarien)\n\n- [Umgang mit fehlender\nSoftware/Paketen](#umgang-mit-fehlender-softwarepaketen)\n\n- [Directed Acyclic Graphs: Schnellere und flexiblere\nPipelines](#directed-acyclic-graphs-schnellere-und-flexiblere-pipelines)\n\n- [Wie wertest du deine Pipeline\nauf?](#wie-wertest-du-deine-pipeline-auf%3F)\n  - [Automatisierte Tests in CI-Pipelines einbinden](#automatisierte-tests-in-ci-pipelines-einbinden)\n  - [Matrix-Builds](#matrix-builds)\n- [Unit-Tests](#unit-tests)\n  - [Was sind Unit-Tests?](#was-sind-unit-tests%3F)\n  - [Best Practices für Unit-Tests](#best-practices-für-unit-tests)\n    - [JUnit Test-Report](#junit-test-report)\n- [Strategien für Integrations- und\nEnd-to-End-Tests](#strategien-für-integrations--und-end-to-end-tests)\n\n- [Testumgebung](#testumgebung)\n\n- [Implementierung von Sicherheitsscans in\nCI-Pipelines](#implementierung-von-sicherheitsscans-in-ci-pipelines)\n  - [SAST und DAST-Integration](#sast-und-dast-integration)\n- [Zusammenfassung](#zusammenfassung)\n\n- [Beschreibungen der Keywords](#beschreibungen-der-keywords)\n\n\nStell dir vor, du arbeitest an einem Projekt, bei dem der gesamte Code aus\nzwei Textdateien besteht. Dabei ist es sehr wichtig, dass die Verkettung\ndieser beiden Dateien die Phrase „Hello world\" enthält.\n\n\nWenn das nicht der Fall ist, wird das gesamte Development-Team in diesem\nMonat nicht bezahlt. Ja, so ernst ist es!\n\n\nDer oder die verantwortliche Softwareentwickler(in) hat ein kleines Skript\ngeschrieben, das jedes Mal ausgeführt wird, wenn wir unseren Code an die\nKunden senden wollen.\n\n\nDer Code ist ziemlich komplex:\n\n\n```bash\n\ncat file1.txt file2.txt | grep -q \"Hello world\"\n\n```\n\n\nDas Problem ist, dass das Team aus 10 Entwickler(inne)n besteht. Da bleiben\nmenschliche Fehler nicht aus.\n\n\nVor einer Woche vergaß einer der Mitarbeiter(innen), das Skript auszuführen,\nund drei Kund(inn)en erhielten fehlerhafte Builds. Also hast du beschlossen,\ndieses Problem endgültig zu lösen. Glücklicherweise befindet sich der Code\nbereits auf GitLab, und du erinnerst dich, dass es eine [integrierte\nCI](/de-de/solutions/continuous-integration/) gibt. Zudem hast du auf einer\nKonferenz gehört, dass viele Entwickler(innen) eine CI verwenden, um Tests\ndurchzuführen...\n\n\n## Der erste Test in CI\n\n\nNach ein paar Minuten Suche und Lesen der Dokumentation scheint es, dass wir\nnur diese zwei Codezeilen benötigen, die wir in einer Datei namens\n.gitlab-ci.yml finden:\n\n\n```yaml\n\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n```\n\n\nWir übertragen die Zeilen, und siehe da– unser Build ist erfolgreich:\n\n\n![build\nsucceeded](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/build_succeeded.png)\n\n\nNun ändern wir in der zweiten Datei \"World\" zu \"Africa\" und prüfen, was\npassiert:\n\n\n![build\nfailed](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/build_failed.png)\n\n\nDer Build schlägt wie erwartet fehl!\n\n\nNun haben wir hier automatisierte Tests! GitLab CI führt unser Testskript\njedes Mal aus, wenn wir neuen Code in das Quellcode-Repository in der\nDevOps-Umgebung übertragen.\n\n\n**Hinweis:** Im obigen Beispiel gehen wir davon aus, dass file1.txt und\nfile2.txt auf dem Runner-Host vorhanden sind.\n\n\nUm dieses Beispiel in GitLab auszuführen, verwende den folgenden Code, der\nzunächst die Dateien erstellt und dann das Skript ausführt.\n\n\n```yaml\n\ntest:\n\nbefore_script:\n      - echo \"Hello \" > | tr -d \"\\n\" | > file1.txt\n      - echo \"world\" > file2.txt\nscript: cat file1.txt file2.txt | grep -q 'Hello world'\n\n```\n\n\nAus Gründen der Übersichtlichkeit gehen wir davon aus, dass diese Dateien\nauf dem Host vorhanden sind und werden sie in den folgenden Beispielen nicht\nerstellen.\n\n\n## Ergebnisse von Builds zum Herunterladen bereitstellen\n\n\nDie nächste Anforderung besteht darin, den Code zu paketieren, bevor wir ihn\nan unsere Kunden senden. Lass uns auch diesen Teil des\nSoftwareentwicklungsprozesses automatisieren!\n\n\nAlles, was wir machen müssen, ist, einen weiteren Job für CI zu definieren.\nNennen wir den Auftrag mal „Package\":\n\n\n```yaml\n\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  script: cat file1.txt file2.txt | gzip > package.gz\n```\n\n\nNun haben wir zwei Tabs:\n\n\n![Two tabs - generated from two\njobs](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/two_tabs.png)\n\n\nWir haben jedoch vergessen anzugeben, dass die neue Datei ein Build-Artefakt\nist, damit sie heruntergeladen werden kann. Wir können dies beheben, indem\nwir einen Abschnitt für Artifacts hinzufügen:\n\n\n```yaml\n\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  script: cat file1.txt file2.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\n\nChecking... it is there:\n\n\n![Checking the download\nbutton](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/artifacts.png)\n\n\nSo klappt's. Wir haben jedoch noch ein Problem zu lösen: Die Aufträge laufen\nparallel, aber wir wollen unsere Anwendung nicht paketieren, wenn unsere\nTests fehlschlagen.\n\n\n## Aufträge der Reihe nach ausführen\n\n\nDer Auftrag „Paket\" soll nur ausgeführt werden, wenn die Tests erfolgreich\nsind. Definieren wir die Reihenfolge, indem wir stages angeben:\n\n\n```yaml\n\nstages:\n  - test\n  - package\n\ntest:\n  stage: test\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  stage: package\n  script: cat file1.txt file2.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\n\nDas sollte funktionieren!\n\nAußerdem haben wir vergessen zu erwähnen, dass die Zusammenstellung (die in\nunserem Fall durch Verkettung dargestellt wird) eine Weile dauert, sodass\nwir sie nicht zweimal ausführen wollen. Definieren wir also einen separaten\nSchritt dafür:\n\n\n```yaml\n\nstages:\n  - compile\n  - test\n  - package\n\ncompile:\n  stage: compile\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n\ntest:\n  stage: test\n  script: cat compiled.txt | grep -q 'Hello world'\n\npackage:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\n\nLass uns jetzt auf unsere Artifacts an:\n\n\n![Unnecessary\nartifact](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/clean-artifacts.png)\n\n\nWir brauchen diese „Kompilierungsdatei\" nicht zum Herunterladen. Deshalb\nlassen wir unsere temporären Artefakte ablaufen, indem wir expire_in auf „20\nMinuten\" setzen:\n\n\n```yaml\n\ncompile:\n  stage: compile\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n    expire_in: 20 minutes\n```\n\n\nJetzt sieht unsere Konfiguration ziemlich beeindruckend aus:\n\n\n- Wir haben drei aufeinanderfolgende Phasen zum Kompilieren, Testen und\nPaketieren unserer Anwendung.\n\n- Wir übergeben die kompilierte Anwendung an die nächsten Stufen, damit die\nKompilierung nicht zweimal ausgeführt werden muss (und somit schneller\nläuft).\n\n- Wir speichern eine paketierte Version unserer Anwendung in\nBuild-Artefakten für die weitere Verwendung.\n\n\n## Welches Docker Image muss verwendet werden?\n\n\nEs scheint, dass unsere Builds immer noch langsam sind. Werfen wir einen\nBlick auf die Protokolle.\n\n\n![ruby3.1](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/ruby-31.png)\n\n\nWas ist Ruby 3.1?\n\n\nGitLab.com verwendet Docker-Images, um unsere\n[Builds](/blog/shared-runners/) auszuführen, und\n[standardmäßig](https://docs.gitlab.com/ee/user/gitlab_com/#shared-runners)\nwird das [`ruby:3.1`](https://hub.docker.com/_/ruby/)-Image verwendet.\nDieses Image enthält natürlich viele Pakete, die wir nicht brauchen. Nach\neiner Minute des Googlens finden wir heraus, dass es ein Image namens\n[`alpine`](https://hub.docker.com/_/alpine/) gibt, das ein fast leeres\nLinux-Image ist.\n\n\nWir geben also explizit an, dass wir dieses Image verwenden wollen, indem\nwir image: alpine` to `.gitlab-ci.yml`.\n\n\nWir haben so drei Minuten gespart:\n\n\n![Build speed\nimproved](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/speed.png)\n\n\nEs sieht so aus, als gäbe es viele öffentliche Images:\n\n- [mysql](https://hub.docker.com/_/mysql/)\n\n- [Python](https://hub.docker.com/_/python/)\n\n- [Java](https://hub.docker.com/_/java/)\n\n- [php](https://hub.docker.com/_/php/)\n\n\nWir können also einfach eines für unseren Technologie-Stack nehmen. Es ist\nsinnvoll, ein Image anzugeben, das keine zusätzliche Software enthält, da\ndies die Downloadzeit verringert.\n\n\n## Umgang mit komplexen Szenarien\n\n\nNehmen wir nun aber an, wir haben neue Kund(inn)en, die möchten, dass wir\nunsere Anwendung in ein .iso-Image statt in ein .gz-Image packen. ISO-Images\nkönnen mit dem Befehl\n[mkisofs](http://www.w3big.com/linux/linux-comm-mkisofs.html) erstellt\nwerden. Da CI die ganze Arbeit erledigt, können wir einfach einen weiteren\nJob hinzufügen. Darauf basierend sollte unsere Konfiguration so aussehen:\n\n\n```yaml\n\nimage: alpine\n\n\nstages:\n  - compile\n  - test\n  - package\n\n# ... \"compile\" and \"test\" jobs are skipped here for the sake of compactness\n\n\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\n\nBeachte, dass die Auftragsnamen nicht unbedingt gleich sein sollten. Wären\nsie identisch, wäre es nicht möglich, die Aufträge innerhalb derselben Phase\ndes Softwareentwicklungsprozesses parallel laufen zu lassen. Sollte es daher\ndoch mal vorkommen, kannst du das getrost als Zufall betrachten.\n\n\nWie dem auch sei, zurück zu unserem Job, da läuft es nicht recht rund – der\nBuild schlägt fehl:\n\n\n![Failed build because of missing\nmkisofs](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/mkisofs.png)\n\n\n`mkisofs` ist nicht im `alpine` Image mit dabei, also müssenw ir es erstmal\ninstallieren.\n\n\n## Umgang mit fehlender Software/Paketen\n\n\nLaut der [Alpine Linux\nwebsite](https://pkgs.alpinelinux.org/contents?file=mkisofs&path=&name=&branch=edge&repo=&arch=)\nist mkisofs Teil der Pakete xorriso und cdrkit. Dies sind die Befehle, die\nwir ausführen müssen, um ein Paket zu installieren:\n\n\n```bash\n\necho \"ipv6\" >> /etc/modules  # enable networking\n\napk update                   # update packages list\n\napk add xorriso              # install package\n\n```\n\n\nFür CI sind dies die gleichen Befehle wie für alle anderen. Die vollständige\nListe der Befehle, die wir dem Skriptabschnitt übergeben müssen, sollte wie\nfolgt aussehen:\n\n\n```yml\n\nscript:\n\n- echo \"ipv6\" >> /etc/modules\n\n- apk update\n\n- apk add xorriso\n\n- mkisofs -o ./packaged.iso ./compiled.txt\n\n```\n\n\nUm es jedoch semantisch korrekt zu machen, sollten wir die Befehle, die sich\nauf die Paketinstallation beziehen, in before_script unterbringen. Beachte,\ndass, wenn du before_script auf der obersten Ebene einer Konfiguration\nverwendest, die Befehle vor allen Aufträgen ausgeführt werden. In unserem\nFall wollen wir nur, dass sie vor einem bestimmten Auftrag ausgeführt\nwerden.\n\n\n## Directed Acyclic Graphs: Schnellere und flexiblere Pipelines\n\n\nWir haben die Stufen so definiert, dass die Paketaufgaben nur ausgeführt\nwerden, wenn die Tests bestanden wurden. Was aber, wenn wir die\nPhasenabfolge ein wenig aufbrechen und einige Aufträge früher ausführen\nwollen, auch wenn sie in einer späteren Phase definiert sind? In einigen\nFällen kann die herkömmliche Phasenabfolge die Gesamtausführungszeit der\nPipeline verlangsamen.\n\n\nStell dir vor, dass unsere Testphase einige umfangreichere Tests enthält,\nderen Ausführung viel Zeit in Anspruch nimmt und diese Tests nicht unbedingt\nmit den Paketaufgaben zusammenhängen. In diesem Fall wäre es effizienter,\nwenn die Paketaufgaben nicht auf den Abschluss dieser Tests warten müssten,\nbevor sie beginnen können. An dieser Stelle kommen Directed Acyclic Graphs\n(DAG) ins Spiel: Um die Phasenreihenfolge für bestimmte Aufträge zu\nunterbrechen, kannst du Abhängigkeiten von Aufgaben definieren, die die\nreguläre Phasenreihenfolge übergehen.\n\n\nGitLab verfügt über ein spezielles Keyword „needs\", das Abhängigkeiten\nzwischen Aufträgen schafft und es ermöglicht, Aufträge früher auszuführen,\nsobald ihre abhängigen Aufträge abgeschlossen sind.\n\n\nIm folgenden Beispiel werden die Paketaufgaben ausgeführt, sobald der\nTestjob abgeschlossen ist. Wenn also in Zukunft jemand weitere Tests in der\nTestphase hinzufügt, beginnen die Paketjobs zu laufen, bevor die neuen\nTestjobs abgeschlossen sind\n\n\n```yaml\n\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  before_script:\n  - echo \"ipv6\" >> /etc/modules\n  - apk update\n  - apk add xorriso\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\n\nUnsere finale Version von: `.gitlab-ci.yml`:\n\n\n```yaml\n\nimage: alpine\n\n\nstages:\n  - compile\n  - test\n  - package\n\ncompile:\n  stage: compile\n  before_script:\n      - echo \"Hello  \" | tr -d \"\\n\" > file1.txt\n      - echo \"world\" > file2.txt\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n    expire_in: 20 minutes\n\ntest:\n  stage: test\n  script: cat compiled.txt | grep -q 'Hello world'\n\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  before_script:\n  - echo \"ipv6\" >> /etc/modules\n  - apk update\n  - apk add xorriso\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\n\nWir haben gerade eine Pipeline erstellt! Wir haben drei sequenzielle Stufen,\ndie Aufträge `pack-gz` und `pack-iso` innerhalb der package-Stufe laufen\nparallel:\n\n\n![Pipelines\nillustration](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/pipeline.png)\n\n\n## Wie wertest du deine Pipeline auf?\n\n\nSo kannst du deine Pipeline aufwerten.\n\n\n### Automatisierte Tests in CI-Pipelines einbinden\n\n\nEine wichtige Regel der DevOps-Strategie für die Softwareentwicklung besteht\ndarin, wirklich großartige Anwendungen mit erstaunlicher Benutzererfahrung\nzu entwickeln. Fügen wir also einige Tests in unsere CI-Pipeline ein, um\nFehler frühzeitig im gesamten Prozess zu erkennen. Auf diese Weise können\nwir Probleme beheben, bevor sie zu groß werden und bevor wir an einem neuen\nProjekt weiterarbeiten.\n\n\nGitLab macht uns das Leben leichter, indem es fertige Vorlagen für\nverschiedene [Tests](https://docs.gitlab.com/ee/ci/testing/) anbietet.\nAlles, was wir tun müssen, ist, diese Vorlagen in unsere CI-Konfiguration\naufzunehmen.\n\n\nIn diesem Beispiel schließen wir auch\n[Accessibility-Tests](https://docs.gitlab.com/ee/ci/testing/accessibility_testing.html)\nein:\n\n\n```yaml\n\nstages:\n  - accessibility\n\nvariables:\n  a11y_urls: \"https://about.gitlab.com https://www.example.com\"\n\ninclude:\n  - template: \"Verify/Accessibility.gitlab-ci.yml\"\n```\n\n\nPasse die Variable a11y_urls an, um die URLs der Webseiten aufzulisten, die\nmit [Pa11y](https://pa11y.org/) und der\n[Codequalität](https://docs.gitlab.com/ee/ci/testing/code_quality.html)\ngetestet werden sollen.\n\n\n```yaml\n   include:\n   - template: Jobs/Code-Quality.gitlab-ci.yml\n```\n\n\nMit GitLab kannst du den Testbericht direkt im Widget-Bereich der\nZusammenführungsanforderung sehen. Wenn du die Codeüberprüfung, den\nPipelinestatus und die Testergebnisse an einem Ort hast, wird alles\nreibungsloser und effizienter.\n\n\n![Accessibility\nreport](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_10.56.41.png)\n\n\u003Ccenter>\u003Ci>Widget für die Zusammenführung von\nAccessibility-Anfragen\u003C/i>\u003C/center>\u003Cp>\u003C/p>\n\n\n![Code quality widget in\nMR](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_11.00.25.png)\n\n\u003Ccenter>\u003Ci>Widget für Zusammenführungsanfragen in Codequalität\u003C/i>\u003C/center>\n\n\n### Matrix-Builds\n\n\nIn einigen Fällen müssen wir unsere Anwendung in verschiedenen\nKonfigurationen, Betriebssystemversionen, Programmiersprachenversionen usw.\ntesten. In diesen Fällen verwenden wir den\n[parallel:matrix](https://docs.gitlab.com/ee/ci/yaml/#parallelmatrix)-Build,\num unsere Anwendung in verschiedenen Kombinationen parallel mit einer\nJob-Konfiguration zu testen. In diesem Artikel werden wir unseren Code mit\nverschiedenen Python-Versionen unter Verwendung des Schlüsselworts matrix\ntesten.\n\n\n```yaml\n\npython-req:\n  image: python:$VERSION\n  stage: lint\n  script:\n    - pip install -r requirements_dev.txt\n    - chmod +x ./build_cpp.sh\n    - ./build_cpp.sh\n  parallel:\n    matrix:\n      - VERSION: ['3.8', '3.9', '3.10', '3.11']   # https://hub.docker.com/_/python\n```\n\n\nWährend der Pipeline-Ausführung wird dieser Auftrag viermal parallel\nausgeführt, wobei jedes Mal ein anderes Python-Image verwendet wird (siehe\nunten):\n\n\n![Matrix job\nrunning](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_11.12.48.png)\n\n\n### Unit-Tests\n\n\n#### Was sind Unit-Tests?\n\n\nUnit-Tests sind kleine, gezielte Tests, die einzelne Komponenten oder\nFunktionen von Software prüfen, um sicherzustellen, dass sie wie erwartet\nfunktionieren. Sie sind wichtig, um Fehler in einem frühen Stadium des\nSoftwareentwicklungsprozesses aufzuspüren und zu überprüfen, ob jeder Teil\ndes Codes für sich genommen korrekt funktioniert.\n\n\nBeispiel: Stell dir vor, du entwickelst eine Taschenrechner-App. Ein\nUnit-Test für die Additionsfunktion würde prüfen, ob 2 + 2 gleich 4 ist.\nWenn dieser Test erfolgreich ist, bestätigt er, dass die Additionsfunktion\nkorrekt funktioniert.\n\n\n#### Best Practices für Unit-Tests\n\n\nWenn die Tests fehlschlagen, schlägt die Pipeline fehl und die Benutzer\nwerden benachrichtigt. Entwickler(innen) müssen die Auftragsprotokolle, die\nin der Regel Tausende von Zeilen enthalten, überprüfen und feststellen, wo\ndie Tests fehlgeschlagen sind, um sie zu korrigieren. Diese Prüfung ist\nzeitaufwendig und ineffizient.\n\n\nDu kannst deinen Auftrag so konfigurieren, dass er\n[Unit-Test-Berichte](https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html)\nverwendet. GitLab zeigt die Berichte in der Zusammenführungsanforderung und\nauf der Detailseite der Pipeline an, sodass du den Fehler einfacher und\nschneller identifizieren kannst, ohne das gesamte Protokoll überprüfen zu\nmüssen.\n\n\n##### JUnit Test-Report\n\n\nDies ist ein beispielhafter JUnit Test-Report:\n\n\n![pipelines JUnit test report v13\n10](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674097/Blog/Content%20Images/pipelines_junit_test_report_v13_10.png){:\n.shadow.center}\n\n\n### Strategien für Integrations- und End-to-End-Tests\n\n\nZusätzlich zu unserer regulären Entwicklungsroutine ist es sehr wichtig,\neine spezielle Pipeline nur für Integrations- und End-to-End-Tests\neinzurichten. Damit wird überprüft, ob alle verschiedenen Teile unseres\nCodes reibungslos zusammenarbeiten, einschließlich der\n[Microservices](https://about.gitlab.com/topics/microservices/), der\nUI-Tests und aller anderen Komponenten.\n\n\nWir führen diese Tests jede\n[Nacht](https://docs.gitlab.com/ee/ci/pipelines/schedules.html) durch. Wir\nkönnen es so einrichten, dass die Ergebnisse automatisch an einen speziellen\n[Slack](https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html#notification-events)-Kanal\ngesendet werden. Auf diese Weise können die Entwickler(innen), wenn sie am\nnächsten Tag kommen, schnell alle Probleme erkennen. Es geht darum, Probleme\nfrühzeitig zu erkennen und zu beheben!\n\n\n### Testumgebung\n\n\nFür einige der Tests benötigen wir möglicherweise eine Testumgebung, um\nunsere Anwendungen ordnungsgemäß zu testen. Mit GitLab CI/CD können wir die\nBereitstellung von Testumgebungen automatisieren und so eine Menge Zeit\nsparen. Da es in diesem Blog hauptsächlich um CI geht, werde ich nicht näher\ndarauf eingehen, aber du kannst diesen Abschnitt in der\n[GitLab-Dokumentation](https://docs.gitlab.com/ee/topics/release_your_application.html)\nnachlesen.\n\n\n## Implementierung von Sicherheitsscans in CI-Pipelines\n\n\nFolgend siehst du die Möglichkeiten zur Implementierung von Sicherheitsscans\nin CI-Pipelines.\n\n\n### SAST und DAST-Integration\n\n\nWir legen großen Wert darauf, dass unser Code sicher ist. Wenn unsere\nletzten Änderungen Schwachstellen aufweisen, wollen wir das so schnell wie\nmöglich wissen. Sicherheitsscans sind hier eine sinnvolle Lösung und wir\nempfehlen dir, sie auch in deine Pipeline aufzunehmen. Sie überprüfen den\nCode bei jeder Übertragung und warnen dich vor möglichen Risiken. Wir haben\neine Produktübersicht zusammengestellt, die dich durch das Hinzufügen von\nScans, einschließlich statischer Anwendungssicherheitstests\n([SAST](https://docs.gitlab.com/ee/user/application_security/sast/)) und\ndynamischer Anwendungssicherheitstests\n([DAST](https://docs.gitlab.com/ee/user/application_security/dast/)), zu\ndeiner CI-Pipeline führt.\n\n\n__Klicke__ auf das Bild unten, um zur Übersicht zu gelangen.\n\n\n[![Scans product\ntour](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-14_at_13.44.42.png)](https://gitlab.navattic.com/gitlab-scans)\n\n\nAußerdem können wir mithilfe von KI noch tiefer in Schwachstellen eindringen\nund Vorschläge zu ihrer Behebung erhalten.\n\n\nWeitere Informationen findest du in dieser Demo.\n\n\n[![product tour explain vulnerability\n](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-14_at_13.50.24.png)](https://tech-marketing.gitlab.io/static-demos/pt-explain-vulnerability.html)\n\n\n## Zusammenfassung\n\n\nEs gibt noch viel mehr zu erläutern, aber lass uns hier erst einmal\naufhören.\n\nAlle Beispiele sind bewusst einfach gehalten, um das Konzept GitLab CI\nvorzustellen, ohne die Dinge zu verkomplizieren. Fassen wir zusammen, was\nwir gelernt haben:\n\n\n1. Um Arbeit an GitLab CI zu delegieren, solltest du einen oder mehrere\n[Jobs](https://docs.gitlab.com/ee/ci/jobs/) in.gitlab-ci.yml. definieren.\n\n2. Jobs sollten Namen haben – also denk dir was Gutes aus! Jeder Auftrag\nenthält eine Reihe von Regeln und Anweisungen für GitLab CI, die durch\nspezielle Schlüsselwörter definiert sind.\n\n3. Aufträge können nacheinander, parallel oder ungeordnet über\n[DAG](https://docs.gitlab.com/ee/ci/directed_acyclic_graph/index.html)\nausgeführt werden.\n\n4. Du kannst Dateien zwischen Aufträgen weitergeben und sie in\nBuild-Artefakten speichern, sodass sie über die Schnittstelle\nheruntergeladen werden können.\n\n5. Du kannst Dateien zwischen Aufträgen weitergeben und sie in\nBuild-Artefakten speichern, sodass sie über die Schnittstelle\nheruntergeladen werden können.\n\n\nNachstehend findest du eine genauere Beschreibung der von uns verwendeten\nBegriffe und Schlüsselwörter sowie Links zu den entsprechenden Dokumenten.\n\n\n### Beschreibungen der Keywords\n\n\n{: #keywords}\n\n\n| Keyword/term       | Beschreibung |\n\n|---------------|--------------------|\n\n| [.gitlab-ci.yml](https://docs.gitlab.com/ee/ci/yaml/) | Datei mit allen\nDefinitionen dazu, wie dein Projekt aufgebaut sein sollte |\n\n| [script](https://docs.gitlab.com/ee/ci/yaml/#script)        | Definiert\nein Shell-Script, das ausgeführt werden soll |\n\n| [before_script](https://docs.gitlab.com/ee/ci/yaml/#before_script) | Wird\nverwendet, um den Befehl zu definieren, der vor (allen) Aufträgen ausgeführt\nwerden soll |\n\n|\n[image](https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-image)\n| Definiert das zu verwendende Docker-Image |\n\n| [stages](https://docs.gitlab.com/ee/ci/yaml/#stages)         | Legt eine\nPipelinestufe fest (Standard: test) |\n\n| [artifacts](https://docs.gitlab.com/ee/ci/yaml/#artifacts)     | Definiert\neine Liste von Build-Artifacts |\n\n|\n[artifacts:expire_in](https://docs.gitlab.com/ee/ci/yaml/#artifactsexpire_in)\n| Wird verwendet, um hochgeladene Artifacts nach der angegebenen Zeit zu\nlöschen |\n\n| [needs](https://docs.gitlab.com/ee/ci/yaml/#needs) | Dient zur Definition\nvon Abhängigkeiten zwischen Aufträgen und ermöglicht die Ausführung von\nAufträgen außerhalb der Reihenfolge |\n\n| [pipelines](https://about.gitlab.com/topics/ci-cd/cicd-pipeline/) | Eine\nPipeline ist eine Gruppe von Builds, die stufenweise (Batches) ausgeführt\nwerden |\n",[9,685],{"slug":868,"featured":6,"template":689},"basics-of-gitlab-ci-updated","content:de-de:blog:basics-of-gitlab-ci-updated.yml","Basics Of Gitlab Ci Updated","de-de/blog/basics-of-gitlab-ci-updated.yml","de-de/blog/basics-of-gitlab-ci-updated",1,[666,694,718,742,765,785,808,832],1758326309526]