[{"data":1,"prerenderedAt":1132},["ShallowReactive",2],{"/de-de/blog/categories/engineering/":3,"navigation-de-de":21,"banner-de-de":442,"footer-de-de":455,"engineering-category-page-de-de":664},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":11,"config":12,"_id":15,"_type":16,"title":9,"_source":17,"_file":18,"_stem":19,"_extension":20},"/de-de/blog/categories/engineering","categories",false,"",{"title":9,"description":10},"Engineering","Browse articles related to Engineering on the GitLab Blog",{"name":9},{"template":13,"slug":14,"hide":6},"BlogCategory","engineering","content:de-de:blog:categories:engineering.yml","yaml","content","de-de/blog/categories/engineering.yml","de-de/blog/categories/engineering","yml",{"_path":22,"_dir":23,"_draft":6,"_partial":6,"_locale":7,"data":24,"_id":438,"_type":16,"title":439,"_source":17,"_file":440,"_stem":441,"_extension":20},"/shared/de-de/main-navigation","de-de",{"logo":25,"freeTrial":30,"sales":35,"login":40,"items":45,"search":379,"minimal":415,"duo":429},{"config":26},{"href":27,"dataGaName":28,"dataGaLocation":29},"/de-de/","gitlab logo","header",{"text":31,"config":32},"Kostenlose Testversion anfordern",{"href":33,"dataGaName":34,"dataGaLocation":29},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":36,"config":37},"Vertrieb kontaktieren",{"href":38,"dataGaName":39,"dataGaLocation":29},"/de-de/sales/","sales",{"text":41,"config":42},"Anmelden",{"href":43,"dataGaName":44,"dataGaLocation":29},"https://gitlab.com/users/sign_in/","sign in",[46,90,189,194,300,360],{"text":47,"config":48,"cards":50,"footer":73},"Plattform",{"dataNavLevelOne":49},"platform",[51,57,65],{"title":47,"description":52,"link":53},"Die umfassendste KI-basierte DevSecOps-Plattform",{"text":54,"config":55},"Erkunde unsere Plattform",{"href":56,"dataGaName":49,"dataGaLocation":29},"/de-de/platform/",{"title":58,"description":59,"link":60},"GitLab Duo (KI)","Entwickle Software schneller mit KI in jeder Phase der Entwicklung",{"text":61,"config":62},"Lerne GitLab Duo kennen",{"href":63,"dataGaName":64,"dataGaLocation":29},"/de-de/gitlab-duo/","gitlab duo ai",{"title":66,"description":67,"link":68},"Gründe, die für GitLab sprechen","10 Gründe, warum Unternehmen sich für GitLab entscheiden",{"text":69,"config":70},"Mehr erfahren",{"href":71,"dataGaName":72,"dataGaLocation":29},"/de-de/why-gitlab/","why gitlab",{"title":74,"items":75},"Erste Schritte mit",[76,81,86],{"text":77,"config":78},"Platform Engineering",{"href":79,"dataGaName":80,"dataGaLocation":29},"/de-de/solutions/platform-engineering/","platform engineering",{"text":82,"config":83},"Entwicklererfahrung",{"href":84,"dataGaName":85,"dataGaLocation":29},"/de-de/developer-experience/","Developer experience",{"text":87,"config":88},"MLOps",{"href":89,"dataGaName":87,"dataGaLocation":29},"/de-de/topics/devops/the-role-of-ai-in-devops/",{"text":91,"left":92,"config":93,"link":95,"lists":99,"footer":171},"Produkt",true,{"dataNavLevelOne":94},"solutions",{"text":96,"config":97},"Alle Lösungen anzeigen",{"href":98,"dataGaName":94,"dataGaLocation":29},"/de-de/solutions/",[100,126,149],{"title":101,"description":102,"link":103,"items":108},"Automatisierung","CI/CD und Automatisierung zur Beschleunigung der Bereitstellung",{"config":104},{"icon":105,"href":106,"dataGaName":107,"dataGaLocation":29},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[109,113,117,122],{"text":110,"config":111},"CI/CD",{"href":112,"dataGaLocation":29,"dataGaName":110},"/de-de/solutions/continuous-integration/",{"text":114,"config":115},"KI-unterstützte Entwicklung",{"href":63,"dataGaLocation":29,"dataGaName":116},"AI assisted development",{"text":118,"config":119},"Quellcodeverwaltung",{"href":120,"dataGaLocation":29,"dataGaName":121},"/de-de/solutions/source-code-management/","Source Code Management",{"text":123,"config":124},"Automatisierte Softwarebereitstellung",{"href":106,"dataGaLocation":29,"dataGaName":125},"Automated software delivery",{"title":127,"description":128,"link":129,"items":134},"Sicherheit","Entwickle schneller, ohne die Sicherheit zu gefährden",{"config":130},{"href":131,"dataGaName":132,"dataGaLocation":29,"icon":133},"/de-de/solutions/security-compliance/","security and compliance","ShieldCheckLight",[135,140,145],{"text":136,"config":137},"Application Security Testing",{"href":138,"dataGaName":139,"dataGaLocation":29},"/solutions/application-security-testing/","Application security testing",{"text":141,"config":142},"Schutz der Software-Lieferkette",{"href":143,"dataGaLocation":29,"dataGaName":144},"/de-de/solutions/supply-chain/","Software supply chain security",{"text":146,"config":147},"Software Compliance",{"href":148,"dataGaName":146,"dataGaLocation":29},"/solutions/software-compliance/",{"title":150,"link":151,"items":156},"Bewertung",{"config":152},{"icon":153,"href":154,"dataGaName":155,"dataGaLocation":29},"DigitalTransformation","/de-de/solutions/visibility-measurement/","visibility and measurement",[157,161,166],{"text":158,"config":159},"Sichtbarkeit und Bewertung",{"href":154,"dataGaLocation":29,"dataGaName":160},"Visibility and Measurement",{"text":162,"config":163},"Wertstrommanagement",{"href":164,"dataGaLocation":29,"dataGaName":165},"/de-de/solutions/value-stream-management/","Value Stream Management",{"text":167,"config":168},"Analysen und Einblicke",{"href":169,"dataGaLocation":29,"dataGaName":170},"/de-de/solutions/analytics-and-insights/","Analytics and insights",{"title":172,"items":173},"GitLab für",[174,179,184],{"text":175,"config":176},"Enterprise",{"href":177,"dataGaLocation":29,"dataGaName":178},"/de-de/enterprise/","enterprise",{"text":180,"config":181},"Kleinunternehmen",{"href":182,"dataGaLocation":29,"dataGaName":183},"/de-de/small-business/","small business",{"text":185,"config":186},"den öffentlichen Sektor",{"href":187,"dataGaLocation":29,"dataGaName":188},"/de-de/solutions/public-sector/","public sector",{"text":190,"config":191},"Preise",{"href":192,"dataGaName":193,"dataGaLocation":29,"dataNavLevelOne":193},"/de-de/pricing/","pricing",{"text":195,"config":196,"link":198,"lists":202,"feature":287},"Ressourcen",{"dataNavLevelOne":197},"resources",{"text":199,"config":200},"Alle Ressourcen anzeigen",{"href":201,"dataGaName":197,"dataGaLocation":29},"/de-de/resources/",[203,236,259],{"title":204,"items":205},"Erste Schritte",[206,211,216,221,226,231],{"text":207,"config":208},"Installieren",{"href":209,"dataGaName":210,"dataGaLocation":29},"/de-de/install/","install",{"text":212,"config":213},"Kurzanleitungen",{"href":214,"dataGaName":215,"dataGaLocation":29},"/de-de/get-started/","quick setup checklists",{"text":217,"config":218},"Lernen",{"href":219,"dataGaLocation":29,"dataGaName":220},"https://university.gitlab.com/","learn",{"text":222,"config":223},"Produktdokumentation",{"href":224,"dataGaName":225,"dataGaLocation":29},"https://docs.gitlab.com/","product documentation",{"text":227,"config":228},"Best-Practice-Videos",{"href":229,"dataGaName":230,"dataGaLocation":29},"/de-de/getting-started-videos/","best practice videos",{"text":232,"config":233},"Integrationen",{"href":234,"dataGaName":235,"dataGaLocation":29},"/de-de/integrations/","integrations",{"title":237,"items":238},"Entdecken",[239,244,249,254],{"text":240,"config":241},"Kundenerfolge",{"href":242,"dataGaName":243,"dataGaLocation":29},"/de-de/customers/","customer success stories",{"text":245,"config":246},"Blog",{"href":247,"dataGaName":248,"dataGaLocation":29},"/de-de/blog/","blog",{"text":250,"config":251},"Remote",{"href":252,"dataGaName":253,"dataGaLocation":29},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":255,"config":256},"TeamOps",{"href":257,"dataGaName":258,"dataGaLocation":29},"/de-de/teamops/","teamops",{"title":260,"items":261},"Vernetzen",[262,267,272,277,282],{"text":263,"config":264},"GitLab-Services",{"href":265,"dataGaName":266,"dataGaLocation":29},"/de-de/services/","services",{"text":268,"config":269},"Community",{"href":270,"dataGaName":271,"dataGaLocation":29},"/community/","community",{"text":273,"config":274},"Forum",{"href":275,"dataGaName":276,"dataGaLocation":29},"https://forum.gitlab.com/","forum",{"text":278,"config":279},"Veranstaltungen",{"href":280,"dataGaName":281,"dataGaLocation":29},"/events/","events",{"text":283,"config":284},"Partner",{"href":285,"dataGaName":286,"dataGaLocation":29},"/partners/","partners",{"backgroundColor":288,"textColor":289,"text":290,"image":291,"link":295},"#2f2a6b","#fff","Perspektiven für die Softwareentwicklung der Zukunft",{"altText":292,"config":293},"the source promo card",{"src":294},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":296,"config":297},"Lies die News",{"href":298,"dataGaName":299,"dataGaLocation":29},"/de-de/the-source/","the source",{"text":301,"config":302,"lists":304},"Unternehmen",{"dataNavLevelOne":303},"company",[305],{"items":306},[307,312,318,320,325,330,335,340,345,350,355],{"text":308,"config":309},"Über",{"href":310,"dataGaName":311,"dataGaLocation":29},"/de-de/company/","about",{"text":313,"config":314,"footerGa":317},"Karriere",{"href":315,"dataGaName":316,"dataGaLocation":29},"/jobs/","jobs",{"dataGaName":316},{"text":278,"config":319},{"href":280,"dataGaName":281,"dataGaLocation":29},{"text":321,"config":322},"Geschäftsführung",{"href":323,"dataGaName":324,"dataGaLocation":29},"/company/team/e-group/","leadership",{"text":326,"config":327},"Team",{"href":328,"dataGaName":329,"dataGaLocation":29},"/company/team/","team",{"text":331,"config":332},"Handbuch",{"href":333,"dataGaName":334,"dataGaLocation":29},"https://handbook.gitlab.com/","handbook",{"text":336,"config":337},"Investor Relations",{"href":338,"dataGaName":339,"dataGaLocation":29},"https://ir.gitlab.com/","investor relations",{"text":341,"config":342},"Trust Center",{"href":343,"dataGaName":344,"dataGaLocation":29},"/de-de/security/","trust center",{"text":346,"config":347},"AI Transparency Center",{"href":348,"dataGaName":349,"dataGaLocation":29},"/de-de/ai-transparency-center/","ai transparency center",{"text":351,"config":352},"Newsletter",{"href":353,"dataGaName":354,"dataGaLocation":29},"/company/contact/","newsletter",{"text":356,"config":357},"Presse",{"href":358,"dataGaName":359,"dataGaLocation":29},"/press/","press",{"text":361,"config":362,"lists":363},"Kontakt",{"dataNavLevelOne":303},[364],{"items":365},[366,369,374],{"text":36,"config":367},{"href":38,"dataGaName":368,"dataGaLocation":29},"talk to sales",{"text":370,"config":371},"Support",{"href":372,"dataGaName":373,"dataGaLocation":29},"/support/","get help",{"text":375,"config":376},"Kundenportal",{"href":377,"dataGaName":378,"dataGaLocation":29},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":380,"login":381,"suggestions":388},"Schließen",{"text":382,"link":383},"Um Repositories und Projekte zu durchsuchen, melde dich an bei",{"text":384,"config":385},"gitlab.com",{"href":43,"dataGaName":386,"dataGaLocation":387},"search login","search",{"text":389,"default":390},"Vorschläge",[391,394,399,401,406,411],{"text":58,"config":392},{"href":63,"dataGaName":393,"dataGaLocation":387},"GitLab Duo (AI)",{"text":395,"config":396},"Code Suggestions (KI)",{"href":397,"dataGaName":398,"dataGaLocation":387},"/de-de/solutions/code-suggestions/","Code Suggestions (AI)",{"text":110,"config":400},{"href":112,"dataGaName":110,"dataGaLocation":387},{"text":402,"config":403},"GitLab auf AWS",{"href":404,"dataGaName":405,"dataGaLocation":387},"/de-de/partners/technology-partners/aws/","GitLab on AWS",{"text":407,"config":408},"GitLab auf Google Cloud",{"href":409,"dataGaName":410,"dataGaLocation":387},"/de-de/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":412,"config":413},"Warum GitLab?",{"href":71,"dataGaName":414,"dataGaLocation":387},"Why GitLab?",{"freeTrial":416,"mobileIcon":421,"desktopIcon":426},{"text":417,"config":418},"Kostenlos testen",{"href":419,"dataGaName":34,"dataGaLocation":420},"https://gitlab.com/-/trials/new/","nav",{"altText":422,"config":423},"GitLab-Symbol",{"src":424,"dataGaName":425,"dataGaLocation":420},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":422,"config":427},{"src":428,"dataGaName":425,"dataGaLocation":420},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"freeTrial":430,"mobileIcon":434,"desktopIcon":436},{"text":431,"config":432},"Erfahre mehr über GitLab Duo",{"href":63,"dataGaName":433,"dataGaLocation":420},"gitlab duo",{"altText":422,"config":435},{"src":424,"dataGaName":425,"dataGaLocation":420},{"altText":422,"config":437},{"src":428,"dataGaName":425,"dataGaLocation":420},"content:shared:de-de:main-navigation.yml","Main Navigation","shared/de-de/main-navigation.yml","shared/de-de/main-navigation",{"_path":443,"_dir":23,"_draft":6,"_partial":6,"_locale":7,"title":444,"button":445,"config":450,"_id":452,"_type":16,"_source":17,"_file":453,"_stem":454,"_extension":20},"/shared/de-de/banner","GitLab Duo Agent Platform ist jetzt in öffentlicher Beta!",{"text":446,"config":447},"Beta testen",{"href":448,"dataGaName":449,"dataGaLocation":29},"/de-de/gitlab-duo/agent-platform/","duo banner",{"layout":451},"release","content:shared:de-de:banner.yml","shared/de-de/banner.yml","shared/de-de/banner",{"_path":456,"_dir":23,"_draft":6,"_partial":6,"_locale":7,"data":457,"_id":660,"_type":16,"title":661,"_source":17,"_file":662,"_stem":663,"_extension":20},"/shared/de-de/main-footer",{"text":458,"source":459,"edit":465,"contribute":470,"config":475,"items":480,"minimal":652},"Git ist eine Marke von Software Freedom Conservancy und unsere Verwendung von „GitLab“ erfolgt unter Lizenz.",{"text":460,"config":461},"Quelltext der Seite anzeigen",{"href":462,"dataGaName":463,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":466,"config":467},"Diese Seite bearbeiten",{"href":468,"dataGaName":469,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":471,"config":472},"Beteilige dich",{"href":473,"dataGaName":474,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":476,"facebook":477,"youtube":478,"linkedin":479},"https://x.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[481,504,559,588,622],{"title":47,"links":482,"subMenu":487},[483],{"text":484,"config":485},"DevSecOps-Plattform",{"href":56,"dataGaName":486,"dataGaLocation":464},"devsecops platform",[488],{"title":190,"links":489},[490,494,499],{"text":491,"config":492},"Tarife anzeigen",{"href":192,"dataGaName":493,"dataGaLocation":464},"view plans",{"text":495,"config":496},"Vorteile von Premium",{"href":497,"dataGaName":498,"dataGaLocation":464},"/de-de/pricing/premium/","why premium",{"text":500,"config":501},"Vorteile von Ultimate",{"href":502,"dataGaName":503,"dataGaLocation":464},"/de-de/pricing/ultimate/","why ultimate",{"title":505,"links":506},"Lösungen",[507,512,515,517,522,527,531,534,537,542,544,546,549,554],{"text":508,"config":509},"Digitale Transformation",{"href":510,"dataGaName":511,"dataGaLocation":464},"/de-de/topics/digital-transformation/","digital transformation",{"text":513,"config":514},"Sicherheit und Compliance",{"href":138,"dataGaName":139,"dataGaLocation":464},{"text":123,"config":516},{"href":106,"dataGaName":107,"dataGaLocation":464},{"text":518,"config":519},"Agile Entwicklung",{"href":520,"dataGaName":521,"dataGaLocation":464},"/de-de/solutions/agile-delivery/","agile delivery",{"text":523,"config":524},"Cloud-Transformation",{"href":525,"dataGaName":526,"dataGaLocation":464},"/de-de/topics/cloud-native/","cloud transformation",{"text":528,"config":529},"SCM",{"href":120,"dataGaName":530,"dataGaLocation":464},"source code management",{"text":110,"config":532},{"href":112,"dataGaName":533,"dataGaLocation":464},"continuous integration & delivery",{"text":162,"config":535},{"href":164,"dataGaName":536,"dataGaLocation":464},"value stream management",{"text":538,"config":539},"GitOps",{"href":540,"dataGaName":541,"dataGaLocation":464},"/de-de/solutions/gitops/","gitops",{"text":175,"config":543},{"href":177,"dataGaName":178,"dataGaLocation":464},{"text":180,"config":545},{"href":182,"dataGaName":183,"dataGaLocation":464},{"text":547,"config":548},"Öffentlicher Sektor",{"href":187,"dataGaName":188,"dataGaLocation":464},{"text":550,"config":551},"Bildungswesen",{"href":552,"dataGaName":553,"dataGaLocation":464},"/de-de/solutions/education/","education",{"text":555,"config":556},"Finanzdienstleistungen",{"href":557,"dataGaName":558,"dataGaLocation":464},"/de-de/solutions/finance/","financial services",{"title":195,"links":560},[561,563,565,567,570,572,574,576,578,580,582,584,586],{"text":207,"config":562},{"href":209,"dataGaName":210,"dataGaLocation":464},{"text":212,"config":564},{"href":214,"dataGaName":215,"dataGaLocation":464},{"text":217,"config":566},{"href":219,"dataGaName":220,"dataGaLocation":464},{"text":222,"config":568},{"href":224,"dataGaName":569,"dataGaLocation":464},"docs",{"text":245,"config":571},{"href":247,"dataGaName":248,"dataGaLocation":464},{"text":240,"config":573},{"href":242,"dataGaName":243,"dataGaLocation":464},{"text":250,"config":575},{"href":252,"dataGaName":253,"dataGaLocation":464},{"text":263,"config":577},{"href":265,"dataGaName":266,"dataGaLocation":464},{"text":255,"config":579},{"href":257,"dataGaName":258,"dataGaLocation":464},{"text":268,"config":581},{"href":270,"dataGaName":271,"dataGaLocation":464},{"text":273,"config":583},{"href":275,"dataGaName":276,"dataGaLocation":464},{"text":278,"config":585},{"href":280,"dataGaName":281,"dataGaLocation":464},{"text":283,"config":587},{"href":285,"dataGaName":286,"dataGaLocation":464},{"title":301,"links":589},[590,592,594,596,598,600,602,606,611,613,615,617],{"text":308,"config":591},{"href":310,"dataGaName":303,"dataGaLocation":464},{"text":313,"config":593},{"href":315,"dataGaName":316,"dataGaLocation":464},{"text":321,"config":595},{"href":323,"dataGaName":324,"dataGaLocation":464},{"text":326,"config":597},{"href":328,"dataGaName":329,"dataGaLocation":464},{"text":331,"config":599},{"href":333,"dataGaName":334,"dataGaLocation":464},{"text":336,"config":601},{"href":338,"dataGaName":339,"dataGaLocation":464},{"text":603,"config":604},"Sustainability",{"href":605,"dataGaName":603,"dataGaLocation":464},"/sustainability/",{"text":607,"config":608},"Vielfalt, Inklusion und Zugehörigkeit",{"href":609,"dataGaName":610,"dataGaLocation":464},"/de-de/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":341,"config":612},{"href":343,"dataGaName":344,"dataGaLocation":464},{"text":351,"config":614},{"href":353,"dataGaName":354,"dataGaLocation":464},{"text":356,"config":616},{"href":358,"dataGaName":359,"dataGaLocation":464},{"text":618,"config":619},"Transparenzerklärung zu moderner Sklaverei",{"href":620,"dataGaName":621,"dataGaLocation":464},"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":38,"dataGaName":39,"dataGaLocation":464},{"text":370,"config":629},{"href":372,"dataGaName":373,"dataGaLocation":464},{"text":375,"config":631},{"href":377,"dataGaName":378,"dataGaLocation":464},{"text":633,"config":634},"Status",{"href":635,"dataGaName":636,"dataGaLocation":464},"https://status.gitlab.com/","status",{"text":638,"config":639},"Nutzungsbedingungen",{"href":640,"dataGaName":641,"dataGaLocation":464},"/terms/","terms of use",{"text":643,"config":644},"Datenschutzerklärung",{"href":645,"dataGaName":646,"dataGaLocation":464},"/de-de/privacy/","privacy statement",{"text":648,"config":649},"Cookie-Einstellungen",{"dataGaName":650,"dataGaLocation":464,"id":651,"isOneTrustButton":92},"cookie preferences","ot-sdk-btn",{"items":653},[654,656,658],{"text":638,"config":655},{"href":640,"dataGaName":641,"dataGaLocation":464},{"text":643,"config":657},{"href":645,"dataGaName":646,"dataGaLocation":464},{"text":648,"config":659},{"dataGaName":650,"dataGaLocation":464,"id":651,"isOneTrustButton":92},"content:shared:de-de:main-footer.yml","Main Footer","shared/de-de/main-footer.yml","shared/de-de/main-footer",{"featuredPost":665,"allPosts":689,"totalPages":1130,"initialPosts":1131},{"_path":666,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":667,"config":670,"content":673,"_id":685,"_type":16,"title":686,"_source":17,"_file":687,"_stem":688,"_extension":20},"/de-de/blog/supercharge-your-git-workflows",{"title":668,"description":669},"Git-Workflows systematisch optimieren","Git clone-Operationen optimieren – bis zu 93% weniger Clone-Zeit und 98% weniger Speicherplatzbedarf mit dem Git Much Faster Script.",{"slug":671,"featured":6,"template":672},"git-workflows-systematisch-optimieren","BlogPost",{"title":668,"description":674,"authors":675,"heroImage":677,"date":678,"category":14,"tags":679,"body":684},"Git clone-Operationen optimieren – bis zu 93 % weniger Clone-Zeit und 98 % weniger Speicherplatzbedarf mit dem Git Much Faster Script.",[676],"Darwin Sanoy","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098264/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_519147119_2RafH61mqosMZv8HGAlsUj_1750098264407.jpg","2025-09-10",[680,681,682,683],"tutorial","git","performance","infrastructure","**7 Minuten Lesezeit**\n\n## Der Geschäftsfall: Was Git-Performance kostet\n\nStellen wir uns vor: Arbeit am Chromium-Projekt, das Repository muss geklont werden. `git clone` starten, einen Kaffee holen, E-Mails checken, vielleicht eine Mittagspause – und 95 Minuten später ist endlich das Arbeitsverzeichnis da. Das ist die Realität für Entwickler, die mit großen Repositories von 50 GB+ arbeiten.\n\nDie Produktivitätsauswirkungen sind erheblich: CI/CD-Pipelines kommen zum Erliegen während sie auf Repository-Klone warten. Infrastrukturkosten steigen, da Compute-Ressourcen untätig bleiben. Entwickler-Frustration wächst, während Context-Switching zur Norm wird. Das Problem zeigt sich überall: Embedded-Teams erben Repositories mit Legacy-Firmware und Vendor-SDKs. Web-Anwendungen akkumulieren Marketing-Assets. Game-Development-Projekte enthalten 3D-Modelle und Audio-Dateien – Repository-Größen erreichen Dutzende von Gigabytes.\n\nEnterprise-CI/CD-Pipelines leiden besonders: Jeder Job braucht frische Repository-Klone. Bei 20-90 Minuten Operationszeit erliegen ganze Entwicklungsworkflows. Infrastrukturkosten steigen durch untätige Compute-Ressourcen.\n\n## Die messbaren Ergebnisse: 6 Minuten statt 95 Minuten\n\n[Git Much Faster](https://gitlab.com/gitlab-accelerates-embedded/misc/git-much-faster) demonstriert dramatische Verbesserungen durch rigoroses Benchmarking über reale Repositories mit konsistenter AWS-Infrastruktur:\n\n**Linux-Kernel-Repository (7,5 GB total):** Standard clone dauerte 6 Minuten 29 Sekunden. Optimized clone erreichte 46,28 Sekunden – eine 88,1%ige Verbesserung, wodurch das .git-Verzeichnis von 5,9 GB auf 284 MB reduziert wurde.\n\n**Chromium-Repository (60,9 GB total):** Standard clone benötigte 95 Minuten 12 Sekunden. Optimized clone erreichte 6 Minuten 41 Sekunden – eine beeindruckende 93%ige Verbesserung, wodurch das .git-Verzeichnis von 55,7 GB auf 850 MB komprimiert wurde.\n\n**GitLab-Website-Repository (8,9 GB total):** Standard clone dauerte 6 Minuten 23 Sekunden. Optimized clone erreichte 6,49 Sekunden – eine bemerkenswerte 98,3%ige Verbesserung, wodurch das .git-Verzeichnis auf 37 MB reduziert wurde.\n\nDie Benchmark-Daten zeigen klare Muster: Größere Repositories zeigen dramatischere Verbesserungen, binär-lastige Repositories profitieren am meisten von intelligenten Filtern, und optimierte Ansätze übertreffen konsistent sowohl standard Git als auch Gits eigenes Scalar-Tool.\n\n## Kosteneinsparungen für die gesamte Infrastruktur\n\nGit clone-Optimierung reduziert auch die Systembelastung durch kleinere Anfragegrößen. GitLabs [Gitaly Cluster](https://docs.gitlab.com/administration/gitaly/praefect/) profitiert direkt: Weniger server-seitige \"pack file\"-Erstellung bedeutet niedrigere Memory-, CPU- und I/O-Anforderungen. Der gesamte Stack wird schneller und günstiger.\n\nDiese Infrastructure-Einsparungen multiplizieren sich in Enterprise-Umgebungen: Reduzierte Dimensionierung der Git-Server, weniger Netzwerk-Overhead, optimierte Storage-Nutzung. Alle Schichten profitieren gleichzeitig.\n\n## Typische Enterprise-Anwendungsfälle\n\n**Embedded Development:** Legacy-Firmware, FPGA-Bitstreams, PCB-Layouts treiben Repository-Größen hoch. Build-Prozesse klonen oft Dutzende externe Repositories, multiplizieren die Performance-Auswirkungen.\n\n**Enterprise-Monorepos:** Mehrere Projekte, akkumulierte Historie. Media-Assets verstärken das Problem – Web-Apps mit Marketing-Assets, Games mit 3D-Modellen über 100 GB.\n\n**CI/CD-Pipelines:** Jeder Job braucht frische Klone. Bei 20-90 Minuten werden Workflows unbrauchbar. Hier zeigen sich die größten Produktivitätsgewinne.\n\n**Verteilte Teams:** Limitierte Netzwerk-Performance zu Development-Workstations profitiert von reduzierten Over-the-Wire-Größen.\n\n---\n\n## Die technische Umsetzung: Wie es funktioniert\n\nGit Much Faster ist ein Script, das ich als Enablement-Tool entwickelt habe, um verschiedene Clone-Optimierungsansätze auf demselben Client zu benchmarken – ob Entwickler-Workstation, CI, Cloud-Umgebungen oder GitOps-Klone. Es enthält kuratierte Konfigurationen für schnellste Clone-Optimierung, die sich als Ausgangspunkt nutzen lassen.\n\nDie Lösung adressiert die grundlegende Herausforderung: Gits Standard-Clone-Verhalten priorisiert Sicherheit über Geschwindigkeit. Bei großen Codebasen, Binär-Assets oder Monorepo-Strukturen wird das zum erheblichen Engpass.\n\n## Vier Benchmark-Strategien im Vergleich\n\nGit Much Faster löst dies durch umfassendes Benchmarking, das vier verschiedene Strategien vergleicht: standard git clone (Baseline mit vollständiger Historie), optimized git clone (custom Konfigurationen mit deaktivierter Kompression und sparse checkout), Gits Scalar clone (integriertes partial cloning) und current directory assessment (Analyse bestehender Repositories ohne erneutes Klonen).\n\nDas Tool bietet messbare, wiederholbare Benchmarks in kontrollierten AWS-Umgebungen. Die wahre Stärke: alle Benchmarks lassen sich in der spezifischen Umgebung ausführen – auch bei langsamen Netzwerkverbindungen findet sich die optimale Clone-Strategie.\n\n## Zwei Schlüssel-Konfigurationen für 93% Zeitersparnis\n\nDie bedeutendsten Gewinne stammen aus zwei Optimierungen:\n\n**Erste Optimierung – `core.compression=0`:** Eliminiert CPU-intensive Kompression während Netzwerkoperationen. Bei modernen Hochgeschwindigkeitsnetzwerken überschreiten CPU-Zyklen oft die Bandbreiteneinsparungen. Allein diese Optimierung reduziert Clone-Zeiten um 40%–60%.\n\n**Zweite Optimierung – `http.postBuffer=1024M`:** Erhöht Gits konservative HTTP-Buffer-Größe. Große Repositories profitieren enorm – Git kann größere Operationen handhaben ohne Aufteilen in mehrere Requests.\n\nZusätzlich nutzt Git Much Faster shallow clones (`--depth=1`) und partial clones (`--filter=blob:none`). Shallow clones reduzieren Daten um 70%–90%, partial clones helfen bei Repositories mit großen Binär-Assets. Sparse checkout kontrolliert ausgecheckte Dateien chirurgisch präzise – 30+ Binärdateitypen werden ausgeschlossen, Working-Directory-Größe sinkt um 78%.\n\nGits Scalar-Tool kombiniert partial clone, sparse checkout und Background-Wartung. Tests zeigen jedoch: Der custom optimized approach übertrifft Scalar um 48%–67% bei ähnlichen Disk-Space-Einsparungen.\n\n## Sofortige Implementierung in drei Schritten\n\nDie Implementierung erfordert das Verständnis, wann welche Technik basierend auf Use Case und Risikotoleranz anzuwenden ist. Für Development, das vollständigen Repository-Zugang erfordert: standard Git cloning nutzen. Für read-heavy Workflows, die schnellen Zugang zu aktuellem Code benötigen: optimized cloning einsetzen. Für CI/CD-Pipelines, wo Geschwindigkeit paramount ist: optimized cloning bietet maximalen Nutzen.\n\nDer Einstieg erfordert nur einfachen Download und Ausführung:\n\n```bash\ncurl -L https://gitlab.com/gitlab-accelerates-embedded/misc/git-much-faster/-/raw/master/git-much-faster.sh -o ./git-much-faster.sh\n\n# Für Benchmarking\nbash ./git-much-faster.sh --methods=optimized,standard --repo=https://github.com/your-org/your-repo.git\n```\n\nFür production-grade Testing enthält das Git Much Faster-Projekt komplette Terraform-Infrastruktur für AWS-Deployment, wodurch sich Variablen eliminieren lassen, die lokale Testergebnisse verzerren.\n\n## Wichtige Einschränkungen beachten\n\nOptimized clones haben Limitierungen: Shallow clones verhindern Zugang zu historischen Commits. Lösung: Entwickler starten optimized, konvertieren bei Bedarf via `git fetch --unshallow` zu full clones. CI-Jobs mit Commit-Historie-Zugriff brauchen möglicherweise vollständige Historie.\n\n---\n\n## Transformative Ergebnisse für deutsche Teams\n\nGit clone-Optimierung liefert messbare Verbesserungen – bis zu 93% weniger Clone-Zeit, 98% weniger Disk-Space-Usage. Gits konservativer Standard-Ansatz lässt erhebliche Performance-Gelegenheiten ungenutzt.\n\n**Für deutsche Entwicklungsteams:** Reduzierte CI/CD-Wartezeiten steigern tägliche Produktivität, geringere Infrastrukturkosten ermöglichen relevante Kosteneinsparungen in Enterprise-Umgebungen.\n\n[Einfach starten mit dem Git Much Faster Repository](https://gitlab.com/gitlab-accelerates-embedded/misc/git-much-faster) – read-only Optimierung in CI/CD-Pipelines beginnen, schrittweise auf Development-Workflows erweitern basierend auf gemessenen Ergebnissen.\n","content:de-de:blog:supercharge-your-git-workflows.yml","Supercharge Your Git Workflows","de-de/blog/supercharge-your-git-workflows.yml","de-de/blog/supercharge-your-git-workflows",[690,709,729,751,777,798,819,843,866,889,910,932,955,979,1000,1023,1043,1064,1088,1110],{"_path":691,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":692,"content":695,"config":703,"_id":705,"_type":16,"title":706,"_source":17,"_file":707,"_stem":708,"_extension":20},"/de-de/blog/fine-grained-job-tokens-ga",{"title":693,"description":694},"Granulare Job Token Berechtigungen sind jetzt verfügbar","GitLab ermöglicht granulare Berechtigungen für CI/CD Job Tokens und erhöht die Sicherheit der Software-Supply-Chain.",{"title":693,"description":694,"authors":696,"heroImage":699,"date":700,"category":14,"tags":701,"body":702},[697,698],"Alex Mark","Joe Randazzo","blog/hero%20images/workflow_1800x945.png","2025-08-26",[271],"[CI/CD](https://about.gitlab.com/de-de/topics/ci-cd/) Pipelines erben oft überprivilegierte Berechtigungen von Benutzerkonten, was erhebliche Sicherheitsrisiken birgt, wenn Pipelines kompromittiert oder Tokens geleakt werden. [GitLab 18.3](https://about.gitlab.com/releases/2025/08/21/gitlab-18-3-released/) führt granulare Berechtigungen für Job Tokens ein, um dieses Problem zu lösen, und überführt diese Sicherheitsverbesserung von Beta zu allgemeiner Verfügbarkeit.\n\nDiese Funktion ermöglicht es Maintainern, granulare Berechtigungen zu implementieren, die den Job-Token-Zugriff auf API-Ressourcen kontrollieren. Gemäß dem [Principle of Least Privilege](https://about.gitlab.com/blog/the-ultimate-guide-to-least-privilege-access-with-gitlab/) haben diese Job Tokens keinerlei Zugriffsmöglichkeit auf API-Ressourcen, bis explizit Berechtigungen erteilt werden.\n\nDiese erste Version umfasst granulare Berechtigungen für die folgenden Ressourcen:\n\n* Repositories\n* Deployments\n* Environments\n* Jobs\n* Packages\n* Pipelines\n* Releases\n* Secure Files\n* Terraform State\n\nZusätzliche API-Endpunkte sind für zukünftige Releases geplant. Weitere Informationen finden sich im [zugehörigen Epic](https://gitlab.com/groups/gitlab-org/-/epics/6310).\n\n![Beispiel für granulare Berechtigungen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755633419/izgwpj45oxoof0frvhap.png)\n\n## Das Gesamtbild\n\nDiese Version stellt einen wichtigen Schritt in GitLabs übergeordneter Mission dar, die Sicherheit der Software-Supply-Chain zu verbessern. Historisch waren Job Tokens an den oder die Benutzer(in) gebunden, der oder die die Pipeline ausführt, wodurch bestehende Privilegien weitergegeben wurden und Sicherheitsrisiken entstanden, wenn Pipelines kompromittiert wurden.\n\nGranulare Berechtigungen für Job Tokens bieten eine Grundlage für ein sichereres CI/CD-Ökosystem, das:\n\n* **Die Angriffsfläche reduziert**: Implementiert das Principle of Least Privilege durch Beschränkung des Zugriffs auf nur notwendige Ressourcen\n* **Die Abhängigkeit von langlebigen Tokens eliminiert**: Bietet eine sichere Alternative, die den Bedarf an persönlichen Zugriffstokens und anderen persistenten Anmeldedaten reduziert\n* **Auf maschinenbasierte Identität vorbereitet**: Dieser Opt-in-Ansatz legt den Grundstein dafür, Job Tokens perspektivisch vollständig von Benutzeridentitäten zu entkoppeln und sich in Richtung echter Machine-to-Machine-Authentifizierung zu bewegen\n* **Sichere Automatisierung im großen Maßstab ermöglicht**: Unterstützt komplexe Deployment-Workflows und CI/CD-Komponenten ohne Kompromisse bei der Sicherheit\n\n## Erste Schritte\n\nSecurity-Teams und DevOps-Ingenieure sollten diese Funktion für alle Projekte evaluieren, die automatisierte Deployments, Package-Veröffentlichungen oder Infrastructure Management durchführen. Da es sich um eine Opt-in-Funktion handelt, kann die Migration schrittweise erfolgen, um Störungen bestehender Pipelines zu minimieren.\n\nBeginne damit, die kritischsten Pipelines zu identifizieren und deren aktuelle Berechtigungsanforderungen zu prüfen. Aktiviere dann granulare Berechtigungen und konfiguriere den minimalen Zugriff, der für jedes Projekt benötigt wird. Weitere Informationen finden sich in der [Dokumentation zu granularen Berechtigungen für CI/CD Job Tokens](https://docs.gitlab.com/ci/jobs/fine_grained_permissions/).",{"slug":704,"featured":6,"template":672},"fine-grained-job-tokens-ga","content:de-de:blog:fine-grained-job-tokens-ga.yml","Fine Grained Job Tokens Ga","de-de/blog/fine-grained-job-tokens-ga.yml","de-de/blog/fine-grained-job-tokens-ga",{"_path":710,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":711,"config":714,"content":716,"_id":725,"_type":16,"title":726,"_source":17,"_file":727,"_stem":728,"_extension":20},"/de-de/blog/docs-site-design-overhaul",{"title":712,"description":713},"Wir haben die GitLab-Dokumentationsseite komplett redesigned","Die Produktdokumentation ist nun sauberer, einfacher zu navigieren und enthält einen Dark Mode.",{"slug":715,"featured":6,"template":672},"docs-site-design-overhaul",{"title":712,"description":717,"authors":718,"heroImage":699,"date":722,"category":14,"tags":723,"body":724},"Erfahre mehr über die Features unserer neu gestalteten Produktdokumentationsseite, die einen einfachen Feedback-Mechanismus und den vielgewünschten Dark Mode bietet.",[719,720,721],"Suzanne Selhorn","Sarah German","Julia Miocene","2025-08-20",[271],"Die GitLab-Dokumentationsseite hat jetzt ein völlig neues Look-and-Feel.\nWas als Anfrage für gezielte Design-Fixes begann, wurde zu einem umfassenden Redesign mit vier wichtigen Verbesserungen:\n\n**Auch und gerade für deutsche Entwicklungsteams:** Diese Verbesserungen machen es einfacher, die englische Dokumentation zu nutzen. Dark Mode und die klarere Navigation helfen dabei, auch bei längeren Sessions die benötigten Informationen zu finden – ohne dass Sprachbarrieren durch schlechte UX verstärkt werden.\n\n## Die vier wichtigsten neuen Features\n\n**Der Dark Mode**: Das meistgewünschte Feature ist endlich da. Du kannst zwischen hellen und dunklen Themes in der oberen rechten Ecke wechseln\nfür bessere Lesbarkeit und weniger Augenbelastung.\n\n**Die Redesigned Navigation**: Wir haben die primäre Navigation nach oben verschoben und die linke Sidebar umstrukturiert, damit unsere 2 300+ Seiten\nweniger überwältigend und besser auffindbar sind.\n\n**Das Simplified Feedback**: Du kannst jetzt Thumbs-up/down-Feedback geben und Kommentare direkt auf jeder Dokumentationsseite hinzufügen.\n\n**Die Technical Debt Fixes**: Dutzende kleiner, aber wirkungsvoller Fixes für Typography, Spacing, Code Blocks und visuelle Inkonsistenzen,\ndie wir über die Jahre gesammelt haben.\n\nDie Brand Alignment mit GitLab's Marketing-Site sorgt außerdem für eine einheitlichere Experience über alle GitLab Properties hinweg.\n\n## Warum jetzt? Das Fundament für Veränderung\n\nAnfang des Jahres hat unser Documentation Engineering Team unter Leitung von Sarah German ein kritisches Replatforming-Projekt durchgeführt\nund von Nanoc zu Hugo migriert. Während diese Änderung für Teams größtenteils unsichtbar war, brachte sie dramatische Performance-Verbesserungen – 130x schnellere lokale Builds\nund 30x schnellere vollständige Builds – und bot die solide technische Grundlage für diese Verbesserungen.\n\nMit diesem Replatforming haben wir die Grundlage geschaffen, die es uns ermöglicht hat, uns auf User Experience-Verbesserungen zu konzentrieren, anstatt mit veralteter Infrastructure zu kämpfen.\n\nSchauen wir uns die Änderungen genauer an.\n\n### Dark Mode\n\nMöglicherweise die größte News für dieses Release: Dark Mode ist jetzt über die gesamte Dokumentationsseite verfügbar.\nDu änderst die Einstellung in der oberen rechten Ecke, und die Site merkt sich deine Präferenz.\nFür viele Teams macht Dark Mode Content einfacher zu lesen und reduziert Eyestrain.\n\n![image of dark mode](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617168/gz45eaygeb0nizf1kwyu.png)\n\n### Redesigned Navigation\n\nWir standen vor der großen Herausforderung, über 2 300 Seiten so zu organisieren, dass Teams nicht überwältigt werden.\nUnsere vorherige einzelne linke Navigation war zwar umfassend, aber schuf eine einschüchternde Experience:\n\n![image of former navigation](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617332/k75fwr3rhjxfjyxmc49d.png)\n\nDer neue Ansatz verschiebt die primäre Navigation nach oben und schafft kürzere, überschaubarere Table-of-Contents-Sections, die sich weniger überwältigend navigieren lassen:\n\n![image of new navigation](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617366/wziabrijury9jl5j7ica.png)\n\nSo zeigen wir die Relationships zwischen Features besser, während einzelne Sections verdaulicher werden.\n\n### Simplified Feedback Mechanism\n\nWir haben den Feedback-Prozess vereinfacht. Anstatt zu verlangen, dass Teams die Docs-Site verlassen und GitLab Issues erstellen,\nkönnen sie jetzt sofortiges Feedback mit Thumbs-up/down-Ratings und Comments direkt auf jeder Page geben.\nScroll einfach auf jeder Dokumentationspage nach unten, um diese neue Functionality in Action zu sehen.\n\n![image of feedback area](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617289/rjocpkmqumacaw7thjqi.png)\n\n### Style Updates und Technical Debt\n\nÜber die Jahre hatten sich kleine Style-Inkonsistenzen angesammelt – inkonsistente Padding in Lists, zusätzliche Spacing um Alerts und verschiedene Typography-Issues.\nDie sehen zwar klein aus, aber zusammen schufen sie eine subtil störende Experience für Daily Users.\n\nUnsere Tabs und Code Blocks haben besondere Aufmerksamkeit bekommen und sind jetzt besser definiert.\n\nVorher sahen Tabs mit Code so aus:\n\n![image of old tabs with code block](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617460/jsa2gz3b2slqu0udrg28.png)\n\nUnd jetzt, mit ein paar kleinen Tweaks, sehen sie so aus:\n\n![image of new tabs with code block](https://res.cloudinary.com/about-gitlab-com/image/upload/v1755617493/jpxiybvnadsex39lyawu.png)\n\nDiese Papercut-Fixes sind einzeln klein, aber zusammen schaffen sie eine viel poliertere, professionellere Experience.\n\n## Was kommt als nächstes?\n\nDieses Redesign zeigt, wie wir bei GitLab iterieren – wir shippen meaningful Improvements und bauen gleichzeitig für eine noch bessere Zukunft.\nWir erwarten, die Struktur weiter zu verfeinern und Features hinzuzufügen, die Teams helfen, leichter zu finden, was sie brauchen.\n\nUser Feedback wird unsere nächsten Iterationen antreiben, und mit unserem neuen simplified Feedback Mechanism\nsind wir besser positioniert denn je, direkt von unseren Documentation-Teams zu hören.\n\n## Das Team\n\nDas ganze Team hat an dieser Transformation gearbeitet. Kudos an UX Papercuts und Julia Miocene dafür,\naus einer einfachen Anfrage eine umfassende Design Vision zu machen. Thanks an die Engineers im Technical Writing:\nSarah German, Pearl Latteier und Hiru Fernando, die diese Designs zum Leben erweckt haben.\n\nDas neue Design balanciert Information Density mit Visual Clarity, modernisiert unsere Site unter Beibehaltung\nvon Usability- und Accessibility-Standards und ist ein großer Schritt nach vorn in User Experience und Visual Design.\n","content:de-de:blog:docs-site-design-overhaul.yml","Docs Site Design Overhaul","de-de/blog/docs-site-design-overhaul.yml","de-de/blog/docs-site-design-overhaul",{"_path":730,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":731,"content":734,"config":745,"_id":747,"_type":16,"title":748,"_source":17,"_file":749,"_stem":750,"_extension":20},"/de-de/blog/inside-gitlabs-healthy-backlog-initiative",{"noIndex":6,"title":732,"description":733,"ogTitle":732,"ogDescription":733},"So optimiert GitLab das Issue-Management für mehr Innovation","GitLab reduziert 65.000 Issues auf das Wesentliche. Erfahre, wie die Healthy Backlog Initiative schnellere Entwicklung und klarere Roadmaps ermöglicht.",{"title":735,"description":736,"authors":737,"heroImage":739,"date":740,"body":741,"category":14,"tags":742},"Hinter den Kulissen von GitLabs Healthy Backlog Initiative","Wie GitLab 65.000 Issues in strategische Features, schnelle Entwicklung und direkte Community-Kommunikation verwandelt.",[738],"Stan Hu","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664458/Blog/Hero%20Images/Gartner_AI_Code_Assistants_Blog_Post_Cover_Image_1800x945.png","2025-07-23","Bei GitLab pflegen wir eine starke Partnerschaft mit unserer Community und ermutigen jeden zur aktiven Mitarbeit. Diese Beiträge haben die GitLab-Plattform über Jahre hinweg gestärkt. Doch mit unserem Wachstum stieg auch die Anzahl der Community-Issues - bis hin zu einem schwer handhabbaren Backlog von über 65.000 Einträgen.\n\nDie Produkt- und Engineering-Teams von GitLab haben kürzlich die [Healthy Backlog Initiative](https://gitlab.com/groups/gitlab-org/-/epics/18639) gestartet, um dieses Backlog anzugehen und unseren Ansatz für die Verwaltung beigetragener Issues in Zukunft zu verfeinern.\n\nIssues mit laufendem Community-Engagement, aktueller Aktivität oder klarer strategischer Ausrichtung bleiben offen. Wir werden Issues schließen, die nicht mehr relevant sind, kein Community-Interesse haben oder nicht mehr zu unserer aktuellen Produktausrichtung passen.\n\nDieser Fokus wird zu mehr Innovation, besserer Erwartungshaltung und schnelleren Entwicklungs- und Bereitstellungszyklen von der Community beigetragenen Funktionen führen.\n\n## Die Healthy Backlog Initiative: 65.000 Issues strategisch reduzieren\n\nIm Laufe der Zeit hat die GitLab-Community zahlreiche Issues eingereicht, darunter Bugs, Feature-Anfragen und Feedback-Elemente. Derzeit enthält der zentrale [GitLab-Issue-Tracker](https://gitlab.com/gitlab-org/gitlab/-/issues) über 65.000 Issues, von denen einige heute nicht mehr relevant sind, andere hingegen schon.\n\nUnsere Healthy Backlog Initiative wird das Backlog bereinigen und einen Arbeitsstrom für unsere Produkt- und Engineering-Teams etablieren, um einen fokussierteren Ansatz zur Backlog-Verwaltung umzusetzen. Sie werden wöchentliche Bewertungen des Backlogs durchführen, um sicherzustellen, dass wir Issues priorisieren, die mit unserer Produktstrategie und Roadmap übereinstimmen.\n\n**Hinweis:** Wenn du der Meinung bist, dass ein geschlossenes Issue mit GitLabs Produktstrategie und Roadmap übereinstimmt, oder wenn du aktiv an der Anfrage arbeitest, ermutigen wir dich, das Issue mit aktualisiertem Kontext und aktuellen Details zu kommentieren. Wir verpflichten uns, diese aktualisierten Issues im Rahmen unserer regelmäßigen Bewertungen zu überprüfen.\n\n## Die Vorteile: Fokussierte Entwicklung und klarere Roadmaps\n\nDieser optimierte Ansatz bedeutet direkte, greifbare Verbesserungen für alle GitLab-Nutzer:\n\n* **Schärferer Fokus und schnellere Bereitstellung:** Durch die Eingrenzung unseres Backlogs auf strategisch ausgerichtete Funktionen können wir Entwicklungskapazitäten gezielter nutzen. Das bedeutet, dass du kürzere Entwicklungszyklen und spürbare Verbesserungen in GitLab erwarten kannst.\n* **Klarere Erwartungen:** Wir verpflichten uns zu transparenter Kommunikation darüber, was auf unserer Roadmap steht und was nicht, damit du fundierte Entscheidungen über deine Workflows treffen kannst.\n* **Beschleunigte Feedback-Schleifen:** Mit einem sauberen Backlog werden neue Feedbacks und Feature-Anfragen effizienter überprüft und priorisiert. Das verkürzt die Triage-Zeit und stellt sicher, dass zeitkritische Issues die notwendige Aufmerksamkeit erhalten. Dies schafft schnelleres Feedback für alle.\n\nDiese Initiative mindert nicht die Bedeutung von Community-Feedback und -Beiträgen. Wir ergreifen diese Maßnahme, um Klarheit darüber zu schaffen, was GitLab-Teammitglieder realistisch liefern können, und um sicherzustellen, dass alle Rückmeldungen angemessen berücksichtigt werden.\n\n## GitLabs Commitment: Transparente Prioritäten für die Community\n\nDie GitLab Healthy Backlog Initiative spiegelt unseren Anspruch wider, transparente und effektive Verwalter der GitLab-Plattform zu sein. Indem wir unsere Prioritäten klar kommunizieren und unsere Bemühungen auf das konzentrieren, was wir realistisch im nächsten Jahr erreichen können, sind wir besser positioniert, deine Erwartungen zu erfüllen und zu übertreffen.\n\nDeine kontinuierliche Teilnahme und dein Feedback helfen dabei, GitLab stärker zu machen. Jeder Kommentar, jede Merge Request, jeder Bug-Report und jeder Feature-Vorschlag trägt zu unserer gemeinsamen Vision bei. Und wir belohnen dich auch weiterhin dafür, mit Initiativen wie unserem monatlichen Notable Contributor-Programm, Swag-Belohnungen für Level-Ups, Hackathon-Gewinnern und mehr, alles verfügbar über unser [Contributor-Portal](https://contributors.gitlab.com).\n\n> Um mehr darüber zu erfahren, wie du zu GitLab beitragen kannst, [besuche unsere Community-Seite](https://about.gitlab.com/community/). Um Feedback zu diesem Projekt zu teilen, füge bitte deine Kommentare zum [Feedback-Issue](https://gitlab.com/gitlab-org/gitlab/-/issues/556865) in diesem [Epic](https://gitlab.com/groups/gitlab-org/-/epics/18639) hinzu.",[271,743,744],"product","news",{"featured":92,"template":672,"slug":746},"inside-gitlabs-healthy-backlog-initiative","content:de-de:blog:inside-gitlabs-healthy-backlog-initiative.yml","Inside Gitlabs Healthy Backlog Initiative","de-de/blog/inside-gitlabs-healthy-backlog-initiative.yml","de-de/blog/inside-gitlabs-healthy-backlog-initiative",{"_path":752,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":753,"content":761,"config":771,"_id":773,"_type":16,"title":774,"_source":17,"_file":775,"_stem":776,"_extension":20},"/de-de/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"ogTitle":754,"schema":755,"ogImage":756,"ogDescription":757,"ogSiteName":758,"noIndex":6,"ogType":759,"ogUrl":760,"title":754,"canonicalUrls":760,"description":757},"GitLab: Repository-Backups von 48h auf 41min reduziert","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Verkürzung der Backup-Zeiten von 48 Stunden auf 41 Minuten\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Karthik Nayak\"},{\"@type\":\"Person\",\"name\":\"Manuel Kraft\"}],\n        \"datePublished\": \"2025-06-05\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097166/Blog/Hero%20Images/Blog/Hero%20Images/REFERENCE%20-%20display%20preview%20for%20blog%20images%20%282%29_2pKf8RsKzAaThmQfqHIaa7_1750097166565.png","GitLab reduziert Backup-Zeiten von 48 Stunden auf 41 Minuten! Entdecke, wie wir einen 15 Jahre alten Git-Bug mit O(N²)-Komplexität gelöst haben. Code inklusive.","https://about.gitlab.com","Artikel","https://about.gitlab.com/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"heroImage":756,"body":762,"authors":763,"updatedDate":766,"date":767,"title":768,"tags":769,"description":770,"category":14},"Backups von Repositorys sind ein wichtiger Bestandteil jeder robusten\nStrategie für die Notfallwiederherstellung. Mit zunehmender Größe der\nRepositorys wird die Erstellung zuverlässiger Backups jedoch immer\nschwieriger. Das Backup unseres eigenen\n[Rails-Repository](https://gitlab.com/gitlab-org/gitlab) dauerte 48 Stunden\nund zwang uns zu einer unmöglichen Entscheidung zwischen Backup-Häufigkeit\nund Systemleistung. Wir wollten dieses Thema sowohl für unsere Kund(inn)en\nals auch für unsere eigenen Benutzer(innen) in den Griff bekommen.\n\n\nSchließlich haben wir das Problem auf eine 15 Jahre alte Git-Funktion mit O(N²)-Komplexität zurückgeführt und sie mit einer algorithmischen Änderung behoben, die die **Backup-Zeiten exponentiell reduzierte**. Das Ergebnis: niedrigere Kosten, weniger Risiko und Backup-Strategien, die tatsächlich mit deiner Codebase mitwachsen.\n\n\nEs stellte sich heraus, dass es sich um ein Skalierungsproblem von Git handelt, das jedes große Repository betrifft. Hier erfährst du, wie wir es aufgespürt und behoben haben.\n\n\n## Skalierbare Backups\n\n\nSehen wir uns zunächst das Problem an. Wenn Unternehmen ihre Repositorys skalieren und Backups immer komplexer werden, stehen sie vor einigen Herausforderungen:\n\n\n* **Zeitintensive Backups:** Bei sehr großen Repositorys kann es mehrere Stunden dauern, bis ein Repository-Backup erstellt wird. Dies kann die Möglichkeit, regelmäßige Backups zu planen, beeinträchtigen. \n\n* **Ressourcenintensität:** Erweiterte Backup-Prozesse können erhebliche Serverressourcen verbrauchen, was sich möglicherweise auf andere Vorgänge auswirken kann.\n\n* **Backup-Fenster:** Für Teams, die rund um die Uhr arbeiten, kann es schwierig sein, angemessene Wartungsfenster für Prozesse zu finden, die so lange dauern.\n\n* **Erhöhtes Ausfallrisiko:** Prozesse, die über längere Zeit ausgeführt werden, sind anfälliger für Unterbrechungen durch Netzwerkprobleme, Neustarts von Servern und Systemfehler. So sind Teams manchmal dazu gezwungen, den gesamten sehr langen Backup-Prozess von Grund auf neu zu starten.\n\n* **Race Conditions:** Da es sehr lange dauert, ein Backup durchzuführen, kann sich das Repository während des Prozesses stark verändern. Dies kann möglicherweise zu einem ungültigen Backup führen oder das Backup unterbrechen, weil Objekte nicht mehr verfügbar sind.\n\n\nDiese Herausforderungen können zu Kompromissen bei der Häufigkeit oder Vollständigkeit von Backups führen – ein inakzeptabler Kompromiss, wenn es um den Datenschutz geht. Erweiterte Backup-Fenster können Kund(inn)en zu Problemumgehungen zwingen. Einige setzen möglicherweise externe Tools ein, während andere die Backup-Häufigkeit reduzieren, was zu potenziell inkonsistenten Datenschutzstrategien im Unternehmen führen kann.\n\n\nSehen wir uns nun an, wie wir einen Leistungsengpass identifiziert, eine Lösung gefunden und diese bereitgestellt haben, um die Backup-Zeiten zu verkürzen.\n\n\n## Die technische Herausforderung\n\n\nDie Repository-Backup-Funktionalität von GitLab basiert auf dem Befehl [`git bundle create`](https://git-scm.com/docs/git-bundle), der einen vollständigen Snapshot eines Repository erfasst, einschließlich aller Objekte und Referenzen wie Branches und Tags. Dieses Bundle dient als Wiederherstellungspunkt, um das Repository in seinem genauen Zustand neu zu erstellen.\n\n\nDie Implementierung des Befehls litt jedoch unter einer schlechten Skalierbarkeit im Zusammenhang mit der Referenzzählung, was zu einem Leistungsengpass führte. Je mehr Referenzen die Repositorys sammelten, desto mehr stieg die Verarbeitungszeit exponentiell an. In unseren größten Repositorys mit Millionen von Referenzen konnten Backup-Vorgänge mehr als 48 Stunden dauern.\n\n\n### Grundursachenanalyse\n\n\nUm die Grundursache dieses Leistungsengpasses zu identifizieren, haben wir ein Flammendiagramm des Befehls während der Ausführung analysiert.\n\n\n![Flammendiagramm, das den Befehl während der Ausführung zeigt](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097176/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097176388.jpg)\n\n\nEin Flammendiagramm, das den Ausführungspfad eines Befehls durch seinen Stacktrace zeigt. Jeder Balken entspricht einer Funktion im Code. Die Breite des Balkens gibt an, wie viel Zeit der Befehl für die Ausführung innerhalb dieser bestimmten Funktion benötigt hat.\n\n\nBei der Untersuchung des Flammendiagramms von `git bundle create`, das auf einem Repository mit 10 000 Referenzen ausgeführt wird, werden etwa 80 % der Ausführungszeit von der Funktion `object_array_remove_duplicates()` verbraucht. Diese Funktion wurde in Git im [Commit b2a6d1c686](https://gitlab.com/gitlab-org/git/-/commit/b2a6d1c686) eingeführt (bundle: allow the same ref to be given more than once, 17.01.2009).\n\n\nUm diese Änderung zu verstehen, ist es wichtig zu wissen, dass `git bundle create` es Benutzer(inne)n ermöglicht, anzugeben, welche Referenzen in das Bundle aufgenommen werden sollen. Für vollständige Repository-Bundles werden mit dem Flag `--all` alle Referenzen gepackt.\n\n\nDer Commit löste ein Problem, bei dem Benutzer(innen), die über die Befehlszeile doppelte Referenzen bereitstellten – wie z. B. `git bundle create main.bundle main main` – ein Bundle erstellten, ohne die doppelte Hauptreferenz ordnungsgemäß zu verarbeiten. Das Entpacken dieses Bundles in einem Git-Repository würde fehlschlagen, da versucht würde, die gleiche Referenz zweimal zu schreiben. Der Code zum Vermeiden von Duplikaten verwendet verschachtelte `for`-Schleifen, die alle Referenzen durchlaufen, um Duplikate zu identifizieren. Dieser O(N²)-Algorithmus wird in Repositorys mit einer großen Anzahl von Referenzen zu einem erheblichen Leistungsengpass, da er viel Rechenzeit verbraucht.\n\n\n### Der Fix: Von O(N²) zu effizientem Mapping\n\n\nUm dieses Leistungsproblem zu lösen, haben wir einen Upstream-Fix für Git bereitgestellt, der die verschachtelten Schleifen durch eine Mapping-Datenstruktur ersetzt. Jede Referenz wird der Zuordnung hinzugefügt, wodurch automatisch sichergestellt wird, dass nur eine einzige Kopie jeder Referenz für die Bearbeitung gespeichert wird.\n\n\nDiese Änderung verbessert die Leistung von `git bundle create` drastisch und ermöglicht eine bessere Skalierbarkeit in Repositorys mit einer großen Anzahl von Referenzen. Benchmark-Tests mit einem Repository mit 10 000 Referenzen zeigen eine 6-fache Leistungssteigerung.\n\n\n```shell\n\nBenchmark 1: bundle (refcount = 100000, revision = master)\n  Time (mean ± σ): \t14.653 s ±  0.203 s\t[User: 13.940 s, System: 0.762 s]\n  Range (min … max):   14.237 s … 14.920 s\t10 runs\n\nBenchmark 2: bundle (refcount = 100000, revision = HEAD)\n  Time (mean ± σ):  \t2.394 s ±  0.023 s\t[User: 1.684 s, System: 0.798 s]\n  Range (min … max):\t2.364 s …  2.425 s\t10 runs\n\nSummary\n  bundle (refcount = 100000, revision = HEAD) ran\n  6.12 ± 0.10 times faster than bundle (refcount = 100000, revision = master)\n```\n\n\nDer Patch wurde akzeptiert und in den Git-Upstream [zusammengeführt](https://gitlab.com/gitlab-org/git/-/commit/bb74c0abbc31da35be52999569ea481ebd149d1d). Wir haben diesen Fix zurückportiert, damit unsere Kund(inn)en sofort davon profitieren können, ohne auf die nächste Git-Version warten zu müssen.\n\n\n## Das Ergebnis: Drastisch verkürzte Backup-Zeiten\n\n\nDie Leistungssteigerungen, die sich aus dieser Verbesserung ergeben haben, sind bahnbrechend:\n\n\n* **Von 48 Stunden auf 41 Minuten:** Das Erstellen eines Backups unseres größten Repositorys (`gitlab-org/gitlab`) dauert jetzt nur noch 1,4 % der ursprünglichen Zeit.\n\n* **Konsistente Leistung:** Die Verbesserung funktioniert zuverlässig bei Repositorys jeder Größe.\n\n* **Ressourceneffizienz:** Wir haben die Serverlast während der Backup-Vorgänge deutlich reduziert.\n\n* **Breitere Anwendbarkeit:** Bei der Erstellung von Backups ist die Verbesserung am größten, aber auch alle Bundle-basierten Vorgänge, die mit vielen Referenzen arbeiten, profitieren davon.\n\n\n## Was bedeutet das für GitLab-Kund(inn)en?\n\n\nGitLab-Kund(inn)en profitieren von dieser Erweiterung unmittelbar und spürbar, wenn es darum geht, wie Unternehmen die Sicherung von Repositorys und die Notfallwiederherstellung planen:\n\n\n* **Transformierte Backup-Strategien**   \n\n  * Enterprise-Teams können umfassende nächtliche Zeitpläne aufstellen, ohne dass die Entwicklungs-Workflows beeinträchtigt werden oder umfangreiche Backup-Fenster erforderlich sind.   \n  * Backups können jetzt während der nächtlichen Zeitpläne nahtlos im Hintergrund ausgeführt werden, anstatt separat und langwierig durchgeführt zu werden.  \n* **Bessere Geschäftskontinuität**  \n\n  * Durch die Verkürzung der Backup-Zeiten von Tagen auf Minuten können Unternehmen ihr Wiederherstellungsziel deutlich minimieren. Dies führt zu einem geringeren Geschäftsrisiko – in einem Katastrophenszenario musst du möglicherweise nur noch Stunden anstatt Tage an Arbeit wiederherstellen.  \n* **Reduzierter betrieblicher Mehraufwand**   \n\n  * Geringerer Verbrauch von Serverressourcen und kürzere Wartungsfenster.  \n  * Kürzere Backup-Fenster bedeuten geringere Compute-Kosten, vor allem in Cloud-Umgebungen, wo sich längere Verarbeitungszeiten direkt in höheren Rechnungen niederschlagen.  \n* **Zukunftssichere Infrastruktur**   \n\n  * Wachsende Repositorys erzwingen keine schwierigen Entscheidungen mehr zwischen Backup-Häufigkeit und Systemleistung.   \n  * Wenn deine Codebase wächst, kann deine Backup-Strategie nahtlos mitwachsen.\n\nUnternehmen können jetzt robustere Backup-Strategien umsetzen, ohne Kompromisse bei der Leistung oder Vollständigkeit einzugehen. Was früher ein schwieriger Kompromiss war, ist heute ein ganz normaler Vorgang.\n\n\nMit dem Release von [GitLab 18.0 (nur in englischer Sprache verfügbar)](https://about.gitlab.com/releases/2025/05/15/gitlab-18-0-released/) können alle GitLab-Kund(inn)en unabhängig von ihrem Tarif diese Verbesserungen bereits in vollem Umfang für ihre [Backup-Strategie und Ausführung (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/administration/backup_restore/backup_gitlab/) nutzen. Es ist keine weitere Änderung der Konfiguration erforderlich.\n\n\n## Wie geht es weiter?\n\n\nDieser Durchbruch ist Teil unseres kontinuierlichen Engagements für eine skalierbare, unternehmensgerechte Git-Infrastruktur. Die Reduzierung der Zeit für die Erstellung von Backups von 48 Stunden auf 41 Minuten ist bereits ein wichtiger Meilenstein. Wir arbeiten weiter daran, Leistungsengpässe in unserem gesamten Stack zu identifizieren und zu beheben.\n\n\nWir sind besonders stolz darauf, dass diese Verbesserung in das Git-Projekt integriert wurde und nicht nur den Benutzer(inn)en von GitLab, sondern auch der gesamten Git-Community zugutekommt. Dieser kollaborative Ansatz bei der Entwicklung stellt sicher, dass Verbesserungen gründlich geprüft, umfassend getestet und für alle zugänglich gemacht werden.\n\n\n> Tiefgreifende Infrastrukturarbeit wie diese ist die Art, wie wir bei GitLab an die Leistung herangehen. Nimm am virtuellen Launch-Event von GitLab 18 teil, um zu sehen, welche weiteren grundlegenden Verbesserungen wir einführen werden. [Registriere dich noch heute!](https://about.gitlab.com/de-de/eighteen/)\n",[764,765],"Karthik Nayak","Manuel Kraft","2025-07-11","2025-06-05","So haben wir GitLab-Backups von 48 Stunden auf 41 Minuten beschleunigt",[],"Erfahre, wie GitLab einen Leistungsengpass in einer 15 Jahre alten Git-Funktion aufgespürt und behoben hat, was zu einer verbesserten Effizienz führte.",{"slug":772,"featured":92,"template":672},"how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes","content:de-de:blog:how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes.yml","How We Decreased Gitlab Repo Backup Times From 48 Hours To 41 Minutes","de-de/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes.yml","de-de/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"_path":778,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":779,"content":786,"config":792,"_id":794,"_type":16,"title":795,"_source":17,"_file":796,"_stem":797,"_extension":20},"/de-de/blog/definition-what-is-kubernetes",{"title":780,"description":781,"ogTitle":780,"ogDescription":781,"noIndex":6,"ogImage":782,"ogUrl":783,"ogSiteName":758,"ogType":784,"canonicalUrls":783,"schema":785},"Was ist Kubernetes?","Container haben Softwareentwicklung und -Deployment revolutioniert. Wir zeigen dir hier die Vorteile von Kubernetes.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662245/Blog/Hero%20Images/blog-image-template-1800x945__16_.png","https://about.gitlab.com/blog/definition-what-is-kubernetes","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Was ist Kubernetes?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab Germany Team\"}],\n        \"datePublished\": \"2025-05-15\",\n      }",{"title":780,"description":781,"authors":787,"heroImage":782,"date":789,"body":790,"category":14,"tags":791,"updatedDate":789},[788],"GitLab Germany Team","2025-05-15","# Kubernetes: Einfach erklärt\n\nKubernetes hat sich weltweit als führende Technologie in der Container-Orchestrierung durchgesetzt. Die Vielfalt an Funktionalitäten, die Kubernetes bereitstellt, ist aber nicht immer leicht zu nutzen. Lukas Gentele schreibt auf entwickler.de, dass \"von vielen Entwicklern Kubernetes als zu komplex und kaum zu beherrschen wahrgenommen wird\". Damit spricht er aus, was viele denken.\n\nIronischerweise besteht der Hauptnutzen von Kubernetes darin, viele Anwendungen überhaupt erst beherrschbar zu machen. Warum das kein Widerspruch ist, was Kubernetes ist und wie es funktioniert, erfährst du in diesem Artikel. \n\n## Inhaltsverzeichnis\n- [Kubernetes: Einfach erklärt](#kubernetes-einfach-erklärt)\n  - [Kubernetes-Container: Kein Pod kommt ohne aus](#kubernetes-container-kein-pod-kommt-ohne-aus)\n  - [Container – übersichtlich, kollaborativ, effizient](#container-–-übersichtlich-kollaborativ%2C-effizient)\n  - [Pod: Container Kombinationen](#pod-container-kombinationen)\n  - [Orchestrierung: Container kontrollieren](#orchestrierung-container-kontrollieren)\n  - [Abstraktion und Zustandsorientierung](#abstraktion-und-zustandsorientierung)\n  - [Node, Kubelet, Cluster: Die Welt von Kubernetes](#node-kubelet%2C-cluster-die-welt-von-kubernetes)\n  - [Wie funktioniert Kubernetes?](#wie-funktioniert-kubernetes%3F)\n  - [Kubernetes in der Praxis](#kubernetes-in-der-praxis)\n  - [Die Vorteile von Kubernetes](#die-vorteile-von-kubernetes)\n  - [Wie funktioniert die Kubernetes-Integration unter GitLab?](#wie-funktioniert-die-kubernetes-integration-unter-gitlab)\n  - [FAQs zu Kubernetes (K8s)](#faqs-zu-kubernetes-(k8s))\n\n## Kubernetes-Container: Kein Pod kommt ohne aus\n\nWenn wir ein Verständnis über Kubernetes vermitteln wollen, kommen wir an einem Bestandteil nicht vorbei – dem Container. \n\nÄhnlich wie Betriebssysteme wurden Anwendungen noch bis vor wenigen Jahre als Monolith entwickelt. Das bedeutet, Anwendungen bestanden aus einer einzigen unteilbaren Codebasis, welche alle Informationen enthält, die zum Betrieb notwendig sind.\n\nAuch, wenn nur wenige Teile der Anwendung benötigt wurden, musste trotzdem das gesamte Programm geladen werden. Das verbrauchte offensichtlich viele Ressourcen, das System wurde langsam und fehleranfällig.\n\n## Container – übersichtlich, kollaborativ, effizient\n\nErste Versuche, die Nachteile einer monolithischen Architektur zu umgehen und Teile eines Programms gezielt zu isolieren, entstanden in den späten 70ern und frühen 80er-Jahren. Doch erst Docker, welches 2013 veröffentlicht wurde, verhalf dem Gedanken auf breiter Basis zum Durchbruch.\n\nDie verschiedenen Funktionalitäten einer Anwendung werden mit einer Software wie Docker isoliert und in Pakete aufgeteilt. Diese Container enthalten sämtliche Daten, Software und Bibliotheken, die zum Betrieb genau dieser Funktionalitäten erforderlich sind.\n\nDie Container können eigenständig genutzt oder getestet werden. Aber man kann sie auch zu einer größeren Architektur verknüpfen und \"aufeinanderstapeln\" wie Container (die Idee entstand [laut dem ehemaligen Docker-CEO Ben Golub](https://www.computerwoche.de/a/der-niedergang-von-docker,3551769) \"als wir all die Containerschiffe im Hafen von Oakland einlaufen sahen\").\n\nFrüher als monolithische Anwendungen entwickelt, werden Programme heute als Zusammensetzungen einzelner Container betrachtet. Anstatt den gesamten Code zu laden, werden nur die Container verwendet, die für die jeweils auszuführenden Aufgaben notwendig sind. Dadurch, dass die Container bereits alle Daten enthalten, die benötigt werden, um das Programm zu starten, wird es deutlich einfacher, einzelne Komponenten von einem Server mit Betriebssystem A auf einen anderen mit Betriebssystem B zu verschieben.\n\n## Pod: Container Kombinationen\n\nAusgehend von den einzelnen Docker-Containern bilden Anwender(innen) nun Gruppen aus Containern, die im Rahmen einer bestimmten Anwendung oder eines größeren Systems zusammenarbeiten. Jede dieser virtuellen Gruppen bezeichnet man als \"Pod\".\n\nIm Beispiel eines E-Commerces Unternehmen, kann nun ein Pod die Benutzeroberfläche enthalten, während andere Pods die Bezahlung, oder die Lieferung abwickeln. Die Vorteile sind klar: Dieser Ansatz ist schlanker und robuster als der monolithische und lässt sich konsistent auf verschiedenen Betriebssystemen verwenden. Gerade in der Softwareentwicklung bedeutete diese Zuverlässigkeit einen deutlichen Sprung nach vorne.\n\n## Orchestrierung: Container kontrollieren\n\nGleichzeitig erfordert eine Anwendung, die aus mehreren Containern zusammengesetzt ist, ein höheres Maß an Management.\n\nWas passiert beispielsweise, wenn ein Pod ausfällt? Wie geht man mit Fehlern in einem Pod um? Wo sollen die Pods ausgeführt werden? Wie wirkt sich die Containerisierung auf die Entwicklung neuer Funktionalitäten aus? Wie funktioniert überhaupt die ständige Neuverteilung verschiedener Pods innerhalb derselben Anwendung während des laufenden Betriebs?\n\nDiese Fragen werden dringlicher, je mehr Container eine Anwendung verwendet. Und sie werden geradezu kritisch in einer Umgebung, in der sehr viele Nutzer(innen) auf eine Vielzahl containerisierter Anwendungen zugreifen sollen.\n\nWenn es keinen monolithischen Code mehr gibt, welcher festlegt, in welchen Situationen bestimmte Kombinationen zur Anwendung kommen, werden neue Prinzipien zur Aktivierung benötigt. Darüber hinaus ergeben sich durch die Containerisierung eine Vielzahl spezifischer Herausforderungen.\n\nDie Lösungsansätze, die sich mit dieser Herausforderung beschäftigen, werden unter dem Begriff Container-Orchestrierung zusammengefasst. Einfach erklärt ist Kubernetes das derzeit wohl leistungsfähigste und effizienteste Orchestrierungs-Tool.\n\n## Abstraktion und Zustandsorientierung\n\nVor der Einführung der Containerisierung, die mit Docker ihren Durchbruch fand, waren Programme im Wesentlichen Stories, die durch ihren Code zusammengehalten wurden. Mit Containern wird dieses Narrativ jedoch aufgebrochen und in seine einzelnen Bestandteile zerlegt. Damit aus diesen Teilen wieder eine sinnvolle Geschichte entsteht, benötigt man einen „roten Faden\", der die einzelnen Komponenten zusammenführt.\n\nAus der Perspektive von Kubernetes werden Anwendungen schlicht als „Arbeitslasten\" (Workloads) betrachtet – also Dienste, die eine bestimmte Menge an Systemressourcen beanspruchen. Pods fungieren dabei als Abstraktionen, da der Zusammenhang zwischen den einzelnen Pods jederzeit aufgelöst und neu gestaltet werden kann.\n\nDas bedeutet, dass du jederzeit eine bestehende Struktur aufbrechen und nach Belieben neu zusammensetzen kannst. Mit denselben Komponenten lässt sich so etwas völlig Neues erschaffen.\n\nWichtig bei der Wahl der geeigneten Abstraktion ist der Zustand (State), der durch die Kombination oder Aktivierung von Nutzlasten im System entsteht. Manche Zustände sind gewünscht, andere nicht.\n\nWenn man Kubernetes einfach definieren würde, würde man sagen Kubernetes stellt sicher, dass alle Komponenten im richtigen Zustand sind.\n\n## Node, Kubelet, Cluster: Die Welt von Kubernetes\n\nIn einem System werden Pods, also funktional zusammengehörige Kombinationen von Kubernetes-Containern auf sogenannte Knoten (englisch: Nodes) verteilt. Ein Knoten kann sowohl ein physischer Rechner (PC) als auch eine virtuelle Maschine (VM) sein.\n\nEs gibt zwei Formen von Knoten:\n\n* Die sogenannten Master-Nodes, welche die Steuerung und Kontrolle übernehmen sowie  \n* die Work-Nodes, auf denen die Anwendungen liegen, welche die Funktionalität einer Anwendung übernehmen.\n\nDie Kommunikation zwischen diesen Ebenen wird von kleinen Managementagenten übernommen, den Kubelets.\n\nSchließlich kann man mehrere Knoten zu Kubernetes-Clustern aufsetzen. Diese bilden dann die Umgebung ab, die Kubernetes verwaltet und auf welcher Kubernetes läuft.\n\n## Wie funktioniert Kubernetes?\n\nKubernetes automatisiert die Container-Orchestrierung, jedoch ist es als Administrator wichtig, stets die Kontrolle darüber zu behalten, welche Prioritäten dabei gesetzt und welche Aspekte berücksichtigt werden müssen.\n\nAdministrator(inn)en erarbeiten zusammen mit den Entwickler(innen)/Anwender(innen) eine Liste an gewünschten Zuständen. Dazu kann beispielsweise der Wunsch gehören, dass gewisse Pods stets aktiv sein sollten. Auch dann, wenn sie formal nicht ununterbrochen benötigt werden.\n\nDas ist ein völlig neuer Ansatz, wie über die Kontrolle der Software nachgedacht werden muss. Statt ständig auf sich ändernde Anforderungen mit neuen Befehlen zu reagieren, definiert man stattdessen, welche Zustände erfüllt werden sollen und überlässt es dann Kubernetes diese zu erfüllen. \n\n*Man bezeichnet diese Form der Kontrolle auch als \"deklarativ\", gegenüber dem traditionellen Modell der \"imperativen\" (befehlsgebenden) Kontrolle.*\n\nEin weiteres Eingreifen seitens Administrator(inn)en ist im Idealfall nicht mehr erforderlich. Senior Solutions Manager Brendan O'Leary von GitLab hat das einmal folgendermaßen auf den Punkt gebracht: *\"Kubernetes sorgt dafür, dass das System so bleibt, wie wir es haben wollen.\"*\n\n## Kubernetes in der Praxis\n\nWie funktioniert die Orchestrierung nun?\n\nKubernetes übernimmt eine Vielzahl von Funktionen, welche die Verwendung der Pods im Cluster optimieren: \n\n* Der Kubernetes Scheduler sorgt dafür, dass Pods den für sie besten Knoten zugeordnet werden.  \n* Kubernetes bringt die Nachfrage nach Nutzlasten mit dem Angebot in Einklang. Das bedeutet: Wenn besonders viele Nutzer(inn)en ein ganz bestimmtes Pod anfragen, droht eine Überlastung. Kubernetes kann hierauf mit zwei Antworten reagieren: Es kann für diesen Pod mehr Ressourcen bereitstellen, oder es kann den Pod duplizieren, also Kopien erstellen und die Anfragen auf diese neuen Pods verteilen. Dieser Prozess wird als load balancing bezeichnet.  \n* Kubernetes aktualisiert sich stets selbst und bleibt somit immer auf dem neuesten Stand.  \n* Entstehen in einem Pod Fehler, die zu einem Ausfall führen, kann Kubernetes im Rahmen seines Self-healings (Selbstheilung) entweder den Pod reparieren oder es auf einen funktionsfähigen früheren Zustand zurücksetzen.  \n* Hast du einmal ein Kubernetes-Cluster aufgesetzt, werden Nutzlasten oft von einem Knoten auf einen anderen verschoben. Interne IP-Adressen können hier also nicht mehr verwendet werden, um den aktuellen Ort eines Pods zu bestimmen (weil er sich ständig ändert). Mit der Service-Discovery-Funktion übernimmt Kubernetes die Aufgabe, dass Anfragen auf dem richtigen Pod auch ankommen.\n\n## Die Vorteile von Kubernetes\n\nGerade bei sehr großen Cloud-Umgebungen ist leicht ersichtlich, warum die oben beschriebene, automatisierte Gewährleistung eines optimalen Zustands einen großen Nutzen mit sich bringt.\n\nEin weiterer Vorteil von Kubernetes besteht in der Entwicklung neuer Funktionen. Es ermöglicht ein reibungsloses Testen, ohne dass es dabei zum Ausfall des Systems kommt. Neue Container und Pods können unkompliziert hinzugefügt werden. Teams können gezielt nur an den Diensten arbeiten, für die sie zuständig sind und so ganz gezielt und spezifisch das System optimieren.\n\nGerade Letzteres war der Grund, dass GitLab sich bereits 2017 für ein Container-zentriertes System mit Kubernetes entschieden hat.\n\nLukas Gentele schreibt dazu:\n\n*\"Dass das Kubernetes-Ökosystem so vielseitig ist, mag auf den ersten Blick abschrecken, doch es ist notwendig, da die Architektur von Kubernetes ein großes Maß an Flexibilität bietet.\"*\n\n## Wie funktioniert die Kubernetes-Integration unter GitLab?\n\nGitLab ist eine Platform die [Kontinuierlichen Integration und Auslieferung](https://about.gitlab.com/de-de/solutions/continuous-integration/) ermöglicht. Somit kannst du als GitLab-Nutzer(in) die Vorteile von Kubernetes bezüglich der Container-Orchestrierung für dich nutzen.\n\nWeil GitLab CE und Kubernetes so natürlich miteinander harmonieren, fällt die Integration recht unkompliziert aus. Wir haben für dich einen Artikel vorbereitet, der genau erklärt, wie du ein [Kubernetes Cluster mit GitLab verbindest](https://docs.gitlab.com/ee/user/clusters/agent/). \n\nKurz zusammengefasst erfordert die Integration folgende Punkte:\n\n* Definiere das Cluster, welches über Kubernetes automatisiert werden soll.  \n* Installiere einen Agenten, der die Kommunikation mit dem Cluster übernimmt.  \n* Konfiguriere die GitLab-CI/CD Pipeline so, dass sie die Kubernetes-API verwendet.\n\n## FAQs zu Kubernetes (K8s)\n\n### Warum wird Kubernetes auch K8s genannt? Was bedeutet der Begriff?\n\nK8s ist eine smarte, leicht kryptische Abkürzung des Begriffs Kubernetes: \"K\" und \"s\" bezeichnen den ersten und letzten Buchstaben, die \"8\" schlicht die Anzahl der Buchstaben, die dazwischen liegen.\n\nDas Wort Kubernetes stammt aus dem Griechischen und bedeutet Steuer- oder Fährmann. Der Begriff bezieht sich auf die zentrale Aufgabe von Kubernetes, ein System auch bei \"hohem Wellengang\" stets stabil zu halten und vor dem Kentern zu bewahren.\n\n### Wer hat Kubernetes entwickelt?\n\nDie ersten Impulse für Kubernetes setzte Google mit seinen Vorläuferprojekten \"Borg\" und \"Project 7\". Beide beschäftigten sich mit der Problemstellung, die Komplexität containierisierter Anwendungen beherrschbar zu machen.\n\nBewusst als Open-Source-Plattform entwickelt, entstand Kubernetes aus der Kollaboration verschiedener großer und kleiner Unternehmen, die sich in der Cloud Native Computing Foundation zusammenschlossen.\n\nDarüber hinaus wurde es maßgeblich über die Git-Community ergänzt und weiterentwickelt.\n\n### Was kostet die Nutzung von Kubernetes?\n\nBei Kubernetes handelt es sich um ein Open-Source-System. Das bedeutet, dass das Programm kostenfrei heruntergeladen werden kann. Trotzdem entstehen bei der Nutzung von Kubernetes in deinem Unternehmen Kosten, potentiell sogar recht hohe.\n\nDer Grund dafür ist, dass die nackte Basisversion der Anwendung letzten Endes für die meisten Anwender(innen) nicht nutzbar ist.\n\nNeben den Kosten, die für das Hosten der Kubernetes-Cluster in der Cloud anfallen, solltest du folgende möglichen Kostenpunkte berücksichtigen:\n\n* Die Nutzung von Kubernetes-Dienstleistungen, welche den Einsatz vereinfachen.  \n* Experten, die das Kubernetes-System konfigurieren, es gegebenenfalls warten und es auf dem neuesten Stand halten. Gerade angesichts des hohen Spezialisierungsgrads des Anforderungsprofils sowie der Menge der anfallenden Arbeitsstunden können hierbei erhebliche Kosten entstehen.  \n* Nach dem Aufsetzen eines Kubernetes-Clusters liegen Ressourcen auf verschiedenen Cloud-Speichern. Ein wichtiger Teil der Funktionalität von Kubernetes besteht darin, Nutzlasten dynamisch zwischen diesen Cloud-Speichern zu verschieben, so dass die Stabilität, Sicherheit und Geschwindigkeit des Systems optimiert wird. Allerdings wird dir das Verschieben von Datenpaketen von einem Speicher auf einen anderen sogar dann berechnet, wenn alle deine Daten bei demselben/derselben Provider(in) liegen. Diese Egress-Kosten werden gemäß des verschobenen Datenvolumens kalkuliert und können sich, abhängig von der Größe der Kubernetes-Cluster, am Ende des Jahres wahrhaft auftürmen.\n\nImmer mehr Anbieter(innen) haben inzwischen Kubernetes-Online-Rechner im Angebot, mit denen du einen besseren Eindruck über die möglichen Kosten erhältst. Allerdings bleibt es meistens bei einer [Schätzung](https://www.heise.de/news/Kosten-der-Google-Kubernetes-Engine-vorab-berechnen-zumindest-grob-7120708.html).",[553],{"slug":793,"featured":6,"template":672},"definition-what-is-kubernetes","content:de-de:blog:definition-what-is-kubernetes.yml","Definition What Is Kubernetes","de-de/blog/definition-what-is-kubernetes.yml","de-de/blog/definition-what-is-kubernetes",{"_path":799,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":800,"content":806,"config":813,"_id":815,"_type":16,"title":816,"_source":17,"_file":817,"_stem":818,"_extension":20},"/de-de/blog/what-is-a-linux-server",{"ogTitle":801,"schema":802,"ogImage":803,"ogDescription":804,"ogSiteName":758,"noIndex":6,"ogType":784,"ogUrl":805,"title":801,"canonicalUrls":805,"description":804},"Was ist ein Linux-Server? | Leitfaden für den Einstieg ","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Linux-Server: Warum sich die Installation lohnt\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab Germany Team\"}],\n        \"datePublished\": \"2025-04-14\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663065/Blog/Hero%20Images/serveur-linux.jpg","Wir zeigen dir, was ein Linus-Server ist und warum er sich lohnt. ✓ Definition ✓ Unterschiede ✓ Vorteile ✓ Distributionen ✓ Einrichtung ➤ Leitfaden lesen!","https://about.gitlab.com/blog/what-is-a-linux-server",{"title":807,"description":808,"authors":809,"heroImage":803,"date":810,"body":811,"category":14,"tags":812},"Linux-Server: Warum sich die Installation lohnt","Linux-Server sind weltweit führend. Wir erklären dir, warum und du selbst von den Vorteilen profitieren kannst.",[788],"2025-04-14","# Linux-Server: Warum sich die Installation lohnt\nServer bilden die Basis des Internets. Und Linux bildet weltweit die Basis für die meisten Server. Seit der Entwicklung von Linux hat sich das Betriebssystem gegenüber weitaus größeren Konkurrenten wie Microsoft nicht nur behaupten, sondern seine Vormachtstellung sogar weiter ausbauen können.\n\nIn diesem Artikel gehen wir auf alle Aspekte eines Linux-Servers ein. Wir wägen Vorteile eines Linux-Servers gegen eventuelle Nachteile ab und stellen dir alle kostenfreien und kommerziellen Varianten („Distributionen“) vor, die aktuell erhältlich sind. Wir zeigen dir, wie du einen Linux-Server verbindest und ein Backup erstellst.\n\nIn der Softwareentwicklung und generell bei DevOps-Projekten eignet sich GitLab besonders gut für die Nutzung auf einem Linux-Server. Dafür gibt es sehr gute Gründe, die wir dir ebenfalls gerne vorstellen möchten.\n\n## Was ist ein Linux-Server?\n\n**Ein Linux-Server ist ein Server, der Linux OS als Betriebssystem nutzt. Bei Linux handelt es sich um ein modulares, monolithisches OS („Operating System“), das in den frühen 1990ern von dem finnisch-amerikanischen Programmierer Linus Torvalds entwickelt wurde.**\n\n- **„Modular“** bezieht sich darauf, dass Linux sowohl um einige Komponenten reduziert, als auch um neue erweitert werden kann, ohne seine Funktionsfähigkeit zu verlieren.\n\n- Gleichzeitig aber ist Linux **„monolithisch“**, was bedeutet, dass der Kern (Kernel) des Betriebssystems nicht geteilt werden kann. Schlankere Ansätze wie beispielsweise Minix arbeiten hingegen mit einem Microkernel, der stets nur die Module nutzt, die wirklich benötigt werden.\n\nTorvalds konzipierte sein eigenes System von Anfang an als Open-Source-Projekt und legte den Quellcode offen. Das bedeutet: Grundsätzlich kannst du Linux in seiner grundlegenden Basisversion nutzen, ohne Lizenzgebühren abzuführen.\n\n## Was ist ein Windows-Server?\nEin Windows-Server ist ein Server, der Microsoft Windows als Betriebssystem nutzt. Dies ist kein Artikel über Microsoft-Server, aber ein kurzer Blick auf ihre Architektur ist hilfreich um zu verstehen, was Linux-Server ausmacht und worauf es sich bei der Auswahl des für dich passenden OS zu achten lohnt.\n\nAuch Microsoft Windows ist monolithisch und eingeschränkt modular. Allerdings nutzt Windows ein grafisches Benutzer-Interface („GUI“), während Linux zumindest in seiner Basisvariante ein Command-Line-Interface („CLI“) verwendet – also über Text und Code angesteuert wird.\n\nDas GUI macht Windows weitaus intuitiver in der Anwendung. GUIs aber verbrauchen sehr viel Arbeitsspeicher und machen das System somit weitaus langsamer und weniger effizient.\n\nDer zweite wichtige Unterschied besteht darin, dass Windows geschlossen und sein Quellcode somit nicht frei einsehbar ist. Daraus ergibt sich eine Vielzahl von Konsequenzen, die größtenteils erklären, weshalb es Microsoft bis heute nicht gelungen ist, das Quasi-Monopol von Linux im Serverbereich aufzubrechen.\n\n## Linux-Server: Vorteile und Entscheidungsgrundlagen\nWie erwähnt ist Linux weltweit führend bei Server-Betriebssystemen. Aktuellen Schätzungen zufolge hatte Linux hier einen Marktanteil von über 80 %. Trotzdem sind sich Expert(inn)en      einig darüber, dass Linux nicht in jedem Fall die beste Wahl ist.\n\n**Ob eine Linux-Architektur für dich geeignet ist, kannst du anhand von vier Kriterien entscheiden:**\n\n**- Stabilität**\n\n**- Sicherheit**\n\n**- Skalierbarkeit und Kundenorientierung**\n\n**- Kosten**\n\nIn den folgenden Abschnitten sehen wir uns diese Punkte genauer an, um dir zu zeigen, wie die Vorteile eines Linux-Servers in der Praxis aussehen.\n\n## Stabilität\nMonolithische Server sind sehr leistungsfähig. Aber sie sind nicht die stabilste Option.\n\nWeil stets der gesamte Kernel genutzt wird, können selbst kleine Fehler in einem isolierten Teil des Betriebssystems zum Absturz führen. Wer wurde nicht schon einmal von dem blauen Bildschirm in Windows „überrascht“! Gerade wenn auf einem Server wichtige Daten liegen oder wenn über ihn eine Website läuft, können sogar kurzzeitige Aussetzer zu hohen Gewinnausfällen oder Kosten führen.\n\nLinux umgeht dieses grundlegende Problem mit einer äußerst schlanken Architektur, die auch der Geschwindigkeit des OS zugutekommt. Diese Leichtigkeit beansprucht weniger Hardware-Ressourcen und stabilisiert das monolithische System auf eine sehr überzeugende Weise.\n\nDarüber hinaus kommt Linux sein offener Quellcode und die Einbettung in die Open-Source-Comunity zugute. Seit 30 Jahren tauschen sich Entwickler(innen) und Systemadministrator(inn)en täglich zu Problemen und Lösungen aus. Sogar akute, schwere Ausfälle können so oftmals schnell behoben werden.\n\nDie „Uptime“ von Linux-Servern, also die Zeit, die ein Server am Stück und ohne Ausfälle online ist, ist bemerkenswert. Bei einigen Linux-Distributionen sind Zeiten von über einem Jahr keine Seltenheit. \n\n## Sicherheit\nSicherheit ist für die meisten Unternehmen neben der Stabilität und Performance der wichtigste Betrachtungspunkt bei der Serverwahl.\n\nLinux wurde von Anfang an mit einigen Features versehen, die das Betriebssystem besonders gut vor eventuellen Angriffen oder ungewünschter Datennutzung schützen. Hier findet sich bereits ein erster Überschneidungspunkt mit der GitLab-Philosophie, bei der Planungseffizienz, Kundenorientierung und Sicherheit stets Hand in Hand gehen.\n\nDazu gehört das standardmäßige Absichern eines Downloads mit einer erzwungenen (Root-)Passwortabfrage oder auch das Abgleichen eines Downloads mit einer Liste als sicher geltender Webseiten.\n\nBesonders vorteilhaft ist, dass Updates auf Linux-Servern im laufenden Betrieb direkt implementiert werden können. Windows verlangt hierzu einen Neustart. Das wird einige Administrator(inn)en dazu verleiten, Updates zu verschieben und damit die Uptime gegenüber      der Sicherheit zu priorisieren. Solche Konflikte entstehen bei Linux nicht.\n\n## Kosten\nLinux ist als Open-Source-Produkt grundsätzlich kostenfrei nutzbar. Die Nutzung von Windows wird über eine Server-Lizenz abgeglichen. So erscheint Linux als die ideale Option für alle, die ihre Kosten möglichst niedrig halten möchten.\n\nIn Wahrheit sind die Kostenunterschiede in der Praxis jedoch nicht so auffällig. In seiner einfachsten Variante erfordert Linux beispielsweise gut geschulte Administrator(inn)en, die mit diesem System arbeiten und es für den konkreten Praxiseinsatz konfigurieren können.\n\nAuch bedarf es einer gewissen Erfahrung, den Kontakt mit der Linux-Community zu nutzen. Hier sind die Support- und Sicherheitspakete kommerzieller Anbieter gelegentlich günstiger.\n\nDer wahre Grund, warum so viele Betriebe auf Linux setzen, ist vielmehr ein anderer:\n\n## Skalierbarkeit und Kundenorientierung\nEine häufig genannte Statistik ist die Dominanz des Linux OS im Supercomputer-Bereich, also seinem Einsatz auf den 500 schnellsten Rechnern der Welt. Hier nähert sich der Wert seit vielen Jahren immer mehr den 100 % an. Tatsächlich wenden gerade große Unternehmen verschiedene Linux-Distributionen besonders gerne an.\n\nSicherlich ist Skalierbarkeit kein Alleinstellungsmerkmal von Linux. Wohl aber wird das traditionelle kommerzielle Lizenzmodell von Windows gerade für rasch wachsende Unternehmen zum Kostenfaktor. Linux hingegen bietet aufgrund seiner inhärent modularen Konstruktion einfache Aufstockungsoptionen – ohne deinen Betrieb dabei finanziell übermäßig zu belasten.\n\nAllerdings brauchen auch mittelgroße und kleine Unternehmen nicht zwangsläufig auf Windows zu setzen. Schließlich wurde Torvalds ursprünglich unter anderem dazu motiviert, Linux zu entwickeln, um die Funktionalität eines großen Servers auf sehr moderater Hardware zu liefern.\n\n## Was sind “Linux-Distributionen”?\nIn seiner Basis-Variante wird Linux sich nur für wenige Unternehmen eignen. Sogar, wenn du die Kosten so niedrig wie möglich halten möchtest, wirst du sehr wahrscheinlich einige Anpassungen vornehmen müssen.\n\nUm dir diese Arbeit abzunehmen und um Linux an deine spezifischen Bedürfnisse anzupassen, haben sich feste Systemkonfigurationen herauskristallisiert. Alle nutzen den Linux-Kernel als Ausgangspunkt und haben ihn um gewisse Elemente und Features erweitert.\n\nDie beliebtesten, offiziell unterstützen Pakete sind Ubuntu, Debian, CentOS, AlmaLinux, Amazon Linux, OpenSUSE Leap und Raspberry Pi OS. Jede dieser Linux-Distributionen hat ihre eigenen Vor- und Nachteile. Sehen wir sie uns der Reihe nach an.\n\n## Linux-Distribution #1: Ubuntu\nUbuntu ist einer der frühesten Linux-Distributionen. Daraus ergibt sich auch unmittelbar einer seiner Hauptvorteile: Die Ubuntu-Community ist global und groß und eventuelle Fragen können in der Regel schnell und effizient beantwortet werden.\n\nUbuntu ist noch immer eine hervorragende Möglichkeit, in die Linux-Welt einzusteigen – auch wenn es inzwischen intuitivere Alternativen gibt. Das User Interface erfordert eine gewisse Einarbeitungs- und Eingewöhnungsphase, ist aber keineswegs komplex und zudem sehr logisch aufgebaut.\n\nFür Privatnutzer ist Ubuntu kostenlos. Die verschiedenen Lizenzlevels für eine kommerzielle Nutzung sind an die Möglichkeiten der jeweiligen Nutzer(innen) angepasst.\n\n## Linux-Distribution #2: Debian\nDebian ist die wohl langlebigste Linux-Distribution. In vielen Ländern, darunter auch Deutschland, bleibt sie die meistgenutzte Linux-Umsetzung für Server.\nDieser Erfolg beruht auf der unvergleichlichen Sicherheit und Stabilität von Debian, die seinesgleichen sucht.\n\nGerade weil Debian so zuverlässig ist, nutzen viele Entwickler(innen) es, um um seinen Core herum eine neue Distribution zu entwickeln. Doch bleibt auch 2024 das ursprüngliche Debian für Linux-Server eine hervorragende Wahl.\n\nAlternativ steht dir mit Raspberry Pi OS ein exzellenter Debian-Klon zur Verfügung.\n\n## Linux-Distribution #3: CentOS\nNach Ubuntu ist CentOS die weltweit beliebteste Linux-Distribution. Von RedHat entwickelt zeichnet sich auch CentOS vor allem durch seine Stabilität und Sicherheit aus. Auch seine einfache Kontrolle und Skalierbarkeit sind hervorzuheben. Und im direkten Vergleich mit anderen Distributionen fällt die bemerkenswerte Geschwindigkeit auf, die für viele Anwender(innen) ein absolutes Alleinstellungsmerkmal darstellt.\n\nLeider wurde der Support von CentOS für Linux eingestellt. Damit werden zwar nicht sofort alle mit dieser Distribution ausgestatteten Server obsolet, zum      Einstieg eignet sich CentOS nach aktuellem Stand aber nicht mehr.\n\n## Linux-Distribution #4: AlmaLinux\nDie Ansprüche von AlmaLinux sind hoch. So hat sich diese Linux Distribution zum Ziel gesetzt, den Status eines Enterprise-Level-Betriebssystems zu erreichen. Um diese Auszeichnung tragen zu dürfen, müssen bestimmte, hohe Kriterien in Bezug auf die Sicherheit und Funktionalität des Systems erreicht werden und es muss durch außenstehende Dienstleister verwaltet und gewartet werden können.\n\nDamit bietet AlmaLinux das volle Leistungspaket für Unternehmen jeder Größenordnung, bleibt aber wegen seines OpenSource-Ansatzes weiter kostenfrei. Durch seine Einbindung in die CentOS-Architektur wird es zudem regelmäßig aktualisiert.\n\nNachteilig wirkt sich allerdings aus, dass die zeitlichen Abstände zwischen neuen Versionen dieser Linux-Distribution eher lang ausfallen. Darüber hinaus ist die Softwareumgebung für Alma eher klein. Das bedeutet, dass du für bestimmte Herausforderungen in deinem Betrieb möglicherweise nicht die passende Lösung findest.\n\n## Linux-Distribution #5: Amazon Linux\nAmazon ist einer der jüngsten Anbieter im Linux-Bereich. Bei Amazon Linux dreht sich alles um die Einbindung in die Amazon Web Services (AWS). Daraus ergeben sich Vorteile in Sachen Kosten und Performance.\n\nAndererseits bedeutet diese enge Verknüpfung auch, dass dir für eventuelle Unterstützung nur eine kleine Community zur Verfügung steht. Das könnte der Grund dafür sein, dass, trotz der Marktmacht, die Amazon hat, das vom Online-Retailer angebotene OS bisher nur einen Anteil von einem halben Prozent erlangt hat.\n\n## Linux-Distribution #6: OpenSUSE Leap\nDas deutsche Unternehmen SUSE hat mit dieser Distribution eine der derzeit beliebtesten neuen Linux-Distributionen vorgelegt. Gerade unter Software-Entwickler(inne)n genießt es eine sehr hohe Wertschätzung.\n\nOpenSUSE Leap macht einiges anders als andere Distributionen. Dazu gehört der hervorragende Package Manager sowie ein optionales grafisches Interface (GUI). Auch in Sachen Sicherheit hat es einigen der etablierteren Distributionen den Rang abgelaufen.\n\n## GitLab und Linux-Server\nBei Git handelt es sich um eine Softwareentwicklungs- und Kollaborationsplattform, die eng mit der agilen Methodologie verknüpft ist. Es mag noch andere Version-Control-Programme geben, doch keines ist so gut für den Einsatz auf einem Linux-Server geeignet wie Git.\n\nDafür reicht ein kurzer Blick in die Geschichte von Git aus. So wurde die Plattform ebenfalls von Linus Torvalds geschrieben, ganz spezifisch für einen Einsatz auf einem Linux-OS. Daraus ergibt sich eine enge Abstimmung, die eine optimale Performance garantiert.\n\nGitLab ist eine der weltweit führenden Git-Plattformen und ergänzt den dahintersteckenden DevOps-Gedanken noch um eine besondere Betonung des Themas Sicherheit.\nUm GitLab unter Linux zu nutzen, richte zunächst den Linux-Server ein und installiere anschließend GitLab.\n\n## Einen Linux-Server einrichten\nJede der genannten Linux-Distributionen hat ihre Eigen- und Besonderheiten. \n\n**Das Einrichten und Verbinden eines Linux-Servers allerdings folgt jeweils einem nahezu identischen Ablauf:**\n\n**- Lade die aktuelle Version der jeweiligen Software auf deinen Rechner und erstelle ein Boot-Medium – entweder auf einem optischen Träger oder einem USB-Stick.**\n\n**- Verbinde das Boot-Medium mit deinem Linux-Server und installiere die Software.**\n\n**- Installiere anschließend den für dich passenden Datenbankserver, einen Webserver und lege die Skriptsprache fest.**\n\n**- Nun kannst du noch eine grafische Benutzeroberfläche hinzufügen oder den Server über Text ansteuern.**\n\nInstalliere anschließend sämtliche weitere Software, die du benötigst.\n\n## Einen Linux-Server sichern\nNach dem Einrichten deines Linux-Servers läuft das Absichern genauso ab wie bei einem Standard-Desktop-PC.\n\nEntscheidend ist, dass du das Linux-Server-Backup wirklich häufig und regelmäßig vornimmst und genau festlegst, was gesichert und was nicht gesichert werden soll. Weil auf Servern oftmals große Datenmengen gespeichert sind, kommt diesem Punkt hier eine noch höhere Bedeutung als im Heimbereich zu. Als Speicherort kann eine hochwertige zweite Festplatte dienen.\n\nWichtig ist die Wahl des besten Backup-Tools. In dieser Übersicht zu Server-Backups unter Linux werden die Vorteile und Nachteile einander anschaulich gegenübergestellt.\n\n## GitLab auf einem Linux-Server nutzen\nUm von den Vorteilen einer GitLab-Nutzung unter Linux profitieren zu können, installiere den Git-Repository-Manager auf einer der obengenannten Distributionen deiner Wahl.\n\n**Der Ablauf der Installation besteht dabei aus drei Schritten:**\n\n**- Dem Installieren und Konfigurieren der verlangten externen Software und/oder Bibliotheken**\n\n**- Dem Hinzufügen des GitLab-Repository und der Installation des Pakets.**\n\n**- Dem Ausführen des Setups.**\n\nAnschließend kannst du von den Funktionen von GitLab für deine Teamarbeit voll profitieren – zum Beispiel im Rahmen deiner Epics und User Stories.",[553],{"slug":814,"featured":6,"template":672},"what-is-a-linux-server","content:de-de:blog:what-is-a-linux-server.yml","What Is A Linux Server","de-de/blog/what-is-a-linux-server.yml","de-de/blog/what-is-a-linux-server",{"_path":820,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":821,"content":827,"config":837,"_id":839,"_type":16,"title":840,"_source":17,"_file":841,"_stem":842,"_extension":20},"/de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab",{"title":822,"description":823,"ogTitle":822,"ogDescription":823,"noIndex":6,"ogImage":824,"ogUrl":825,"ogSiteName":758,"ogType":784,"canonicalUrls":825,"schema":826},"Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab","Wenn Plattformteams ihre CI/CD zu GitLab verschieben, sollte die Migration von Container-Images kein Engpass sein. Befolge diese Schritt-für-Schritt-Anleitung, um den Pipeline-Migrationsprozess zu automatisieren.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663129/Blog/Hero%20Images/blog-image-template-1800x945__28_.png","https://about.gitlab.com/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Rizzi\"}],\n        \"datePublished\": \"2025-02-13\",\n      }\n                  ",{"title":822,"description":823,"authors":828,"heroImage":824,"date":830,"body":831,"category":14,"tags":832,"updatedDate":836},[829],"Tim Rizzi","2025-02-13","„Wir müssen Hunderte von Container-Images von Amazon Elastic Container Registry (ECR) zu GitLab migrieren. Könnt ihr uns helfen?“ Diese Frage taucht immer wieder in Gesprächen mit Platform Engineers auf. Sie modernisierten also ihre DevSecOps-Toolchain mit GitLab, kamen aber beim Verschieben ihrer Container-Images nicht weiter. Während ein einzelner Image-Transfer einfach ist, erscheint das schiere Volumen überwältigend.\n\nEin Platform Engineer brachte es auf den Punkt: „Ich weiß genau, was zu tun ist – pullen, neu kennzeichnen, pushen. Aber ich habe 200 Microservices mit jeweils mehreren Tags. Ich kann es nicht rechtfertigen, Wochen für diese Migration aufzuwenden, während wichtige Infrastrukturarbeiten anstehen.“\n\n## Die Herausforderung\n\nDieses Gespräch führte zu einer Idee. Was wäre, wenn wir den gesamten Prozess automatisieren könnten? Wenn Plattformteams ihre [CI/CD](https://about.gitlab.com/de-de/topics/ci-cd/) zu GitLab verschieben, sollte die Migration von Container-Images kein Engpass sein. Der manuelle Prozess ist einfach, aber repetitiv: Jedes Image pullen, neu kennzeichnen und in die Container-Registry von GitLab pushen. Angesichts dutzender Repositories und mehrerer Tags pro Image, bedeutet dies Tage oder Wochen langwieriger Arbeit.\n\n## Die Lösung\n\nWir haben uns daran gemacht, eine GitLab-Pipeline zu erstellen, die all diese schwierigen Aufgaben automatisch erledigt. Das Ziel war einfach: Wir wollten Platform Engineers ein Tool zur Verfügung stellen, das sie in wenigen Minuten einrichten und über Nacht ausführen können, sodass am nächsten Morgen alle ihre Images erfolgreich migriert wurden.\n\n### Einrichten des Zugriffs\n\nDas Wichtigste zuerst: die Sicherheit. Teams sollen diese Migration mit minimalen AWS-Berechtigungen durchführen können. Hier ist die schreibgeschützte Identitäts- und Zugriffsmanagement (IAM)-Richtlinie dafür:\n\n```json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ecr:GetAuthorizationToken\",\n                \"ecr:BatchCheckLayerAvailability\",\n                \"ecr:GetDownloadUrlForLayer\",\n                \"ecr:DescribeRepositories\",\n                \"ecr:ListImages\",\n                \"ecr:DescribeImages\",\n                \"ecr:BatchGetImage\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\n```\n\n### GitLab-Konfiguration\n\nNachdem die Sicherheit gewährleistet ist, ist der nächste Schritt die Einrichtung von GitLab. Wir haben uns auf das Wesentliche beschränkt. Du musst diese Variablen in deinen CI/CD-Einstellungen konfigurieren:\n\n```\nAWS_ACCOUNT_ID: Your AWS account number\nAWS_DEFAULT_REGION: Your ECR region\nAWS_ACCESS_KEY_ID: [Masked]\nAWS_SECRET_ACCESS_KEY: [Masked]\nBULK_MIGRATE: true\n```\n\n### Die Migrationspipeline\n\nJetzt wird es interessant. Wir haben die Pipeline mit Docker-in-Docker erstellt, um alle Image-Vorgänge zuverlässig zu verarbeiten:\n\n```yaml\nimage: docker:20.10\nservices:\n  - docker:20.10-dind\n\nbefore_script:\n  - apk add --no-cache aws-cli jq\n  - aws sts get-caller-identity\n  - aws ecr get-login-password | docker login --username AWS --password-stdin\n  - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}\n```\n\nDie Pipeline hat drei Phasen, die jeweils auf der letzten aufbauen:\n\n1. Entdeckung\n\nZuerst findet sie alle deine Repositories:\n\n```bash\nREPOS=$(aws ecr describe-repositories --query 'repositories[*].repositoryName' --output text)\n```\n\n2. Tag-Auflistung\n\nDann ruft sie für jedes Repository alle Tags ab:\n\n```bash\nTAGS=$(aws ecr describe-images --repository-name $repo --query 'imageDetails[*].imageTags[]' --output text)\n```\n\n3. Übertragung\n\nSchließlich übernimmt sie die eigentliche Migration:\n\n```bash\ndocker pull ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag}\ndocker tag ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag} ${CI_REGISTRY_IMAGE}/${repo}:${tag}\ndocker push ${CI_REGISTRY_IMAGE}/${repo}:${tag}\n```\n\n## Das Ergebnis\n\nErinnerst du dich an den Platform Engineer, der nicht wochenlang mit der Migration verbringen wollte? Diese Lösung bietet Folgendes:\n\n- automatisierte Erkennung und Migration aller Repositories und Tags\n- konsistente Image-Benennung zwischen ECR und GitLab\n- Fehlerbehandlung für fehlgeschlagene Übertragungen\n- klare Protokollierung zur Verfolgung des Fortschritts\n\nAnstatt Skripte zu schreiben und die Migration zu überwachen, konnte sich der Plattform Engineer auf wertvollere Arbeit konzentrieren.\n\n## Verwendung\n\nDie ersten Schritte sind einfach:\n\n1. Kopiere die Datei `.gitlab-ci.yml` in dein Repository.\n2. Konfiguriere die AWS- und GitLab-Variablen.\n3. Setze `BULK_MIGRATE` auf „true“, um die Migration zu starten.\n\n## Best Practices\n\nBei der Unterstützung von Teams bei ihren Migrationen haben wir einige Dinge gelernt:\n\n- Der Prozess sollte außerhalb der Stoßzeiten durchgeführt werden, um die Auswirkungen auf dein Team zu minimieren.\n- Die Pipeline-Protokolle sind wichtig – darin findest du Informationen, wenn es ein Problem gibt.\n- Die Elastic Container Registry (ECR) sollte erst deaktiviert werden, wenn du überprüft hast, dass alle Images erfolgreich übertragen wurden.\n- Bei sehr großen Migrationen solltest du eine Ratenbegrenzung in Betracht ziehen, um eine Überlastung deines Netzwerks zu vermeiden.\n\nWir haben diese Pipeline in unserem öffentlichen GitLab-Repository quelloffen verfügbar gemacht, weil wir der Meinung sind, dass Plattform Engineers Zeit damit verbringen sollten, wertvolle Infrastrukturen aufzubauen, anstatt Container-Images zu kopieren. Passe sie an deine Bedürfnisse an und stelle Fragen zur Implementierung, wenn etwas unklar ist.\n\n> #### Informationen dazu und zu anderen Paketkomponenten findest du in unserer [CI/CD-Katalog-Dokumentation](https://gitlab.com/explore/catalog/components/package).",[110,833,680,834,743,835],"AWS","DevSecOps platform","solutions architecture","2025-04-10",{"slug":838,"featured":92,"template":672},"automating-container-image-migration-from-amazon-ecr-to-gitlab","content:de-de:blog:automating-container-image-migration-from-amazon-ecr-to-gitlab.yml","Automating Container Image Migration From Amazon Ecr To Gitlab","de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab.yml","de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab",{"_path":844,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":845,"content":851,"config":860,"_id":862,"_type":16,"title":863,"_source":17,"_file":864,"_stem":865,"_extension":20},"/de-de/blog/what-is-an-ide",{"ogTitle":846,"schema":847,"ogImage":848,"ogDescription":849,"ogSiteName":758,"noIndex":6,"ogType":784,"ogUrl":850,"title":846,"canonicalUrls":850,"description":849},"IDE: Integrierte Entwicklungsumgebung einfach erklärt ","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Was ist eine integrierte Entwicklungsumgebung (IDE)?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab Germany Team\"}],\n        \"datePublished\": \"2024-11-13\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659768/Blog/Hero%20Images/AdobeStock_271529563.jpg","Wir zeigen dir, was eine integrierte Entwicklungsumgebung (IDE) ist. ✓ Definition ✓ Unterschiede ✓ Komponenten ✓ Auswahl ➤ Jetzt Leitfaden lesen!","https://about.gitlab.com/blog/what-is-an-ide",{"heroImage":848,"body":852,"authors":853,"updatedDate":854,"date":855,"title":856,"tags":857,"description":859,"category":14},"Entwickler/in ist ein finanziell lukrativer Beruf in einer der derzeit spannendsten Branchen. Zugleich ist es auch ein Job, der mit einer sehr hohen Arbeitsbelastung und einem enormen Leistungsdruck einhergeht. Laut einer Studie leiden bis zu 60 % aller IT-Expert(inn)en unter „Burn-out”. Diese Zahl ist umso bedrückender, wenn man bedenkt, dass sie Studierende miteinschließt. \n\nIntegrierte Entwicklungsumgebungen (IDEs) wurden nicht primär dafür entwickelt, das Coden angenehmer zu machen. Dennoch tragen sie viel dazu bei, die tägliche Arbeit für Entwickler(innen) einfacher zu gestalten. Wer eine gut funktionierende, auf die persönlichen Bedürfnisse zugeschnittene IDE gefunden hat, weiß, wie viel das wert ist.\n\nDie Optimierung des Workflows ist nur ein Aspekt unter vielen, weswegen IDEs einen hohen Stellenwert genießen. Man kann mit gutem Recht behaupten: Modernes Programmieren wäre ohne IDEs nicht denkbar.\n\nWas ist eine IDE? In dieser Übersicht gehen wir ausführlich auf diese Frage ein sowie auf alle Aspekte, die IDEs so begehrt machen. Wenn du noch offene Fragen zum Thema hattest – nach der Lektüre sollten sie beantwortet sein.\n\n## Inhaltsverzeichnis - Was ist eine IDE?\n\n- [Was ist eine IDE?](#was-ist-eine-ide%3F)\n- [IDE vs Code-Editor vs Building-Tools](#ide-vs-code-editor-vs-building-tools)\n- [Was sind die wichtigsten Komponenten einer IDE?](#was-sind-die-wichtigsten-komponenten-einer-ide%3F)\n - [Code-Editor](#code-editor)\n - [Building-Tools](#building-tools)\n - [Debugging](#debugging)\n- [Warum wurden IDEs entwickelt?](#warum-wurden-ides-entwickelt%3F)\n- [Gibt es unterschiedliche IDE-Typen?](#gibt-es-unterschiedliche-ide-typen%3F)\n- [Wonach sollte ich meine IDE auswählen?](#wonach-sollte-ich-meine-ide-auswählen%3F)\n- [Was ist die beste IDE?](#was-ist-die-beste-ide%3F)\n  - [IDE Eclipse](#ide-eclipse)\n  - [Dreamweaver](#dreamweaver)\n  - [IntelliJ](#intellij)\n  - [IDE Visual Studio](#ide-visual-studio)\n  - [GitLab](#gitlab)\n- [IDE-FAQs](#ide-faqs)\n\n## Was ist eine IDE?\n\nDie Abkürzung IDE steht für „Integrated Development Environment”, zu Deutsch „Integrierte Entwicklungsumgebung”. Aus dem Begriff lässt sich eine einfache Definition ableiten:\n\nIDEs unterstützen Entwickler(innen) bei den meisten Aspekten des Codens, beziehungsweise der Programmierung.\nIDEs kombinieren verschiedene Entwicklungstools in einem Paket. So können Anwender(innen) nahtlos zwischen Funktionen hin- und herschalten.\n\nMan kann sich eine IDE wie einen Baukasten vorstellen, der eine zentrale Benutzeroberfläche sowie ein Netzwerk aus Modulen bietet, auf die Benutzer(innen) zugreifen können.\n\n## IDE vs Code-Editor vs Building-Tools\n\nDie ersten IDEs entstanden, als sich das Programmieren aus den Universitäten wegbewegte und Computer in der freien Wirtschaft Fuß zu fassen begannen.\n\nWeil IDEs verschiedene Tools integrieren, folgt ihre Entwicklung somit den Fortschritten, die in Entwicklungsanwendungen im Laufe der Jahre gemacht wurden. Compiler beispielsweise gab es bereits in den 1950ern, Code-Editoren hingegen kamen weitaus später hinzu.\n\nGemeinhin wird der Maestro I, der in München vom Unternehmen Softlab entwickelt wurde, als die erste kommerzielle IDE betrachtet. Der erste Maestro wurde 1977 verkauft und die Marke hatte bis in die frühen 1990er Jahre hinein einen signifikanten Kundenstamm. Insgesamt wurden 22000 Maestros installiert.\n\nSchon dieser Vorläufer vereinte die bis heute relevanten Kernfunktionalitäten eines Coding-Editors, Assemblers und Compilers. \n\n## Was sind die wichtigsten Komponenten einer IDE?\n\nWar der Maestro I wirklich die erste IDE? Dafür müssen wir uns noch weitere Aspekte ansehen, die eine IDE ausmachen. Einige der wichtigsten Bestandteile einer integrierten Entwicklungsumgebung haben wir bereits genannt:\n\nEin Coding-Editor\nBuilding-Tools, einschließlich Compiler und Packer\n\nDarüber hinaus beinhalten IDEs noch Fehlerbeseitigungs-Anwendungen, die für ein Debugging zur Verfügung stehen. \n\nAuch ist es möglich, IDEs in einen DevOps- oder Agile-Management-Prozess einzubinden. Durch diese Verknüpfung üben sie einen positiven Einfluss auf den gesamten Arbeitsprozess aus, der über das Programmieren hinausgeht. So profitiert unter anderem deine agile Planung von der Wahl der für dich und dein Team optimalen IDE.\n\nBetrachten wir diese verschiedenen Teile nun ein wenig genauer.\n\n### Code-Editor \n\nDer Code-Editor ist das Herzstück einer IDE. Auch deshalb ist die Vielfalt an Instrumenten, die Entwickler(innen) als Teil dieser Editoren zur Verfügung stehen, besonders groß.\n\nDazu gehören zum Beispiel:\nIntelligente Code-Vervollständigung: Ähnlich einer Auto-Complete-Funktion beim Smartphone schlagen moderne Coding-Editoren während des Programmierens die nächsten Zeilen vor und korrigieren offensichtliche syntaktische Fehler.\nDie IDE kümmert sich um einen korrekten, auf Lesbarkeit und Struktur optimierten Code. Dazu gehören das Refactoring (Reorganisation des Codes für maximale Effizienz), das farbliche Hervorheben unterschiedlicher Code-Bausteine sowie eine Prüfung für verschiedene Programmiersprachen.\nBegleitende Bug-Prüfung, das heißt, dass die IDE bereits während des Programmierens den gesamten Code auf innere Konsistenz hin untersucht.\nDas Programmieren ist der zentrale Teil der Arbeit an neuen Softwareprojekten. Doch damit eine Anwendung getestet werden kann, muss sie regelmäßig kompiliert werden.\n\nHierfür existieren spezialisierte Anwendungen, die sogenannten Compiler und Packer. Integrierte Entwicklungsumgebungen bieten diese in der Regel als Teil ihrer Basisfunktionalität an.\n\n### Building-Tools\n\nSogar Programmiersprachen mit einem hohen Abstraktionsgrad sind immer noch für Menschen ausgelegt. Damit Maschinen einen Code in einer Programmiersprache ausführen können, müssen die Daten in eine von Maschinen lesbare binäre Sprache übertragen werden.\n\nDie damit verbundenen Aufgaben werden von Compilern und Packern übernommen. Diese Anwendungen werden unter dem Oberbegriff „Building-Tools” zusammengefasst. Building-Tools vereinfachen den Prozess der Übersetzung, indem sie ihn automatisieren.\n\nBuilding-Tools sind heute ein integraler Teil von IDEs und erlauben es Teams, den gesamten Prozess des Programmierens über die Durchführung von Tests bis hin zur finalen Delivery innerhalb derselben Entwicklung durchzuführen und zu steuern.\n\n### Debugging\n\nHistorisch gesehen sind Debugger einer der Hauptgründe, warum Integrated Development Systems sich auf breiter Front durchgesetzt haben: Gerade beim Coden kann sich die Suche nach Fehlern als sehr aufwändig erweisen.\n\nDas ist zum einen ein Problem, wenn du auf kontinuierliche Verbesserung setzt und dazu das Produkt regelmäßig und oft testen möchtest. Wenn zu viele Fehler verhindern, dass du ein testfähiges Stadium erreichst, hemmt dies den gesamten Prozess und macht agiles Management unmöglich.\n\nNoch schwerwiegender wird es, wenn das Endprodukt von Fehlern betroffen ist, die seinen Nutzen für Kund(innen) reduzieren. Hier können effektive Debugger einen entscheidenden Beitrag leisten.\n\n## Warum wurden IDEs entwickelt? \n\nAn sich fällt die Beantwortung dieser Frage nicht schwer. Gemäß ihrer Definition schnüren IDEs Pakete aus miteinander verbundenen Anwendungen, die sich gegenseitig ergänzen.\n\nZusammen erlauben sie:\n\n- Fokussiertes Arbeiten und einen „sauberen” Code, der den Regeln der jeweiligen Programmiersprache folgt und optimal auf Lesbarkeit und Effizienz hin strukturiert ist.\n- Flexibilität im Hinblick einerseits auf die zu wählende Programmiersprache und andererseits für eine Vielzahl verschiedener Projekte.\n- Eine Reduzierung des Aufwands und der Kosten für einzelne Lizenzen. Gerade wenn Anwendungen auf einer SaaS-Basis erworben werden, häufen sich die Abonnements an.\n- Eine nahezu garantierte Kompatibilität der Anwendungen. Alles innerhalb einer IDE ist optimal aufeinander abgestimmt.\n- Ein nahtloses Springen zwischen verschiedenen Anwendungen, statt für jeden neuen Schritt im Arbeitsprozess die Aktivität unterbrechen zu müssen.\n\nZusammengefasst addieren sich die Punkte zu einer beträchtlichen Zeitersparnis. Darüber hinaus sorgen IDEs gerade in großen Teams oder Netzwerken aus Teams dafür, dass alle Beteiligten mit denselben Mitteln arbeiten und es nicht zu Kompatibilitätskonflikten kommt.\n\n## Gibt es unterschiedliche IDE-Typen?\n\nMan unterscheidet grundsätzlich drei verschiedene Formen von IDEs.\nCloudbasierte IDEs werden von allen Teammitgliedern geteilt und laufen oftmals über einen Browser. Sie bieten den großen Vorteil, dass der Zugriff von nahezu überall möglich ist und Teams dezentral an einem Projekt arbeiten können.\n\nLokale IDEs werden auf dem Rechner von  Mitarbeiter(inne)n gespeichert. Diese Form verliert zunehmend an Beliebtheit. Trotzdem haben sich Cloud-Lösungen noch nicht so durchgesetzt wie in anderen Bereichen der IT-Branche. Auf die Gründe dafür gehen wir gleich ein.\nStandardized Development Environments: Jedes Unternehmen hat seine eigenen Bedürfnisse. \n\nCloudbasierte und lokale Anwendungen mögen umfangreich und flexibel sein, doch bleiben sie letzten Endes generisch. Wenn du eine personalisierte Lösung für deine Teams bevorzugst, kann eine aus einzelnen Bausteinen zusammengesetzte, modulare IDE Sinn ergeben. Mit einer solchen SDE definierst du für dein Unternehmen einen eigenen Standard.\nFür manche Entwickler(innen) kommt noch eine vierte Variante hinzu: Eine komplett selbst zusammengestellte, personalisierte IDE. In besonders anspruchsvollen Projekten kann das Sinn ergeben. Für die meisten Unternehmen jedoch ergeben sich aus einer Vielzahl individueller Umgebungen zu viele Abstimmungsprobleme.\n\n## Wonach sollte ich meine IDE auswählen?\n\nDer Markt für IDEs ist inzwischen sogar für erfahrene Entwickler(innen) unübersichtlich geworden. Und so finden sich zahlreiche Foren, in denen man sich austauscht und berät, welche IDE für die eigenen Ziele am besten geeignet ist.\n\nNatürlich hängt diese Entscheidung unter anderem auch von dem Projekt ab, an dem du arbeitest. Darüber hinaus gibt es einige Aspekte, die du ebenfalls berücksichtigen solltest.\n\nDer erste ist, mit welcher Programmiersprache du vorhast, zu arbeiten. IDEs unterstützen eine Vielzahl von Sprachen, dennoch sind manche IDEs schlicht besser auf bestimmte Sprachen abgestimmt als auf andere.\n\nDas gleiche gilt für die Funktionalität. Die meisten Bausteine wirst du in jeder IDE finden. Trotzdem lohnt es sich, im Team nachzufragen, ob Wünsche bestehen, die eventuell nicht von jeder gängigen IDE abgedeckt werden.\n\nDie beiden wichtigsten Punkte bei der Auswahl der IDE sind aber zweifelsfrei Performance und Community Support. Da integrierte Entwicklungsebenen heutzutage so umfangreich sind, stellen sie oftmals auch eine Performance-Belastung für das System dar. Dies wiegt umso schwerer bei cloudbasierten IDEs. Communities wiederum bieten Unterstützung bei Problemen und treiben die Entwicklung der Software organisch voran. \n\n## Was ist die beste IDE?\n\nJeder Artikel, welcher dieser Frage nachgeht, fängt mit der Feststellung an, dass es keine beste IDE geben kann, da jede Aufgabe und jedes Team sehr spezifische Anforderungen und Präferenzen hat. Die Bewertung einer IDE ist somit unmittelbar mit der Definition der Aufgaben verbunden. \n\nDas ist ganz gewiss richtig. Dennoch fällt auf, dass, unabhängig von der Plattform oder dem Projekt, bestimmte IDEs von Experten weitaus öfter genannt werden als andere. Offenbar erfüllen manche integrierte Entwicklungsumgebungen die Bedürfnisse von breiten Anwender(innen)gruppen.\n\nUm dir einen besseren Überblick zu verschaffen, haben wir das Netz durchkämmt und die wichtigsten englischsprachigen Artikel sowie die am höchsten rankenden deutschen Artikel zu diesem Thema analysiert. \n\nAus diesen haben wir eine Rangliste erstellt. In den Klammern findest du die Zahl der Nennungen dieser IDE als eine der besten:\n\n1. Visual Studio (10x)\n2. Eclipse (8x)\n    IntelliJ (8x)\n    NetBeans (8x)\n5. Android (6x)\n    Code::Blocks (6x)\n7. Atom (5x)\n    PyCharm (5x)\n9. AWS Cloud 9 (4x)\n    RubyMine (4x)\n    WebStorm (4x)\n    Xcode (4x)\n    Zend (4x)\n\nAuch wenn jedes dieser Programme die Anforderungen an eine zeitgemäße IDE erfüllt, bestehen zwischen ihnen teilweise erhebliche Unterschiede. Werfen wir deswegen einen genaueren Blick auf einige IDE-Beispiele, um dies zu verdeutlichen.\n\n### IDE Eclipse\n\nWer sich mit der Geschichte von IDEs auseinandersetzt, wird zwangsläufig auf Eclipse IDE stoßen. Hierbei handelt es sich um eine integrierte Entwicklungsumgebung, die ursprünglich von IBM entwickelt wurde und nun als Freeware zur Verfügung steht. In einer schnelllebigen Branche ist Eclipse eine nahezu unvorstellbare Erfolgsgeschichte: Seit fast einem Vierteljahrhundert nutzen Entwickler(innen) diese Software, um an Projekten zu arbeiten.\n\nMan muss offen zugeben, dass der Zahn der Zeit nicht spurlos an Eclipse vorbeigegangen ist. Im direkten Vergleich zu aktuellen Alternativen hat die Oberfläche einen deutlichen Retro-Touch. Die Anwendung ist eher langsam und von gelegentlichen Abstürzen geplagt.\n\nDem steht allerdings ein umfangreicher Erfahrungsschatz gegenüber und eine nahezu endlose Palette an Erweiterungen und Plug-ins. Für manche Entwickler(innen) bietet Eclipse einen guten Workflow, den vermeintlich innovativere neue Lösungen immer noch nicht erreichen.\n\n### Dreamweaver\n\nDreamweaver ist ein interessantes Beispiel für eine spezialisierte IDE. Zwar verfügt die von Adobe vertriebene Anwendung auch über eine Code-Editor, der Dreamweaver zu einer vollwertigen IDE aufwertet, ihr Haupteinsatzgebiet aber ist die Website-Programmierung.\n\nViele Jahre lang war Dreamweaver in diesem Bereich der globale Führer. Für das Programm sprechen auch weiterhin seine Robustheit und die große User-Community, die gerne bei Problemen und Fragen behilflich ist. Der Editor erlaubt eine direkte Sicht auf die fertige Website, was vielen Entwicklern entgegenkommt.\n\nNachteilig aber ist, dass Dreamweaver sich in den letzten Jahren wenig weiterentwickelt hat und aus Sicht vieler professioneller Anwender(innen) nicht mehr sinnvoll für große kommerzielle Websites verwendet werden kann. Die Performance ist zudem nicht optimal und der von Dreamweaver generierte Code ein wenig „aufgebläht”.\n\nFür einfache Projekte aber kann Dreamweaver auch weiterhin eine hervorragende Lösung darstellen.\n\n### IntelliJ\n\nIntelliJ gilt bei vielen als die derzeit beste IDE.\n\nIn dieser Anwendung verbinden sich traditionelle Tugenden – ein großer Funktionsumfang, kostenlose Einstiegsversion – mit innovativen neuen Features und einer großen, umtriebigen Community. Zwar ist die kostenpflichtige Ultimate Edition mit einem Jahresbeitrag von knapp 560 Euro im Jahr nicht günstig, für viele Unternehmen ist die Investition ihr Geld aber wert.\n\nWer im Netz nach Erfahrungen mit der IntelliJ IDE sucht, wird gelegentlich Beschwerden finden, diese Integrated Development Environment sei langsam und die Ladezeiten seien recht hoch. Gemeinhin fallen die Ladezeiten aber nur beim Neustart negativ auf. Gegenüber der direkten Konkurrenz und vor allem gegenüber älteren Alternativen wie Eclipse fällt IntelliJ hier keineswegs ab.\n\nMan kann sagen, dass diese Beschwerden daher rühren, dass Anwender(innen) von IntelliJ besonders fortschrittlich denken und hohe Ansprüche haben. Bis jetzt hat sich das dahinterstehende Unternehmen Jetbrains mit seinen neuen Versionen immer wieder die Treue seiner Nutzer(innen) gesichert.\n\nIntelliJ mag nicht perfekt sein, derzeit aber kommt diese IDE dem Ideal einer IDE recht nahe. Überboten wird sie aus der Sicht von Entwickler(inne)n und Expert(inn)en, wenn überhaupt, nur von einem einzigen Konkurrenzprodukt:\n\n### IDE Visual Studio\n\nEs überrascht kaum, dass auf einem so begehrten Markt wie dem für integrierte Entwicklungsumgebungen auch die großen Global Players mitmischen wollen. So bietet Apple Xcode an, Google's Cloud Workstations beinhaltet eine webbasierte IDE und Amazon geht mit seiner AWS Cloud9 an den Start.\n\nKeine dieser IDEs aber erreicht den Stellenwert von Microsofts IDE Visual Studio. Eine der stärksten Funktionen dieser IDE liegt in ihrer nahtlosen, organischen und äußerst funktionalen Einbindung von KI. Aber ganz allgemein ist der Funktionsumfang der Software bemerkenswert. Es bleiben hier wahrhaft kaum Wünsche offen.\n\nAls die Website Onlinekurse das Visual Studio bewertete, fiel ihr nur ein einziger ernstzunehmender Einwand ein, der eher nach einem versteckten Kompliment als einer Kritik klingt: „[Die] Vielfalt an Optionen macht die Ersteinrichtung und Konfiguration schwierig.” \n\n### GitLab\n\nAuch GitLab hat eine eigene cloudbasierte IDE. Das ergibt Sinn, weil die direkte Einbindung in das Projektmanagement eine noch bessere Umsetzung agiler Methoden ermöglicht.\n\nMit der GitLab-IDE steht dir ein voll funktionsfähige integrierte Entwicklungsumgebung zur Verfügung. In einer ausführlichen Einführung und Übersicht in die GitLab-IDE kannst du dich informieren, ob sie für dich und dein Team eine gelungene Alternative zu den oben genannten Angeboten darstellt.\n\nWenn du die GitLab-IDE in der Praxis testen möchtest, nutze unsere GitLab-Testversion und arbeite 30 Tage kostenlos damit. \n\n## IDE-FAQs\n\n### Was ist die beste Einsteiger-IDE? Was ist die beste IDE für erfahrene Entwickler(innen)?\n\nDie Ansprüche von erfahrenen Entwickler(inne)n und Anfänger(inne)n an eine IDE unterscheiden sich erheblich.\n\nFür Anfänger(innen) ist es entscheidend, dass die Anwendung stabil läuft, eine klar strukturierte Oberfläche aufweist und die Basisfunktionen intuitiv zu bedienen sind. Eine allzu umfangreiche Palette an Möglichkeiten kann hier sogar einen Nachteil darstellen.\n\nFür professionelle, erfahrene Programmierer(innen) hingegen sind oftmals Performance und Individualisierungsfähigkeit wichtigere Faktoren. Für sie sind gelegentlich sogar Cloud-IDEs keine gute Option, da sie langsamer als lokale IDEs sind. Auch kann eine innovative Produktweiterentwicklung für sie einen höheren Stellenwert einnehmen als Stabilität.\nWährend IDEs als Alles-in-einem-Paketlösungen für Einsteiger(innen) ein hervorragendes Konzept bieten, präferieren manche Entwickler(innen) es, in einem einfachen Code-Editor zu arbeiten und für die darüber hinaus anfallenden Schritte jeweils individuelle Apps zu nutzen.\n\nVon den genannten IDEs bietet wohl das Visual Studio den besten Kompromiss, da es sowohl umfangreich und innovativ als auch einfach zu bedienen ist.\n\n### Hat die Verwendung von IDEs auch Nachteile?\n\nDie meisten IDEs funktionieren hervorragend und machen die Arbeit an einem Projekt deutlich einfacher. Trotzdem solltest du bei der Verwendung einer integrierten Entwicklungsumgebung stets beachten, dass es auch gewisse Nachteile gibt:\n\nPaketlösungen bieten in der Regel eine sehr gute Qualität ihrer Einzelanwendungen, die Komponenten erreichen aber eher selten Spitzenwerte. So ist es durchaus denkbar, dass bestimmte Individuallösungen besser sind als die entsprechenden Komponenten einer IDE.\nJede IDE wird die Performance einschränken, da bei ihr mehr Komponenten in den Speicher geladen werden als bei Einzelanwendungen. \n\nWer sich zu sehr auf ein bestimmtes System verlässt, bewegt sich zwangsläufig in Richtung eines „Lock-Ins”. Dieses Risiko ist natürlich auch bei IDEs gegeben. Allerdings ist es in den letzten Jahren gesunken, da IDEs zunehmend mit allgemeinen Standards arbeiten. So fällt der Wechsel von einer IDE zur anderen oftmals sehr undramatisch aus.\n",[788],"2025-05-14","2024-11-13","Was ist eine integrierte Entwicklungsumgebung (IDE)?",[835,858],"embedded DevOps","Der ultimative Guide: Alles, was du über Integrierte Entwicklungsumgebungen wissen musst.",{"slug":861,"featured":6,"template":672},"what-is-an-ide","content:de-de:blog:what-is-an-ide.yml","What Is An Ide","de-de/blog/what-is-an-ide.yml","de-de/blog/what-is-an-ide",{"_path":867,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":868,"content":874,"config":883,"_id":885,"_type":16,"title":886,"_source":17,"_file":887,"_stem":888,"_extension":20},"/de-de/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"title":869,"description":870,"ogTitle":869,"ogDescription":870,"noIndex":6,"ogImage":871,"ogUrl":872,"ogSiteName":758,"ogType":784,"canonicalUrls":872,"schema":873},"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":869,"description":870,"authors":875,"heroImage":871,"date":877,"body":878,"category":14,"tags":879,"updatedDate":882},[876],"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.",[110,880,881,834,680],"CI","CD","2024-11-05",{"slug":884,"featured":6,"template":672},"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":890,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":891,"content":897,"config":904,"_id":906,"_type":16,"title":907,"_source":17,"_file":908,"_stem":909,"_extension":20},"/de-de/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",{"title":892,"description":893,"ogTitle":892,"ogDescription":893,"noIndex":6,"ogImage":894,"ogUrl":895,"ogSiteName":758,"ogType":784,"canonicalUrls":895,"schema":896},"Einfaches Erstellen einer GitLab-CI/CD-Pipeline für ein Monorepo","Erfahre, wie du eine GitLab-CI/CD-Pipeline für ein Monorepo erstellst, um mehrere Anwendungen in einem Repository zu hosten.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749660151/Blog/Hero%20Images/blog-image-template-1800x945__26_.png","https://about.gitlab.com/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Einfaches Erstellen einer GitLab-CI/CD-Pipeline für ein Monorepo\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sam Morris\"}],\n        \"datePublished\": \"2024-07-30\",\n      }",{"title":892,"description":893,"authors":898,"heroImage":894,"date":900,"body":901,"category":14,"tags":902,"updatedDate":903},[899],"Sam Morris","2024-07-30","Mit Monorepos kannst du den Code von mehreren Anwendungen in einem einzigen Repository hosten. In GitLab bedeutet das, dass du den Quellcode verschiedener Anwendungen in getrennten Verzeichnissen in einem Projekt ablegen musst. So kannst du zwar deinen Code versionskontrolliert speichern, aber die [CI/CD-Pipeline von GitLab](https://about.gitlab.com/de-de/topics/ci-cd/) nicht voll ausschöpfen … bis jetzt!\n\n## Der Idealfall: CI/CD in einem Monorepo\n\nDa du mehr als den Code einer Anwendung in deinem Repository hast, wirst du mehr als eine Pipeline-Konfiguration benötigen. Wenn du z. B. eine .NET-Anwendung und eine Spring-Anwendung in einem Projekt hast, kann es sein, dass für jede Anwendung unterschiedliche Build- und Testjobs ausgeführt werden müssen. Im Idealfall kannst du die Pipelines vollständig entkoppeln und jede Pipeline nur auf der Grundlage von Änderungen am Quellcode der jeweiligen Anwendung ausführen.\n\nDer technische Ansatz hierfür wäre eine `.gitlab-ci.yml`-Pipeline-Konfigurationsdatei auf Projektebene, die eine bestimmte YAML-Datei enthält, die auf Änderungen in einem bestimmten Verzeichnis basiert. Die `.gitlab-ci.yml`-Pipeline dient als Steuerungsebene, die auf der Grundlage der Änderungen am Code die entsprechende Pipeline anstößt.\n\n## Der Legacy-Ansatz\n\nVor GitLab 16.4 war es nicht möglich, eine YAML-Datei bei Änderungen an einem Verzeichnis oder einer Datei in einem Projekt einzubinden. Wir konnten diese Funktionalität jedoch mit einem Workaround realisieren.\n\nIn unserem Monorepo-Projekt haben wir zwei Verzeichnisse für verschiedene Anwendungen. In diesem Beispiel gibt es die Verzeichnisse `java` und `python`, die jeweils eine Java- und eine Python-Anwendung repräsentieren. Jedes Verzeichnis hat eine anwendungsspezifische YAML-Datei, um jede App zu bauen. In der Pipeline-Datei des Projekts binden wir einfach beide Anwendungspipeline-Dateien ein und führen die logische Verarbeitung direkt in diesen Dateien durch.\n\n`.gitlab-ci.yml`:\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n  - local: '/python/py.gitlab-ci.yml'\n\n```\n\nIn jeder anwendungsspezifischen Pipeline-Datei erstellen wir einen versteckten Auftrag mit dem Namen .java-common oder .python-common, der nur ausgeführt wird, wenn es Änderungen im Verzeichnis der jeweiligen Anwendung gibt. [Versteckte Jobs (nur in englischer Sprache verfügbar](https://docs.gitlab.com/ee/ci/jobs/#hide-jobs) werden standardmäßig nicht ausgeführt und werden oft verwendet, um bestimmte Jobkonfigurationen wiederzuverwenden. Jede Pipeline erweitert diesen versteckten Job, um die Regeln zu übernehmen, die festlegen, welche Dateien auf Änderungen überwacht werden sollen, die dann den Pipeline-Job auslösen.\n\n`j.gitlab-ci.yml`:\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\n.java-common:\n  rules:\n    - changes:\n      - '../java/*'\n\njava-build-job:\n  extends: .java-common\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  extends: .java-common\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n```\n\n`py.gitlab-ci.yml`:\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\n.python-common:\n  rules:\n    - changes:\n      - '../python/*'\n\npython-build-job:\n  extends: .python-common\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  extends: .python-common\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n```\n\nDas hat einige Nachteile, z. B. muss der Job für jeden anderen Job in der YAML-Datei erweitert werden, um sicherzustellen, dass er mit den Regeln übereinstimmt, was eine Menge redundanten Code und Raum für menschliche Fehler schafft. Außerdem können erweiterte Jobs keine doppelten Schlüssel haben, so dass du nicht in jedem Job deine eigene `rules`-Logik definieren kannst, da es zu einer Kollision der Schlüssel kommen würde und ihre [Werte nicht zusammengeführt werden (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/yaml/index.html#extends). \n\nDas führt dazu, dass eine Pipeline ausgeführt wird, die die `j.gitlab-ci.yml`-Jobs enthält, wenn `java/` aktualisiert wird, und `py.gitlab-ci.yml`-Jobs, wenn `python/` aktualisiert wird.\n\n## Der neue Ansatz: Bedingtes Einbeziehen von Pipeline-Dateien\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/6phvk8jioAo?si=y6ztZODvUtM-cHmZ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nIn GitLab 16.4 haben wir [`include` mit `rules:changes` für Pipelines (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/yaml/includes.html#include-with-ruleschanges) eingeführt. Bisher konntest du `include` mit `rules:if` verwenden, aber nicht mit `rules:changes`. Das macht diese Aktualisierung extrem effizient. Jetzt kannst du einfach das Schlüsselwort `include` verwenden und die Monorepo-Regeln in deiner Projekt-Pipeline-Konfiguration definieren.\n\nNeue `.gitlab-ci.yml`:\n\n```\nstages:\n  - build\n  - test\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'java/*'\n  - local: '/python/py.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'python/*'\n\n```\n\nJetzt kann sich die YAML jeder Anwendung nur noch auf das Erstellen und Testen des Codes dieser Anwendung konzentrieren, ohne dass ein versteckter Job wiederholt erweitert werden muss. Das ermöglicht mehr Flexibilität bei der Definition von Jobs und reduziert das Neuschreiben von Code für Entwickler(innen).\n\nNeue `j.gitlab-ci.yml`:\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\njava-build-job:\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n```\n\nNeue `py.gitlab-ci.yml`:\n```\nstages:\n  - build\n  - test\n  - deploy\n\npython-build-job:\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n```\n\nDamit werden die Java- und Python-Jobs nur dann einbezogen, wenn ihre Verzeichnisse geändert werden. Bei deiner Implementierung solltest du bedenken, dass [Jobs unerwartet ausgeführt werden können, wenn du `changes` verwendest (nur in englischer Sprache verfügbar)](https://docs.gitlab.com/ee/ci/jobs/job_troubleshooting.html#jobs-or-pipelines-run-unexpectedly-when-using-changes). Die Regel „changes“ wird immer als wahr interpretiert, wenn ein neuer Branch oder ein neues Tag in GitLab gepusht wird, so dass alle Jobs unabhängig von der Definition von `rules:changes` beim ersten Push in einen Branch ausgeführt werden. Du kannst dieses Problem umgehen, indem du zuerst deinen Feature-Branch erstellst und dann eine Merge Request öffnest, um mit der Entwicklung zu beginnen, da der erste Push auf den Branch, wenn er erstellt wird, alle Jobs zur Ausführung zwingt.\n\nLetztlich sind Monorepos eine Strategie, die mit GitLab und CI/CD genutzt werden kann. Mit unserer neuen Funktion `include` mit `rules:changes` haben wir eine bessere bewährte Methode für die Nutzung von GitLab CI mit Monorepos. Um Monorepos zu verwenden, hol dir noch heute eine kostenlose Testversion von Gitlab Ultimate.\n\n## Weitere CI/CD-Ressourcen\n\n* [5 Tipps für die Verwaltung von Monorepos in GitLab (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/tips-for-managing-monorepos-in-gitlab/)\n* [Der schnelle Einstieg in CI/CD (nur in englischer Sprache verfügbar)](https://about.gitlab.com/blog/how-to-learn-ci-cd-fast/)",[110,680],"2025-05-26",{"slug":905,"featured":6,"template":672},"building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","content:de-de:blog:building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way.yml","Building A Gitlab Ci Cd Pipeline For A Monorepo The Easy Way","de-de/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way.yml","de-de/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",{"_path":911,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":912,"content":918,"config":926,"_id":928,"_type":16,"title":929,"_source":17,"_file":930,"_stem":931,"_extension":20},"/de-de/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"title":913,"description":914,"ogTitle":913,"ogDescription":914,"noIndex":6,"ogImage":915,"ogUrl":916,"ogSiteName":758,"ogType":784,"canonicalUrls":916,"schema":917},"Effiziente DevSecOps-Workflows: Praktische python-gitlab-API-Automatisierung","Die Python-GitLab-Bibliothek ist eine nützliche Basis für die GitLab-API. In diesem Tutorial erfährst du mehr über praktische Beispiele und bewährte Verfahren.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659883/Blog/Hero%20Images/post-cover-image.jpg","https://about.gitlab.com/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Effiziente DevSecOps-Workflows: Praktische python-gitlab-API-Automatisierung\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Michael Friedrich\"}],\n        \"datePublished\": \"2023-02-01\",\n      }",{"title":913,"description":914,"authors":919,"heroImage":915,"date":921,"body":922,"category":14,"tags":923,"updatedDate":925},[920],"Michael Friedrich","2023-02-01","Ein oft zitiertes Sprichwort aus einer Konferenzpräsentation lautet:\n„Manuelle Arbeit ist ein Fehler“. Bei sich wiederholenden Aufgaben in\nArbeitsabläufen ist es ratsam, so viel wie möglich zu automatisieren. Ein\nBeispiel dafür ist die Nutzung einer REST-API zur Bestandsaufnahme von\nEinstellungen oder das Erstellen neuer Kommentare in GitLab-Issues und\nMerge-Anfragen mittels API-Aktionen.\n\n\n## GitLab-API-Interaktion: Möglichkeiten und Unterstützung durch\nAPI-Abstraktionsbibliotheken\n\n\nDie Interaktion mit der REST-API von GitLab kann auf verschiedene Weise\nerfolgen: entweder durch HTTP-Anfragen mit curl (oder hurl) in der\nBefehlszeile oder durch das Schreiben von Skripten in einer\nProgrammiersprache. Letzteres kann dazu führen, dass der Code für\nHTTP-Anfragen und das Parsen der JSON-Antworten neu entwickelt werden muss.\nGlücklicherweise unterstützt die umfangreiche GitLab-Community viele\nProgrammiersprachen mit API-Abstraktionsbibliotheken.\n\n\nDiese Bibliotheken bieten Unterstützung für alle API-Attribute, fügen\nHilfsfunktionen zum Abrufen, Erstellen und Löschen von Objekten hinzu und\nhelfen Entwicklern dabei, sich auf ihre Kernaufgaben zu konzentrieren. Die\n[python-gitlab Bibliothek](https://python-gitlab.readthedocs.io/en/stable/)\nist ein besonders funktionsreiches und einfach zu verwendendes Beispiel für\neine solche Bibliothek in Python.\n\n\nIn diesem Blogbeitrag wird die grundlegende Nutzung der\npython-gitlab-Bibliothek erläutert, einschließlich der Arbeit mit\nAPI-Objekten, Attributen, Paginierung und Resultsets. Zudem werden\nspezifischere Anwendungsfälle vorgestellt, in denen Daten gesammelt,\nZusammenfassungen gedruckt und Daten in die API geschrieben werden, um\nKommentare und Commits zu erstellen. Viele dieser Anwendungsfälle basieren\nauf Fragen aus der Community in Foren, auf Hacker News oder in Issues.\n\n\n## Inhaltsverzeichnis\n\n- [GitLab-API-Interaktion: Möglichkeiten und Unterstützung durch\nAPI-Abstraktionsbibliotheken](#gitlab-api-interaktion-möglichkeiten-und-unterstützung-durch-api-abstraktionsbibliotheken)\n\n- [Los geht's: python-gitlab Install](#los-geht's-python-gitlab-install)\n\n- [GitLab API Python: Konfiguration](#gitlab-api-python-konfiguration)\n\n- [Objekte verwalten: das\nGitLab-Objekt](#objekte-verwalten-das-gitlab-objekt)\n  - [Objektmanager und Laden von Objekten](#objektmanager-und-laden-von-objekten)\n  - [Paginierung der Ergebnisse](#paginierung-der-ergebnisse)\n  - [Arbeiten mit Objektbeziehungen](#arbeiten-mit-objektbeziehungen)\n  - [Arbeiten mit verschiedenen Objektsammlungsbereichen](#arbeiten-mit-verschiedenen-objektsammlungsbereichen)\n- [DevSecOps-Anwendungsfälle für\nAPI-Leseaktionen](#devsecops-anwendungsfälle-für-api-leseaktionen)\n  - [Zweige nach Zusammenführungsstatus auflisten](#zweige-nach-zusammenführungsstatus-auflisten)\n  - [Drucken von Projekteinstellungen zur Überprüfung: MR-Genehmigungsregeln](#drucken-von-projekteinstellungen-zur-überprüfung-mr-genehmigungsregeln)\n  - [Inventarisierung: Abrufen aller CI/CD-Variablen, die geschützt oder maskiert sind](#inventarisierung-abrufen-aller-cicd-variablen-die-geschützt-oder-maskiert-sind)\n  - [Herunterladen einer Datei aus dem Repository](#herunterladen-einer-datei-aus-dem-repository)\n  - [Hilfe zur Migration: Auflistung aller zertifikatsbasierten Kubernetes-Cluster](#hilfe-zur-migration-auflistung-aller-zertifikatsbasierten-kubernetes-cluster)\n  - [Team-Effizienz: Prüfe, ob bestehende Merge-Requests nach dem Mergen einer großen Refactoring-MR neu gebasht werden müssen](#team-effizienz-prüfe-ob-bestehende-merge-requests-nach-dem-mergen-einer-großen-refactoring-mr-neu-gebasht-werden-müssen)\n- [DevSecOps-Anwendungsfälle für\nAPI-Schreibaktionen](#devsecops-anwendungsfälle-für-api-schreibaktionen)\n  - [Verschieben von Epics zwischen Gruppen](#verschieben-von-epics-zwischen-gruppen)\n  - [Automatisierung des Verschiebens von Epics](#automatisierung-des-verschiebens-von-epics)\n  - [Compliance: Sicherstellen, dass Projekteinstellungen nicht überschrieben werden](#compliance-sicherstellen-dass-projekteinstellungen-nicht-überschrieben-werden)\n  - [Notizen machen, Fälligkeitsübersicht erstellen](#notizen-machen-fälligkeitsübersicht-erstellen)\n\n## Los geht's: python-gitlab Install\n\n\nDie Dokumentation von python-gitlab bietet eine umfassende Einführung in die\nNutzung, einschließlich Anleitungen für den Einstieg, Informationen zu\nObjekttypen und deren Methoden sowie kombinierte Workflow-Beispiele.\nErgänzend dazu ist die Dokumentation der GitLab-API-Ressourcen hilfreich, da\nsie die verfügbaren Objektattribute detailliert beschreibt. Zusammen sind\ndiese beiden Dokumentationen die besten Ressourcen für den Einstieg.\n\n\nDie Code-Beispiele in diesem Blogbeitrag setzen Python 3.8+ und die\npython-gitlab-Bibliothek voraus. Weitere notwendige Abhängigkeiten sind in\nder Datei requirements.txt aufgeführt. Ein Beispiel erfordert die Bibliothek\npyyaml zum Parsen von YAML-Konfigurationen. Um den Code der Anwendungsfälle\nnachzuvollziehen und zu üben, empfiehlt es sich, das Projekt zu klonen, die\nAnforderungen zu installieren und die Skripte auszuführen.\n\n\n```shell\n\ngit clone\nhttps://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python.git\n\n\ncd gitlab-api-python\n\n\nbrew install python\n\n\npip3 install -r requirements.txt\n\n\npython3 \u003Cscriptname>.py\n\n```\n\nDie Skripte verwenden absichtlich keine gemeinsam genutzte Bibliothek, die\nz. B. generische Funktionen für das Lesen von Parametern oder zusätzliche\nHilfsfunktionen bereitstellt. Die Idee ist, einfach zu verstehende Beispiele\nzu zeigen, die eigenständig zum Testen verwendet werden können und lediglich\ndie Installation der python-gitlab-Bibliothek erfordern.\n\n\nEs wird empfohlen, den Code für den Produktionseinsatz zu verbessern. Dies\nkann auch beim Aufbau eines gewarteten API-Tooling-Projekts helfen, das z.\nB. Container-Images und CI/CD-Vorlagen für Entwickler enthält, die auf einer\nDevSecOps-Plattform genutzt werden können.\n\n\n## GitLab API Python: Konfiguration\n\n\nOhne Konfiguration führt python-gitlab unauthentifizierte Anfragen an den\nStandardserver https://gitlab.com aus. Die häufigsten\nKonfigurationseinstellungen beziehen sich auf die GitLab-Instanz, mit der\neine Verbindung hergestellt werden soll, und die Authentifizierungsmethode\ndurch Angabe von Zugriffstokens. python-gitlab unterstützt verschiedene\nArten der Konfiguration: Eine Konfigurationsdatei oder Umgebungsvariablen.\n\n\nDie Konfigurationsdatei ist für die API-Bibliotheksbindungen und die CLI\nverfügbar (die CLI wird in diesem Blogpost nicht erläutert). Die\nKonfigurationsdatei unterstützt Credential Helpers für den direkten Zugriff\nauf Token.\n\n\nUmgebungsvariablen als alternative Konfigurationsmethode bieten eine\neinfache Möglichkeit, das Skript auf dem Terminal auszuführen, in\nContainer-Images zu integrieren und sie für die Ausführung in\nCI/CD-Pipelines vorzubereiten.\n\n\nDie Konfiguration muss in den Kontext des Python-Skripts geladen werden.\nBeginne mit dem Import der os-Bibliothek, um die Umgebungsvariablen mit der\nMethode os.environ.get() abzurufen. Der erste Parameter gibt den Schlüssel\nan, der zweite Parameter legt den Standardwert fest, wenn die Variable in\nder Umgebung nicht verfügbar ist.\n\n\n```python\n\nimport os\n\n\ngl_server = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n\nprint(gl_server)\n\n```\n\n\nDie Parametrisierung auf dem Terminal kann direkt nur für den Befehl\nerfolgen oder in die Shell-Umgebung exportiert werden.\n\n\n```shell\n\n$ GL_SERVER=’https://gitlab.company.com’ python3 script.py\n\n\n$ export GL_SERVER=’https://gitlab.company.com’\n\n$ python3 script.py\n\n```\n\n\nEs wird empfohlen, Sicherheitsprüfungen hinzuzufügen, um sicherzustellen,\ndass alle Variablen gesetzt sind, bevor das Programm weiter ausgeführt wird.\nDer folgende Ausschnitt importiert die erforderlichen Bibliotheken, liest\ndie Umgebungsvariable GL_SERVER und erwartet, dass der Benutzer die Variable\nGL_TOKEN setzt. Wenn dies nicht der Fall ist, gibt das Skript Fehler aus und\nruft sys.exit(1) auf, um einen Fehlerstatus anzuzeigen.\n\n\n```python\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n```\n\n\nFolgend siehst du ein ausführlicheres Beispiel, das eine Verbindung zur API\nherstellt und eine tatsächliche Datenabfrage durchführt.\n\n\n## Objekte verwalten: das GitLab-Objekt\n\n\nFür jede Interaktion mit der API muss das GitLab-Objekt instanziiert werden.\nDies ist der Einstiegspunkt für die Konfiguration des GitLab-Servers für die\nVerbindung, die Authentifizierung mithilfe von Zugriffstokens und weitere\nglobale Einstellungen für die Paginierung, das Laden von Objekten und mehr.\n\n\nIm folgenden Beispiel wird eine nicht authentifizierte Anfrage an gitlab.com\nausgeführt. Es ist möglich, auf öffentliche API-Endpunkte zuzugreifen und\nzum Beispiel eine bestimmte [.gitignore Vorlage für\nPython](https://python-gitlab.readthedocs.io/en/stable/gl_objects/templates.html#gitignore-templates)\nabzurufen.\n\n\n[python_gitlab_object_unauthenticated.py](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_object_unauthenticated.py)\n\n\n```python\n\nimport gitlab\n\n\ngl = gitlab.Gitlab()\n\n\n# Get .gitignore templates without authentication\n\ngitignore_templates = gl.gitignores.get('Python')\n\n\nprint(gitignore_templates.content)\n\n```\n\n\nDie nächsten Abschnitte geben weitere Einblicke in:\n\n\n- Objektmanager und Laden von Objekten\n\n- Paginierung von Ergebnissen\n\n- Arbeiten mit Objektbeziehungen\n\n- Arbeiten mit verschiedenen Objektsammlungsbereichen\n\n\n### Objektmanager und Laden von Objekten\n\n\nDie python-gitlab-Bibliothek ermöglicht den Zugriff auf GitLab-Ressourcen\nüber sogenannte\n„[Manager](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#managers)\".\nJeder Managertyp implementiert Methoden zur Arbeit mit den Datensätzen\n(list, get, etc.).\n\n\nDas Skript zeigt, wie man auf Untergruppen, direkte Projekte, alle Projekte\neinschließlich Untergruppen, Issues, Epics und To-dos zugreifen kann. Diese\nMethoden und der API-Endpunkt erfordern eine Authentifizierung für den\nZugriff auf alle Attribute. Der Codeschnipsel verwendet daher Variablen, um\ndas Authentifizierungs-Token abzurufen sowie die GROUP_ID-Variable, um eine\nHauptgruppe anzugeben, bei der die Suche beginnen soll.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-de/use-cases/\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\nmain_group = gl.groups.get(GROUP_ID)\n\n\nprint(\"Sub groups\")\n\nfor sg in main_group.subgroups.list():\n    print(\"Subgroup name: {sg}\".format(sg=sg.name))\n\nprint(\"Projects (direct)\")\n\nfor p in main_group.projects.list():\n    print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Projects (including subgroups)\")\n\nfor p in main_group.projects.list(include_subgroups=True, all=True):\n     print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Issues\")\n\nfor i in main_group.issues.list(state='opened'):\n    print(\"Issue title: {t}\".format(t=i.title))\n\nprint(\"Epics\")\n\nfor e in main_group.issues.list():\n    print(\"Epic title: {t}\".format(t=e.title))\n\nprint(\"Todos\")\n\nfor t in gl.todos.list(state='pending'):\n    print(\"Todo: {t} url: {u}\".format(t=t.body, u=t.target_url\n```\n\n\nDu kannst das Skript\n[`python_gitlab_object_manager_methods.py`](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_object_manager_methods.py)\nausführen, indem du die GROUP_ID-Variable auf GitLab.com SaaS für deine\neigene zu analysierende Gruppe überschreibst. Die Variable GL_SERVER muss\nfür selbstverwaltete Instanzziele angegeben werden. GL_TOKEN muss das\npersönliche Zugriffstoken enthalten.\n\n\n```shell\n\nexport GL_TOKEN=xxx\n\n\nexport GL_SERVER=”https://gitlab.company.com”\n\n\nexport GL_SERVER=”https://gitlab.com”\n\n\nexport GL_GROUP_ID=1234\n\n\npython3 python_gitlab_object_manager_methods.py\n\n```\n\nIn Zukunft werden die Beispiel-Snippets die Python-Header und das Parsen von\nUmgebungsvariablen nicht mehr zeigen, um sich auf den Algorithmus und die\nFunktionalität zu konzentrieren. Alle Skripte sind Open Source unter der\nMIT-Lizenz und in [diesem\nProjekt](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python)\nverfügbar.\n\n\n### Paginierung der Ergebnisse\n\n\nStandardmäßig gibt die GitLab-API nicht alle Ergebnissätze zurück und\nerfordert, dass die Clients die Paginierung verwenden, um durch alle\nErgebnisseiten zu iterieren. Mit der python-gitlab-Bibliothek können\nBenutzer die Einstellungen global im GitLab-Objekt oder bei jedem\nlist()-Aufruf\n[festlegen](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination).\nStandardmäßig würden alle Ergebnissätze API-Anfragen auslösen, was die\nSkriptausführung verlangsamen kann. Die empfohlene Methode ist die\nVerwendung von iterator=True, die ein Generatorobjekt zurückgibt, und\nAPI-Aufrufe werden beim Zugriff auf das Objekt bei Bedarf ausgelöst.\n\n\nDas folgende Beispiel sucht nach dem Gruppennamen everyonecancontribute und\nverwendet eine\n[Paginierung](https://docs.gitlab.com/ee/api/rest/index.html#pagination) der\nSchlüsselsätze mit 100 Ergebnissen auf jeder Seite. Der Iterator wird bei\ngl.groups.list(iterator=True) auf true gesetzt, um bei Bedarf neue\nErgebnissätze abzurufen. Wird der gesuchte Gruppenname gefunden, bricht die\nSchleife ab und gibt eine Zusammenfassung aus, einschließlich der Messung\nder Dauer der gesamten Suchanfrage.\n\n\n```python\n\nSEARCH_GROUP_NAME=\"everyonecancontribute\"\n\n\n# Use keyset pagination\n\n# https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN,\n    pagination=\"keyset\", order_by=\"id\", per_page=100)\n\n# Iterate over the list, and fire new API calls in case the result set does\nnot match yet\n\ngroups = gl.groups.list(iterator=True)\n\n\nfound_page = 0\n\nstart = timer()\n\n\nfor group in groups:\n    if SEARCH_GROUP_NAME == group.name:\n        # print(group) # debug\n        found_page = groups.current_page\n        break\n\nend = timer()\n\n\nduration = f'{end-start:.2f}'\n\n\nif found_page > 0:\n    print(\"Pagination API example for Python with GitLab{desc} - found group {g} on page {p}, duration {d}s\".format(\n        desc=\", the DevSecOps platform\", g=SEARCH_GROUP_NAME, p=found_page, d=duration))\nelse:\n    print(\"Could not find group name '{g}', duration {d}\".format(g=SEARCH_GROUP_NAME, d=duration))\n```\n\n\nBeim Ausführen von python_gitlab_pagination.py wurde die Gruppe\n[everyonecancontribute](https://gitlab.com/everyonecancontribute) auf Seite\n5 gefunden.\n\n\n```shell\n\n$ python3 python_gitlab_pagination.py\n\nPagination API example for Python with GitLab, the DevSecOps platform -\nfound group everyonecancontribute on page 5, duration 8.51s\n\n```\n\n\n### Arbeiten mit Objektbeziehungen\n\n\nBei der Arbeit mit Objektbeziehungen – z. B. beim Sammeln aller Projekte in\neiner bestimmten Gruppe – müssen zusätzliche Schritte unternommen werden.\nDie zurückgegebenen Projektobjekte enthalten standardmäßig nur begrenzte\nAttribute. Für verwaltbare Objekte ist ein zusätzlicher get()-Aufruf\nerforderlich, der das vollständige Projektobjekt von der API im Hintergrund\nanfordert. Dieser On-Demand-Workflow hilft, Wartezeiten und Datenverkehr zu\nvermeiden, indem er die sofort zurückgegebenen Attribute reduziert.\n\n\nDas folgende Beispiel veranschaulicht das Problem, indem es eine Schleife\ndurch alle Projekte in einer Gruppe durchläuft und versucht, die Funktion\nproject.branches.list() aufzurufen, was eine Ausnahme im try/except-Flow\nauslöst. Im zweiten Beispiel wird ein verwaltbares Projektobjekt ermittelt\nund der Funktionsaufruf erneut versucht.\n\n\n```python\n\n# Main\n\ngroup = gl.groups.get(GROUP_ID)\n\n\n# Collect all projects in group and subgroups\n\nprojects = group.projects.list(include_subgroups=True, all=True)\n\n\nfor project in projects:\n    # Try running a method on a weak object\n    try:\n       print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=project.name,\n        b=\", \".join([x.name for x in project.branches.list()])))\n    except Exception as e:\n        print(\"Got exception: {e} \\n ===================================== \\n\".format(e=e))\n\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # Print a method available on a manageable object\n    print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=manageable_project.name,\n        b=\", \".join([x.name for x in manageable_project.branches.list()])))\n```\n\n\nDer Exception-Handler in der python-gitlab-Bibliothek gibt die Fehlermeldung\naus und verlinkt auch auf die Dokumentation. Es ist hilfreich, bei der\nFehlersuche zu beachten, dass Objekte möglicherweise nicht verwaltet werden\nkönnen, wenn du nicht auf Objektattribute oder Funktionsaufrufe zugreifen\nkannst.\n\n\n```shell\n\n$ python3 python_gitlab_manageable_objects.py\n\n\n🤔 Project: GitLab API Playground 💡 Branches: cicd-demo-automated-comments,\ndocs-mr-approval-settings, main\n\n\nGot exception: 'GroupProject' object has no attribute 'branches'\n\n\n\u003Cclass 'gitlab.v4.objects.projects.GroupProject'> was created via a\n\nlist() call and only a subset of the data may be present. To ensure\n\nall data is present get the object using a get(object.id) call. For\n\nmore details, see:\n\n\nhttps://python-gitlab.readthedocs.io/en/v3.8.1/faq.html#attribute-error-list\n =====================================\n```\n\n\nHier findest du das vollständige\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_manageable_objects.py).\n\n\n### Arbeiten mit verschiedenen Objektsammlungsbereichen\n\n\nManchmal muss das Skript alle Projekte aus einer selbstverwalteten Instanz,\naus einer Gruppe mit Untergruppen oder aus einem einzelnen Projekt sammeln.\nLetzteres ist hilfreich, um die erforderlichen Attribute schneller testen zu\nkönnen, und der Gruppenabruf hilft später beim Testen im großen Maßstab. Das\nfolgende Snippet sammelt alle Projektobjekte in der projects-Liste und fügt\nObjekte aus verschiedenen eingehenden Konfigurationen hinzu. Du wirst auch\nwieder das verwaltbare Objektmuster für Projekte in Gruppen sehen.\n\n\n```python\n    # Collect all projects, or prefer projects from a group id, or a project id\n    projects = []\n\n    # Direct project ID\n    if PROJECT_ID:\n        projects.append(gl.projects.get(PROJECT_ID))\n\n    # Groups and projects inside\n    elif GROUP_ID:\n        group = gl.groups.get(GROUP_ID)\n\n        for project in group.projects.list(include_subgroups=True, all=True):\n            # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n            manageable_project = gl.projects.get(project.id)\n            projects.append(manageable_project)\n\n    # All projects on the instance (may take a while to process)\n    else:\n        projects = gl.projects.list(get_all=True)\n```\n\n\nDas vollständige Beispiel befindet sich in [diesem\nSkript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py)\nfür die Auflistung der Einstellungen der MR-Genehmigungsregeln für bestimmte\nProjektziele.\n\n\n## DevSecOps-Anwendungsfälle für API-Leseaktionen\n\n\nDas authentifizierte Zugriffstoken benötigt den Bereich [`read_api`\nscope](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-token-scopes).\n\n\nDie folgenden Anwendungsfälle werden diskutiert:\n\n\n- Zweige nach Zusammenführungsstatus auflisten\n\n- Drucken von Projekteinstellungen zur Überprüfung: MR-Genehmigungsregeln\n\n- Inventarisierung: Abrufen aller CI/CD-Variablen, die geschützt oder\nmaskiert sind\n\n- Herunterladen einer Datei aus dem Repository\n\n- Hilfe zur Migration: Auflistung aller zertifikatsbasierten\nKubernetes-Cluster\n\n- Team-Effizienz: Prüfen Sie, ob bestehende Merge-Requests nach dem Mergen\neiner großen Refactoring-MR neu gebasht werden müssen\n\n\n### Zweige nach Zusammenführungsstatus auflisten\n\n\nEin häufiges Anliegen ist es, in einem Projekt ein wenig Git-Housekeeping zu\nbetreiben und zu sehen, wie viele zusammengeführte und nicht\nzusammengeführte Zweige im Umlauf sind. Eine\n[Frage](https://forum.gitlab.com/t/python-gitlab-project-branch-list-filter/80257)\nim GitLab-Community-Forum zum Filtern von Zweiglisten hat mich dazu\ninspiriert, ein\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_branches_by_state.py)\nzu schreiben, mit dem sich dieses Ziel erreichen lässt. Die Methode\nbranches.list() gibt alle Zweigobjekte zurück, die in einer temporären Liste\nfür die spätere Verarbeitung in zwei Schleifen gespeichert werden: Sammeln\nder Namen der zusammengeführten Zweige und der Namen der nicht\nzusammengeführten Zweige. Das Attribut merged des branch-Objekts ist ein\nboolescher Wert, der angibt, ob der Zweig zusammengeführt wurde.\n\n\n```python\n\nproject = gl.projects.get(PROJECT_ID, lazy=False, pagination=\"keyset\",\norder_by=\"updated_at\", per_page=100)\n\n\n# Get all branches\n\nreal_branches = []\n\nfor branch in project.branches.list():\n    real_branches.append(branch)\n\nprint(\"All branches\")\n\nfor rb in real_branches:\n    print(\"Branch: {b}\".format(b=rb.name))\n\n# Get all merged branches\n\nmerged_branches_names = []\n\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if branch.merged:\n        merged_branches_names.append(branch.name)\n\nprint(\"Branches merged: {b}\".format(b=\", \".join(merged_branches_names)))\n\n\n# Get un-merged branches\n\nnot_merged_branches_names = []\n\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if not branch.merged:\n        not_merged_branches_names.append(branch.name)\n\nprint(\"Branches not merged: {b}\".format(b=\",\n\".join(not_merged_branches_names)))\n\n```\n\n\nDer Arbeitsablauf ist absichtlich schrittweise zu lesen. Du kannst die\nOptimierung des Python-Codes für die bedingte Zweignamensammlung üben.\n\n\n### Drucken von Projekteinstellungen zur Überprüfung: MR-Genehmigungsregeln\n\n\nDas folgende\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py)\ngeht durch alle gesammelten Projektobjekte und prüft, ob Genehmigungsregeln\nangegeben sind. Wenn die Länge der Liste größer als Null ist, durchläuft es\ndie Liste in einem Loop und druckt die Einstellungen mit einer JSON-Ph\npretty-print-Methode aus.\n\n\n```python\n    # Loop over projects and print the settings\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_request_approvals.html\n    for project in projects:\n        if len(project.approvalrules.list()) > 0:\n            #print(project) #debug\n            print(\"# Project: {name}, ID: {id}\\n\\n\".format(name=project.name_with_namespace, id=project.id))\n            print(\"[MR Approval settings]({url}/-/settings/merge_requests)\\n\\n\".format(url=project.web_url))\n\n            for ar in project.approvalrules.list():\n                print(\"## Approval rule: {name}, ID: {id}\".format(name=ar.name, id=ar.id))\n                print(\"\\n```json\\n\")\n                print(json.dumps(ar.attributes, indent=2)) # TODO: can be more beautiful, but serves its purpose with pretty print JSON\n                print(\"\\n```\\n\")\n\n```\n\n\n### Inventarisierung: Abrufen aller CI/CD-Variablen, die geschützt oder\nmaskiert sind\n\n\n[CI/CD Variablen](https://docs.gitlab.com/ee/ci/variables/) sind hilfreich\nfür die Pipeline-Parametrisierung und können global auf der Instanz, in\nGruppen und in Projekten konfiguriert werden. Auch Daten, Passwörter und\nandere sensible Informationen können dort gespeichert werden. Manchmal kann\nes notwendig sein, sich einen Überblick über alle CI/CD-Variablen zu\nverschaffen, die entweder geschützt oder maskiert sind, um ein Gefühl dafür\nzu bekommen, wie viele Variablen aktualisiert werden müssen, wenn Token zum\nBeispiel rotieren.\n\n\nDas folgende\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_all_cicd_variables_masked_or_protected.py)\nruft alle Gruppen und Projekte ab und versucht, die CI/CD-Variablen der\nglobalen Instanz (erfordert Admin-Rechte), der Gruppen und Projekte\n(erfordert Maintainer-/Eigentümer-Rechte) zu sammeln. Es gibt alle\nCI/CD-Variablen aus, die entweder geschützt oder maskiert sind, und fügt\nhinzu, dass ein möglicher geheimer Wert gespeichert ist.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\n# Helper function to evaluate secrets and print the variables\n\ndef eval_print_var(var):\n    if var.protected or var.masked:\n        print(\"🛡️🛡️🛡️ Potential secret: Variable '{name}', protected {p}, masked: {m}\".format(name=var.key,p=var.protected,m=var.masked))\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN') # token requires maintainer+\npermissions. Instance variables require admin access.\n\nPROJECT_ID = os.environ.get('GL_PROJECT_ID') #optional\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 8034603) #\nhttps://gitlab.com/everyonecancontribute\n\n\nif not GITLAB_TOKEN:\n    print(\"🤔 Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Collect all projects, or prefer projects from a group id, or a project id\n\nprojects = []\n\n# Collect all groups, or prefer group from a group id\n\ngroups = []\n\n\n# Direct project ID\n\nif PROJECT_ID:\n    projects.append(gl.projects.get(PROJECT_ID))\n\n# Groups and projects inside\n\nelif GROUP_ID:\n    group = gl.groups.get(GROUP_ID)\n\n    for project in group.projects.list(include_subgroups=True, all=True):\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n        projects.append(manageable_project)\n\n    groups.append(group)\n\n# All projects/groups on the instance (may take a while to process, use\niterators to fetch on-demand).\n\nelse:\n    projects = gl.projects.list(iterator=True)\n    groups = gl.groups.list(iterator=True)\n\nprint(\"# List of all CI/CD variables marked as secret (instance, groups,\nprojects)\")\n\n\n# https://python-gitlab.readthedocs.io/en/stable/gl_objects/variables.html\n\n\n# Instance variables (if the token has permissions)\n\nprint(\"Instance variables, if accessible\")\n\ntry:\n    for i_var in gl.variables.list(iterator=True):\n        eval_print_var(i_var)\nexcept:\n    print(\"No permission to fetch global instance variables, continueing without.\")\n    print(\"\\n\")\n\n# group variables (maintainer permissions for groups required)\n\nfor group in groups:\n    print(\"Group {n}, URL: {u}\".format(n=group.full_path, u=group.web_url))\n    for g_var in group.variables.list(iterator=True):\n        eval_print_var(g_var)\n\n    print(\"\\n\")\n\n# Loop over projects and print the settings\n\nfor project in projects:\n    # skip archived projects, they throw 403 errors\n    if project.archived:\n        continue\n\n    print(\"Project {n}, URL: {u}\".format(n=project.path_with_namespace, u=project.web_url))\n    for p_var in project.variables.list(iterator=True):\n        eval_print_var(p_var)\n\n    print(\"\\n\")\n```\n\nDas Skript druckt die Variablenwerte absichtlich nicht aus; dies soll als\nÜbung für sichere Umgebungen dienen. Für die Speicherung von Daten empfiehlt\nsich die Verwendung [externer\nAnbieter](https://docs.gitlab.com/ee/ci/secrets/).\n\n\n### Herunterladen einer Datei aus dem Repository\n\n\nZiel des\n[Skripts](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_raw_file_content.py)\nist es, einen Dateipfad von einem angegebenen Verzweigungsnamen\nherunterzuladen und dessen Inhalt in einer neuen Datei zu speichern.\n\n\n```python\n\n# Goal: Try to download README.md from\nhttps://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/README.md\n\nFILE_NAME = 'README.md'\n\nBRANCH_NAME = 'main'\n\n\n# Search the file in the repository tree and get the raw blob\n\nfor f in project.repository_tree():\n    print(\"File path '{name}' with id '{id}'\".format(name=f['name'], id=f['id']))\n\n    if f['name'] == FILE_NAME:\n        f_content = project.repository_raw_blob(f['id'])\n        print(f_content)\n\n# Alternative approach: Get the raw file from the main branch\n\nraw_content = project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME)\n\nprint(raw_content)\n\n\n# Store the file on disk\n\nwith open('raw_README.md', 'wb') as f:\n    project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME, streamed=True, action=f.write)\n```\n\n\n### Hilfe zur Migration: Auflistung aller zertifikatsbasierten\nKubernetes-Cluster\n\n\nDie zertifikatsbasierte Integration von Kubernetes-Clustern in GitLab wurde\n[abgeschafft](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes).\nUm Migrationspläne zu unterstützen, kann die Erfassung bestehender Gruppen\nund Projekte mithilfe der GitLab-API automatisiert werden.\n\n\n```python\n\ngroups = [ ]\n\n\n# get GROUP_ID group\n\ngroups.append(gl.groups.get(GROUP_ID))\n\n\nfor group in groups:\n    for sg in group.subgroups.list(include_subgroups=True, all=True):\n        real_group = gl.groups.get(sg.id)\n        groups.append(real_group)\n\ngroup_clusters = {}\n\nproject_clusters = {}\n\n\nfor group in groups:\n    #Collect group clusters\n    g_clusters = group.clusters.list()\n\n    if len(g_clusters) > 0:\n        group_clusters[group.id] = g_clusters\n\n    # Collect all projects in group and subgroups and their clusters\n    projects = group.projects.list(include_subgroups=True, all=True)\n\n    for project in projects:\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n\n        # skip archived projects\n        if project.archived:\n            continue\n\n        p_clusters = manageable_project.clusters.list()\n\n        if len(p_clusters) > 0:\n            project_clusters[project.id] = p_clusters\n\n# Print summary\n\nprint(\"## Group clusters\\n\\n\")\n\nfor g_id, g_clusters in group_clusters.items():\n    url = gl.groups.get(g_id).web_url\n    print(\"Group ID {g_id}: {u}\\n\\n\".format(g_id=g_id, u=url))\n    print_clusters(g_clusters)\n\nprint(\"## Project clusters\\n\\n\")\n\nfor p_id, p_clusters in project_clusters.items():\n    url = gl.projects.get(p_id).web_url\n    print(\"Project ID {p_id}: {u}\\n\\n\".format(p_id=p_id, u=url))\n    print_clusters(p_clusters)\n```\n\n\nHier findest du das vollständige\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/list_cert_based_kubernetes_clusters.py).\n\n\n### Team-Effizienz: Prüfe, ob bestehende Merge-Requests nach dem Mergen\neiner großen Refactoring-MR neu gebasht werden müssen\n\n\nDas [GitLab-Handbuch-Repository](https://handbook.gitlab.com/handbook/) ist ein großes Monorepo mit\nzahlreichen Merge-Requests, die erstellt, geprüft, genehmigt und\nzusammengeführt werden müssen. Einige Prüfungen dauern länger als andere,\ninsbesondere wenn Zusammenführungsanfragen mehrere Seiten betreffen,\nbeispielsweise wenn ein String umbenannt wird oder Änderungen auf\n[alle](/handbook/about/#count-handbook-pages) Handbuchseiten ausgedehnt\nwerden. Das Marketing-Handbuch wurde umstrukturiert, was zu vielen\nVerschiebungen oder Umbenennungen von Verzeichnissen und Pfaden führte.\n\n\nMit der Zeit nahmen die Issues zu, und es bestand die Sorge, dass andere\nMerge-Anfragen nach dem Zusammenführen der großen Änderungen auf Konflikte\nstoßen könnten. Es wurde festgestellt, dass Python-Gitlab in der Lage ist,\nalle Merge-Requests in einem bestimmten Projekt abzurufen, einschließlich\nDetails über den Git-Zweig, geänderte Quellpfade und vieles mehr.\n\n\nDas daraus resultierende Skript konfiguriert eine Liste von Quellpfaden, die\nvon allen pythongitlab-Merge-Requests berührt werden, und vergleicht die\nDiffs der Merge-Requests mit mr.diffs.list(), um festzustellen, ob ein\nMuster mit dem Wert in old_path. übereinstimmt. Bei einer Übereinstimmung\nprotokolliert das Skript diese und speichert die Zusammenführungsanforderung\nim seen_mr-Wörterbuch für die spätere Zusammenfassung. Zusätzlich werden\nAttribute gesammelt, um eine Markdown-Aufgabenliste mit URLs zum leichteren\nEinfügen in Issue-Beschreibungen zu erstellen.\n\n\n```python\n\nPATH_PATTERNS = [\n    'path/to/handbook/source/page.md',\n]\n\n\n# Only list opened MRs\n\n#\nhttps://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_requests.html#project-merge-requests\n\nmrs = project.mergerequests.list(state='opened', iterator=True)\n\n\nseen_mr = {}\n\n\nfor mr in mrs:\n    # https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs\n    real_mr = project.mergerequests.get(mr.get_id())\n    real_mr_id = real_mr.attributes['iid']\n    real_mr_url = real_mr.attributes['web_url']\n\n    for diff in real_mr.diffs.list(iterator=True):\n        real_diff = real_mr.diffs.get(diff.id)\n\n        for d in real_diff.attributes['diffs']:\n            for p in PATH_PATTERNS:\n                if p in d['old_path']:\n                    print(\"MATCH: {p} in MR {mr_id}, status '{s}', title '{t}' - URL: {mr_url}\".format(\n                        p=p,\n                        mr_id=real_mr_id,\n                        s=mr_status,\n                        t=real_mr.attributes['title'],\n                        mr_url=real_mr_url))\n\n                    if not real_mr_id in seen_mr:\n                        seen_mr[real_mr_id] = real_mr\n\nprint(\"\\n# MRs to update\\n\")\n\n\nfor id, real_mr in seen_mr.items():\n    print(\"- [ ] !{mr_id} - {mr_url}+ Status: {s}, Title: {t}\".format(\n        mr_id=id,\n        mr_url=real_mr.attributes['web_url'],\n        s=real_mr.attributes['detailed_merge_status'],\n        t=real_mr.attributes['title']))\n```\n\n\n## DevSecOps-Anwendungsfälle für API-Schreibaktionen\n\n\nDas authentifizierte Zugriffstoken benötigt den vollen Anwendungsbereich der\n[`api`](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-token-scopes).\n\n\nDie folgenden Anwendungsfälle werden diskutiert:\n\n\n- Verschieben von Epics zwischen Gruppen\n\n- Compliance: Sicherstellen, dass Projekteinstellungen nicht überschrieben\nwerden\n\n- Notizen machen, Fälligkeitsübersicht erstellen\n\n\n### Verschieben von Epics zwischen Gruppen\n\n\nManchmal ist es erforderlich, Epics, ähnlich wie Issues, in eine andere\nGruppe zu verschieben. Eine Frage im GitLab-Marketing-Slack-Kanal hat dazu\ngeführt, einen\n[Funktionsvorschlag](https://gitlab.com/gitlab-org/gitlab/-/issues/12689)\nfür die Benutzeroberfläche und die\n[Schnellaktionen](/blog/improve-your-gitlab-productivity-with-these-10-tips/)\nzu prüfen und später über das Schreiben eines API-Skripts nachzudenken, um\ndie Schritte zu automatisieren.\n\n\n### Automatisierung des Verschiebens von Epics\n\n\nDie Idee ist einfach: Ein Epic wird von einer Quellgruppe in eine Zielgruppe\nverschoben, wobei Titel, Beschreibung und Labels kopiert werden. Da Epics es\nerlauben, Themen zu gruppieren, müssen sie auch dem Ziel-Epic neu zugewiesen\nwerden. Parent-Child-Epic-Relationships müssen dabei berücksichtigt werden:\nAlle Child-Epics der Quell-Epics müssen dem Ziel-Epic neu zugewiesen werden.\n\n\nDas folgende Skript sucht zunächst alle\n[Attribute](https://python-gitlab.readthedocs.io/en/stable/gl_objects/epics.html)\ndes Quellepos und erstellt dann ein neues Zielepos mit den minimalen\nAttributen: Titel und Beschreibung. Die Liste der Bezeichnungen wird kopiert\nund die Änderungen werden mit dem save()-Aufruf beibehalten. Die Ausgaben,\ndie dem Epos zugeordnet sind, müssen im Zielepos neu erstellt werden.\n\n\nDer create()-Aufruf erzeugt das Beziehungselement und nicht ein neues\nIssue-Objekt selbst. Das Verschieben von Child-Epics erfordert einen anderen\nAnsatz, da die Beziehung umgekehrt ist: Die parent_id des Child-Epics muss\nmit der ID des Quell-Epics verglichen und bei Übereinstimmung auf die ID des\nZiel-Epics aktualisiert werden. Nachdem alles erfolgreich kopiert wurde,\nmuss das Quell-Epos in den closed-Zustand versetzt werden.\n\n\n```python\n\n#!/usr/bin/env python\n\n\n# Description: Show how epics can be moved between groups, including title,\ndescription, labels, child epics and issues.\n\n# Requirements: python-gitlab Python libraries. GitLab API write access, and\nmaintainer access to all configured groups/projects.\n\n# Author: Michael Friedrich \u003Cmfriedrich@gitlab.com>\n\n# License: MIT, (c) 2023-present GitLab B.V.\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-da/use-cases/gitlab-api\n\nSOURCE_GROUP_ID = os.environ.get('GL_SOURCE_GROUP_ID', 62378643)\n\n# https://gitlab.com/gitlab-da/use-cases/gitlab-api/epic-move-target\n\nTARGET_GROUP_ID = os.environ.get('GL_TARGET_GROUP_ID', 62742177)\n\n# https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1\n\nEPIC_ID = os.environ.get('GL_EPIC_ID', 1)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\n# Goal: Move epic to target group, including title, body, labels, and child\nepics and issues.\n\nsource_group = gl.groups.get(SOURCE_GROUP_ID)\n\ntarget_group = gl.groups.get(TARGET_GROUP_ID)\n\n\n# Create a new target epic and copy all its items, then close the source\nepic.\n\nsource_epic = source_group.epics.get(EPIC_ID)\n\n# print(source_epic) #debug\n\n\nepic_title = source_epic.title\n\nepic_description = source_epic.description\n\nepic_labels = source_epic.labels\n\nepic_issues = source_epic.issues.list()\n\n\n# Create the epic with minimal attributes\n\ntarget_epic = target_group.epics.create({\n    'title': epic_title,\n    'description': epic_description,\n})\n\n\n# Assign the list\n\ntarget_epic.labels = epic_labels\n\n\n# Persist the changes in the new epic\n\ntarget_epic.save()\n\n\n# Epic issues need to be re-assigned in a loop\n\nfor epic_issue in epic_issues:\n    ei = target_epic.issues.create({'issue_id': epic_issue.id})\n\n# Child epics need to update their parent_id to the new epic\n\n# Need to search in all epics, use lazy object loading\n\nfor sge in source_group.epics.list(lazy=True):\n    # this epic has the source epic as parent epic?\n    if sge.parent_id == source_epic.id:\n        # Update the parent id\n        sge.parent_id = target_epic.id\n        sge.save()\n\nprint(\"Copied source epic {source_id} ({source_url}) to target epic\n{target_id} ({target_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url,\n    target_id=target_epic.id, target_url=target_epic.web_url))\n\n# Close the old epic\n\nsource_epic.state_event = 'close'\n\nsource_epic.save()\n\nprint(\"Closed source epic {source_id} ({source_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url))\n\n```\n\n\n```shell\n\n$  python3 move_epic_between_groups.py\n\nCopied source epic 725341\n(https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1) to\ntarget epic 725358\n(https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/epic-move-target/-/epics/6)\n\nClosed source epic 725341\n(https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1)\n\n```\n\n\nDas\n[Ziel-Epic](https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/epic-move-target/-/epics/5)\nwurde erstellt und zeigt das erwartete Ergebnis: Derselbe Titel, dieselbe\nBeschreibung, dieselben Bezeichnungen, dasselbe untergeordnete Epic und\ndieselben Issues.\n\n\n![Target epic which has all attributes copied from the source epic: title,\ndescription, labels, child epics,\nissues](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_moved_epic_with_all_attributes.png){:\n.shadow}\n\n\n**Übung:** Das Skript kopiert noch keine\n[Kommentare](https://python-gitlab.readthedocs.io/en/stable/gl_objects/notes.html)\nund\n[Diskussionsstränge](https://python-gitlab.readthedocs.io/en/stable/gl_objects/discussions.html).\nRecherchiere und hilf mit, das Skript zu aktualisieren – Merge-Requests\nwillkommen!\n\n\n### Compliance: Sicherstellen, dass Projekteinstellungen nicht überschrieben\nwerden\n\n\nProjekt- und Gruppeneinstellungen können versehentlich von Teammitgliedern\nmit Administratorrechten geändert werden. Die Compliance-Anforderungen\nmüssen erfüllt werden. Ein weiterer Anwendungsfall ist die Verwaltung der\nKonfiguration mit Infrastructure-as-Code-Tools, um sicherzustellen, dass die\nKonfiguration von GitLab-Instanzen, -Gruppen, -Projekten usw. erhalten\nbleibt und immer dieselbe ist. Tools wie Ansible oder Terraform können ein\nAPI-Skript aufrufen oder die Python-GitLab-Bibliothek verwenden, um Aufgaben\nzur Verwaltung von Einstellungen auszuführen.\n\n\nIm folgenden Beispiel ist nur der main-Zweig geschützt.\n\n\n![GitLab project settings for repositories and protected branches, main\nbranch](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main.png){:\n.shadow}\n\n\nNehmen wir an, dass ein neuer production-Zweig hinzugefügt wurde und\nebenfalls geschützt werden soll. Das folgende\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/enforce_protected_branches.py)\ndefiniert das Wörterbuch der geschützten Zweige und ihre Zugriffsebenen für\nPush-/Merge-Berechtigungen auf Maintainer-Ebene und baut die Vergleichslogik\nauf der Grundlage der\n[python-gitlab-Dokumentation](https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html)\nzu geschützten Zweigen auf.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-da/use-cases/\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nPROTECTED_BRANCHES = {\n    'main': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n    'production': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n}\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\ngroup = gl.groups.get(GROUP_ID)\n\n\n# Collect all projects in group and subgroups\n\nprojects = group.projects.list(include_subgroups=True, all=True)\n\n\nfor project in projects:\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html\n    protected_branch_names = []\n\n    for pb in manageable_project.protectedbranches.list():\n        manageable_protected_branch = manageable_project.protectedbranches.get(pb.name)\n        print(\"Protected branch name: {n}, merge_access_level: {mal}, push_access_level: {pal}\".format(\n            n=manageable_protected_branch.name,\n            mal=manageable_protected_branch.merge_access_levels,\n            pal=manageable_protected_branch.push_access_levels\n        ))\n\n        protected_branch_names.append(manageable_protected_branch.name)\n\n    for branch_to_protect, levels in PROTECTED_BRANCHES.items():\n        # Fix missing protected branches\n        if branch_to_protect not in protected_branch_names:\n            print(\"Adding branch {n} to protected branches settings\".format(n=branch_to_protect))\n            p_branch = manageable_project.protectedbranches.create({\n                'name': branch_to_protect,\n                'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n                'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n            })\n```\n\n\nWenn das Skript ausgeführt wird, werden der bestehende main-Zweig und ein\nHinweis, dass die production aktualisiert wird, ausgegeben. Der Screenshot\naus den Repository-Einstellungen verdeutlicht diese Aktion.\n\n\n```\n\n$ python3\nenforce_protected_branches.py\n─╯\n\nProtected branch name: main, merge_access_level: [{'id': 67294702,\n'access_level': 40, 'access_level_description': 'Maintainers', 'user_id':\nNone, 'group_id': None}], push_access_level: [{'id': 68546039,\n'access_level': 40, 'access_level_description': 'Maintainers', 'user_id':\nNone, 'group_id': None}]\n\nAdding branch production to protected branches settings\n\n```\n\n\n![GitLab project settings for repositories and protected branches, main and\nproduction\nbranch](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main_production.png){:\n.shadow}\n\n\n### Notizen machen, Fälligkeitsübersicht erstellen\n\n\nEine Diskussion auf [Hacker\nNews](https://news.ycombinator.com/item?id=32155848) über Tools zum\nErstellen von Notizen hat mich dazu inspiriert, eine Übersicht in Form einer\nMarkdown-Tabelle zu erstellen, die aus Dateien, die Notizen aufnehmen,\ngeholt und nach dem geparsten Fälligkeitsdatum sortiert wird. Das\n[Skript](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/generate_snippets_index_by_due_date.py)\nist hier zu finden und etwas komplexer zu verstehen.\n\n\n\u003C!--\n\n# 2022-07-19 Notes\n\n\nHN topic about taking notes: https://news.ycombinator.com/item?id=32152935\n\n\n-->\n\n\n***Die englischsprachige\n[Originalversion](https://about.gitlab.com/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation/)\ndieses Artikels wurde bereits aktualisiert und erhält einige weitere Tipps,\nwelche wir der deutschen Version beizeiten hinzufügen werden.***\n",[235,680,924,834],"DevSecOps","2025-05-16",{"slug":927,"featured":6,"template":672},"efficient-devsecops-workflows-hands-on-python-gitlab-api-automation","content:de-de:blog:efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","Efficient Devsecops Workflows Hands On Python Gitlab Api Automation","de-de/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","de-de/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"_path":933,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":934,"content":940,"config":949,"_id":951,"_type":16,"title":952,"_source":17,"_file":953,"_stem":954,"_extension":20},"/de-de/blog/observability-vs-monitoring-in-devops",{"title":935,"description":936,"ogTitle":935,"ogDescription":936,"noIndex":6,"ogImage":937,"ogUrl":938,"ogSiteName":758,"ogType":784,"canonicalUrls":938,"schema":939},"Observability vs. Monitoring in DevOps","Observability sammelt Daten, um Prozesse zu optimieren und Probleme zu beheben. Wir zeigen dir, wie das geht - und warum es dem Monitoring überlegen ist.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665484/Blog/Hero%20Images/monitoring-update-feature-image.jpg","https://about.gitlab.com/blog/observability-vs-monitoring-in-devops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Observability vs. Monitoring in DevOps\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mike Vanbuskirk\"}],\n        \"datePublished\": \"2022-06-14\",\n      }",{"title":935,"description":936,"authors":941,"heroImage":937,"date":943,"body":944,"category":14,"tags":945,"updatedDate":948},[942],"Mike Vanbuskirk","2022-06-14","Logging und Monitoring sind feste Bestandteile moderner Software-Infrastrukturen. Die Einführung von syslog in den 1980ern markierte hierbei einen Wendepunkt. Ursprünglich für Unix-Systeme entwickelt, verdeutlichte syslog zwei zentrale Punkte: Wie wichtig es ist, sich einen Überblick darüber zu verschaffen, was genau in einem System geschieht – und dass es von Vorteil ist, diesen Kontrollmechanismus von der Grundfunktionalität des Systems zu trennen.\n\nDie Vorzüge dieser erhöhten Sichtbarkeit waren offensichtlich. Trotzdem wurden Monitoring und Logging lange eher stiefmütterlich behandelt. So kam es immer wieder vor, dass Systeme eine Vielzahl von Einträgen produzierten, ohne dass diese aber jemals sinnvoll zusammengefasst oder analysiert wurden. Oder es wurden in der Vergangenheit Monitoring-Infrastrukturen geschaffen, die dann aber über ein Jahrzehnt lang verkümmerten, bis sie nicht mehr dem aktuellen Stand entsprachen.\n\nSeitdem hat sich die operative Landschaft verändert. Observability ist das Stichwort der Stunde. Für die Einschätzung der Application-Performance bietet Observability gegenüber Monitoring den großen Vorzug, dass Entwickler(innen) nun nicht mehr auf ihre eigenen Interpretationen oder statische Messungen angewiesen sind. Stattdessen ermöglicht das Konzept der Observability es, sich ein ganzheitliches Bild darüber zu machen, wie sich die Applikation verhält und vor allem, wie sich ihre Leistung für Anwender(innen) darstellt.\n\n## Was ist Observability?\n\nUm die Bedeutung von Observability zu verstehen, hilft es, sich zunächst einen Überblick darüber zu verschaffen, was Monitoring ist, was es leisten kann und worin seine Beschränkungen liegen.\n\nAuf der grundlegendsten Ebene werden beim Monitoring verschiedene Werte und Outputs eines gegebenen Systems oder Software-Stacks gemessen. Dazu gehören beispielsweise die CPU-Auslastung, RAM-Nutzung sowie die Reaktionszeit (Latenz). In dieser Hinsicht ähnelt das Monitoring klassischen Logging-Systemen, die statische Informationen über Ereignisse aus dem aktiven Betrieb des Systems liefern.\n\nDie Messungen des Monitorings bieten in einem eingegrenzten Rahmen Hinweise auf systematische Probleme. Traditionelle DevOps-Monitoring-Tools erlauben es, die Daten zu aggregieren und miteinander zu korrelieren. Um aber holistische Aussagen treffen zu können, müssen diese Tools darüber hinaus üblicherweise noch manuell konfiguriert und angepasst werden. Statische Werte wie die CPU-Auslastung sind deswegen lediglich ein erster Schritt.\n\nIn seinem inzwischen berühmten SRE-Buch hat Google vier Kennzahlen - die sogenannten goldenen Signale - hervorgehoben, welche die Aussagekraft des Monitorings erhöhen sollen:\n\n- Latenz: Misst die Zeit, die benötigt wird, um eine Anfrage durchzuführen\n- Traffic: Misst die systemspezifische Nachfrage nach Leistungen auf höchster Ebene\n- Fehlerwahrscheinlichkeit: Misst die Rate, mit der Anfragen scheitern\n- Saturierung: Misst die Auslastung des Systems als das Verhältnis der Ressourcennutzung zu den verfügbaren Ressourcen insgesamt; üblicherweise liegt die Betonung hierbei auf knappen Ressourcen\n\nTatsächlich bieten diese goldenen Signale eine weitaus bessere Einschätzung der Systemleistung als die Kennziffern des konventionellen DevOps-Monitorings. Trotzdem muss um sie herum noch immer ein Monitoring-System entworfen, gebaut und in die bestehenden Abläufe integriert werden. Dies erfordert einen nicht zu unterschätzenden Aufwand. So müssen sämtliche potentiellen Fehler genau spezifiziert und händisch definiert und korrekt korreliert werden. Sogar in verhältnismäßig einfachen Fällen kann sich dies als sehr zeitintensiv erweisen.\n\n## Was also ist Observability?\n\nIm direkten Vergleich Observability vs. Monitoring ist Observability intuitiver und vollständiger. Das manuelle Harmonisieren unterschiedlicher DevOps-Monitoring-Tools entfällt. Während ein aggregiertes Monitoring-Dashboard nur so gut ist wie die letzten Entwickler(innen), die daran gearbeitet hat, passt sich eine Observability-Plattform eigenständig an. So liefert Observability automatisch kritische Informationen im passenden Kontext. Dies kann sogar auf den Software-Entwicklungszyklus ausgedehnt werden (Software Development Life Cycle, SDLC). Dabei liefern die Observability-Tools, im Gegensatz zum DevOps-Monitorings, während der CI/CD-Runs wichtige Informationen, die Entwickler(innen) operative Rückmeldungen zu ihrem Code bieten.\n\nLetzten Endes trägtObservability schlicht zu einer ganzheitlicheren Fehlerbeseitigung und einem holistischen Verständnis bei. Die Daten, die es produziert, lassen die „unbekannten Unbekannten” deutlicher hervortreten. So werden Produktionsprobleme erklärbarer. Im nächsten Abschnitt wollen wir verdeutlichen, warum genau dies so wertvoll ist. Anhand eines Beispiels werden wir dir zeigen, warum Monitoring alleine oftmals nicht ausreicht - und welche Lücken durch Observability geschlossen werden.\n\n## Warum sich Observability auszahlt\n\nEine Priorisierung von Observability kann dazu beitragen, die Zeit zu reduzieren, die zur Lösung eines Problems benötigt wird (mean time to resolution, MTTR). Dadurch können Ausfälle zeitlich eingeschränkt werden, die Application-Performance verbessert sich und das Kundenerlebnis fällt positiver aus. Man könnte meinen, Monitoring biete sehr ähnliche Vorzüge. Die folgende Anekdote soll veranschaulichen, dass dies jedoch nicht immer der Fall ist.\n\nDie Buchhaltung einer Engineering-Organisation gibt eine Warnung aus: Die Rechnungen für Cloud-Services steigen und sogar die Finanzleiterin hat ihre Sorge ausgedrückt. Entwickler(innen) haben bereits ebenso intensiv wie erfolglos das DevOps-Monitoring-System zu Rate gezogen: Alle Monitoring-Werte sind durchgehend im grünen Bereich, darunter der Speicher, die CPU-Auslastung sowie disk I/O. Wie sich herausstellt, lag die Ursache in einer anderen „unbekannten Unbekannten”: Eine erhöhte DNS-Latenz in den CI/CD-Pipelines führte zu einer erhöhten Ausfallrate in den Builds. Weil für jeden Build nun mehr Versuche benötigt wurden, kam es unweigerlich zu einer höheren Beanspruchung der Cloud-Ressourcen. Allerdings war jeder einzelne Versuch für sich verhältnismäßig kurz und fiel im Monitoring-System nicht auf. Durch die Einführung von DevOps-Observability-Tools konnte Ops eine weitaus breitere Palette an Ereignissen sammeln, das Problem damit einkreisen und es schließlich beheben. Dies wäre in einem traditionellen Monitoring-System nicht möglich gewesen. Hier hätte die Organisation selbst auf das DNS-Latenz-Problem schließen müssen.\n\nAuch für nichttechnische Stakeholder(innen) und Geschäftseinheiten erweist sich Observability als wichtig. Da Technologie zunehmend zu einem Profitfaktor wird, tragen die wirtschaftlichen Kennzahlen der Softwarestruktur unmittelbar zum gesamten Unternehmenserfolg bei. Observability bietet einen klaren Blick auf diese Kennzahlen und kann von verschiedenen Teams individuell genutzt werden.\n\nOhne eine positive Nutzererfahrung (User Experience, UX) sind moderne Software und Applikationen nicht möglich. Wie das Beispiel illustriert, reichen die statischen Kennziffern des Monitorings nicht aus. Unter einer scheinbar unauffälligen Oberfläche können sich schwerwiegende Probleme verbergen.\n\n## Zentrale Observability-Kennzahlen\n\nFür Organisationen, die sich dafür entschieden haben, DevOps-Observability-Tools zu verwenden, besteht der erste Schritt darin, die wichtigsten Ziele zu identifizieren und die besten Umsetzungsoptionen festzulegen.\n\nWir empfehlen, mit den drei grundlegenden Säulen der Observability anzufangen:\n\n- Logs: Informationen und Ereignisse\n- Kennziffern (metrics): Messungen spezifischer Kennziffern und Performance-Daten\n- Tracing: Die lückenlose Dokumentation einer Anfrage und ihrer Performance\n\nWer sein Observability-System auf diesen drei Säulen aufbaut, muss mit einem hohen Aufwand rechnen.  Projekte wie OpenTelemetry tragen aber erheblich zur Realisierbarkeit bei. Sie begünstigen die Akzeptanz industrieweiter Standards für Logging, Kennzahlen und Tracing und schaffen die Bedingungen für ein in sich stimmiges Ökosystem. Das verkürzt für alle Unternehmen, die DevOps-Observability-Tools umzusetzen gedenken, die auf OpenTelemetry-Standards basieren, die Zeit von der Einführung bis zur Profitabilität.\n\nAuch bei GitLab ist Observability ein zentraler Aspekt unseres Produkts, damit du Fehler und Engpässe so früh wie möglich erkennst und im laufenden Betrieb Anpassungen vornehmen kannst. Wenn du näher interessiert bist, besteht die Möglichkeit, die neue GitLab-Observability-Suite zu testen. Melde dich dazu als [Beta-Tester(in)](https://docs.gitlab.com/operations/observability/ \"GitLab Observability\") an.\n\nAls weitere Observability-Daten und -Säulen sind darüber hinaus zu nennen:\n\n- Das Tracking von Fehlern: Feinmaschigere (granulare) Logs mit Aggregation\n- Kontinuierliches Profiling: Auswertung der granularen Code-Performance\n- Real User Monitoring: Beurteilung der Application-Performance anhand echter Nutzer(innen)\n\nWenn wir uns diese Säulen ansehen, wird ein gemeinsames Prinzip erkennbar. Es reicht nicht mehr aus, sich bei der Analyse moderner, distribuierter Systeme auf einen sehr kurzen Zeitraum zu beschränken. Vielmehr ist eine holistische Betrachtung aus der Vogelperspektive erforderlich. Ein tiefes Verständnis der Application-Performance mittels Observability statt Monitoring beginnt damit, Ereignisse aus der erlebten Perspektive der Kundinnen und Kunden zu betrachten und anschließend die vollständige Performance und die Interaktion mit ihrer Software zu überwachen. Darin liegt der Hauptgrund, warum Observability im direkten Vergleich mit dem Monitoring die Oberhand behält.\n\nObservability erlaubt es einer Engineering-Organisation, über das konventionelle Monitoring hinaus die betriebliche Exzellenz zu verbessern. Letzten Endes ergeben sich die wertvollsten Warnsysteme und Problembehebungs-Programme aus schmerzhaft erlittenen Ausfällen. Hier bietet das sogenannte Chaos-Engineering eine Möglichkeit, Beobachtbarkeirs-Plattformen zu Testzwecken zu nutzen. Dabei werden die Konsequenzen echter Ausfälle in einer kontrollierten Umgebung und mit bekannten Ergebnissen geprüft. Wenn du vermutest, dass dein System „unbekannte Unbekannte” enthalten könnte, bietet Chaos-Engineering für deine [CI/CD-Pipelines](https://about.gitlab.com/de-de/topics/ci-cd/ \"CI/CD pipelines\"), Supply-Chain und DNS signifikante Zugewinne, was die operative Basis anbelangt.\n\n## Observability ist ein zentraler Teil von DevOps\n\nObservability ist nicht  nur für DevOps von zentraler Bedeutung, sondern für die gesamte Organisation. Indem du die statischen Daten überholter Monitoring-Lösungen ersetzt, erreichst du durch die Einführung von Observability einen 360-Grad-Blick auf deine Applikations-Infrastruktur.\n\nDevOps-Teams sollten eng mit Stakeholdern zusammenarbeiten, um ihre Observability-Kennziffern so miteinander zu teilen, dass sie der Organisation als Ganzes dienen und gemeinsam an ihrer Umsetzung arbeiten. Es kann für eine höhere Effektivität von Vorteil sein, sich die Vorteile der Apps-Instrumentierung zu verdeutlichen und diese Vorteile anschließend dem Entwicklungs-Team nahezulegen. DevOps-Teams können dazu beitragen, die Grundursachen von Produktionsproblemen schneller zu erkennen: gut eingesetzter Applikations-Code macht es zudem einfacher, diese von Ursachen zu unterscheiden, die auf der Infrastruktur beruhen. Je früher Observability in der CI/CD-Pipeline zur Anwendung kommt, umso größer ist die Wahrscheinlichkeit, dass SLO-Deltas erkannt werden, bevor das Produkt veröffentlicht wird.\n\nDevOps-Teams, die sowohl die Applikations-Performance als auch Geschäftswerte signifikant verbessern möchten, erhalten durch Observability die Möglichkeit, beide Aspekte gleichzeitig zu optimieren.\n",[946,947,682],"DevOps","security","2024-10-16",{"slug":950,"featured":6,"template":672},"observability-vs-monitoring-in-devops","content:de-de:blog:observability-vs-monitoring-in-devops.yml","Observability Vs Monitoring In Devops","de-de/blog/observability-vs-monitoring-in-devops.yml","de-de/blog/observability-vs-monitoring-in-devops",{"_path":956,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":957,"content":963,"config":973,"_id":975,"_type":16,"title":976,"_source":17,"_file":977,"_stem":978,"_extension":20},"/de-de/blog/demystifying-ci-cd-variables",{"ogTitle":958,"schema":959,"ogImage":960,"ogDescription":961,"ogSiteName":758,"noIndex":6,"ogType":784,"ogUrl":962,"title":958,"canonicalUrls":962,"description":961},"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":960,"body":964,"authors":965,"updatedDate":967,"date":968,"title":958,"tags":969,"description":972,"category":14},"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",[966],"Veethika Mishra","2025-01-28","2021-04-09",[881,970,971,880,110,680],"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":974,"featured":6,"template":672},"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":980,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":981,"content":987,"config":994,"_id":996,"_type":16,"title":997,"_source":17,"_file":998,"_stem":999,"_extension":20},"/de-de/blog/ci-deployment-and-environments",{"title":982,"description":983,"ogTitle":982,"ogDescription":983,"noIndex":6,"ogImage":984,"ogUrl":985,"ogSiteName":758,"ogType":784,"canonicalUrls":985,"schema":986},"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","\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":982,"description":983,"authors":988,"heroImage":984,"date":991,"body":992,"category":14,"tags":993,"updatedDate":925},[989,990],"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>",[880,881,680],{"slug":995,"featured":6,"template":672},"ci-deployment-and-environments","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":1001,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1002,"content":1008,"config":1017,"_id":1019,"_type":16,"title":1020,"_source":17,"_file":1021,"_stem":1022,"_extension":20},"/de-de/blog/we-need-to-talk-no-proxy",{"title":1003,"description":1004,"ogTitle":1003,"ogDescription":1004,"noIndex":6,"ogImage":1005,"ogUrl":1006,"ogSiteName":758,"ogType":784,"canonicalUrls":1006,"schema":1007},"Kann NO_PROXY standardisiert werden?","Erfahre, wie GitLab ein Problem gelöst hat, das durch die Unterschiede der\nVariablen, die nicht von allen Webclients unterstützt werden, entstanden\nist.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659507/Blog/Hero%20Images/AdobeStock_623844718.jpg","https://about.gitlab.com/blog/we-need-to-talk-no-proxy","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Kann NO_PROXY standardisiert werden?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Stan Hu\"}],\n        \"datePublished\": \"2021-01-27\",\n      }",{"title":1003,"description":1004,"authors":1009,"heroImage":1005,"date":1010,"body":1011,"category":14,"tags":1012,"updatedDate":1016},[738],"2021-01-27","Wenn du schon einmal einen Web-Proxyserver verwendet hast, bist du wahrscheinlich mit den Umgebungsvariablen `http_proxy` oder `HTTP_PROXY` vertraut. Weniger bekannt ist möglicherweise die Variable `no_proxy`, mit der du bestimmten Datenverkehr für bestimmte Hosts von der Verwendung des Proxys ausschließen kannst. Obwohl HTTP ein gut definierter Standard ist, existiert kein einheitlicher Standard dafür, wie Clients diese Variablen behandeln sollten. Dies führt dazu, dass Webclients diese Variablen auf sehr unterschiedliche Weise unterstützen. Bei einem GitLab-Kunden führten eben diese Unterschiede zu einer wochenlangen Fehlersuche, um herauszufinden, warum bestimmte Dienste nicht mehr kommunizierten.\n\nIn diesem Artikel erfährst du, wie wir die Probleme analysiert und gelöst haben.\n\n## Verwendung des Proxyservers: Konflikte und Ausnahmen\n\nDie meisten Webclients unterstützen heutzutage die Verbindung zu Proxy-Servern über Umgebungsvariablen (Environment variables):\n\n- `http_proxy / HTTP_PROXY`\n- `https_proxy / HTTPS_PROXY`\n- `no_proxy / NO_PROXY`\n\nDiese Variablen sagen dem Client, welche URL genutzt werden sollte, um Zugang zu Proxyservern zu erhalten und welche Ausnahmen gemacht werden sollten. Wenn du zum Beispiel einen Proxyserver hast, der auf `http://alice.example.com:8080` überwacht wird, könntest du ihn verwenden via:\n\n```sh\nexport http_proxy=http://alice.example.com:8080\n```\n\nWelcher Proxyserver wird verwendet, wenn Bob die Version in Großbuchstaben, `HTTP_PROXY`, ebenfalls definiert?\n\n```sh\nexport HTTP_PROXY=http://bob.example.com:8080\n```\n\nDie Antwort ist uneindeutig: Es hängt vom jeweiligen Kontext ab. In einigen Fällen gewinnt der Proxy von Alice, in anderen Fällen gewinnt Bob. \n\n### Ausnahmen definieren\n\nWas passiert, wenn du Ausnahmen machen willst? Nehmen wir etwa an, du willst einen Proxyserver für alles außer `internal.example.com` und `internal2.example.com` verwenden. In diesem Fall kommt die Variable `no_proxy` ins Spiel. Dann würdest du `no_proxy` wie folgt definieren:\n\n```sh\nexport no_proxy=internal.example.com,internal2.example.com\n```\n\nWas ist, wenn du IP-Adressen ausschließen willst? Kann man Sternchen oder eine `no_proxy`-Wildcard verwenden? Kann man CIDR-Blöcke verwenden (z. B. `192.168.1.1/32`)? Auch hier gilt wieder: Es kommt darauf an.\n\n## Geschichte der Webclients,wget no_proxy und cURLno_proxy\n\n1994 haben die meisten Webclients CERN's `libwww` genutzt, welche `http_proxy` und die `no_proxy` Umgebungsvariable unterstützt haben. `libwww` hat nur die kleingeschriebene Variante von `http_proxy` verwendet. Somit war die `no_proxy`-[Syntax](https://github.com/w3c/libwww/blob/8678b3dcb4191065ca39caea54bb1beba809a617/Library/src/HTAccess.c#L234-L239 \"Syntax\") sehr einfach:\n\n```\nno_proxy ist eine mithilfe von Kommas oder Leerzeichen  getrennte Liste von Rechner-\noder Domain-Namen mit optionalem :port part. Wenn kein :port\npart vorhanden ist, wird sie für alle Ports auf der Domain angewendet.\n\nBeispiel:\n\t\tno_proxy=\"cern.ch,some.domain:8001\"\n```\n\nEs entstanden neue Clients, die ihre eigenen HTTP-Implementierungen hinzufügten, ohne auf `libwww` zu verlinken. Im Januar 1996 veröffentlichte Hrvoje Niksic `geturl`, den Vorgänger des heutigen `wget`. Einen Monat später fügte `geturl` in v1.1 Unterstützung für `http_proxy` hinzu. Im Mai 1996 wurde mit `geturl` v1.3 die Unterstützung für `no_proxy` hinzugefügt. Genau wie `libwww` unterstützte `geturl` nur die Kleinbuchstabenform.\n\nIm Januar 1998 veröffentlichte Daniel Stenberg `curl` v5.1, das die Variablen `http_proxy` und `no_proxy` unterstützte. Darüber hinaus erlaubte `curl` die Großbuchstaben HTTP_PROXY und NO_PROXY. Eine plötzliche Wendung: Im März 2009 wurde mit `curl` v7.19.4 die Unterstützung für die Großbuchstabenvariante von HTTP_PROXY aufgrund von Sicherheitsbedenken eingestellt. Während curl HTTP_PROXY ignoriert, funktioniert HTTPS_PROXY jedoch auch heute noch.\n\nHeutzutage werden diese Proxyserver-Variablen je nach verwendeter Sprache oder Tool unterschiedlich gehandhabt.\n\n## http_proxy und https_proxy\n\nIn der folgenden Tabelle steht jede Zeile für ein unterstütztes Verfahren, während jede Spalte das Werkzeug (z.B. curl) oder die Sprache (z.B. Ruby) enthält, für die es gilt:\n\n|                 | curl      | wget           | Ruby          | Python    | Go        |\n|-----------------|-----------|----------------|---------------|-----------|-----------|\n| `http_proxy`    | Ja       | Ja            | Ja           | Ja       | Ja       |\n| `HTTP_PROXY`    | Nein       | Nein             |Ja ([warning](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1519)) | Ja (wenn `REQUEST_METHOD` nicht in env)       | Ja       |\n| `https_proxy`   | Ja       | Ja            | Ja           | Ja       | Ja       |\n| `HTTPS_PROXY`   | Ja       | Nein             | Ja           | Ja       | Ja       |\n| Präzedenzfall | Kleinschreibung | Kleinschreibung | Kleinschreibung     | Kleinschreibung | Großschreibung |\n| Referenz      | [Quelle](https://github.com/curl/curl/blob/30e7641d7d2eb46c0b67c0c495a0ea7e52333ee2/lib/url.c#L2250-L2266) | [Quelle](https://github.com/jay/wget/blob/099d8ee3da3a6eea5635581ae517035165f400a5/src/retr.c#L1222-L1239) | [Quelle](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1474-L1543) | [Quelle](https://github.com/python/cpython/blob/030a713183084594659aefd77b76fe30178e23c8/Lib/urllib/request.py#L2488-L2517) | [Quelle](https://github.com/golang/go/blob/682a1d2176b02337460aeede0ff9e49429525195/src/vendor/golang.org/x/net/http/httpproxy/proxy.go#L82-L97) |\n\n### Proxy-Variablen in Python und Go: Der Unterschied zwischen Groß- und Kleinschreibung\n\nBeachte, dass `http_proxy` und `https_proxy` immer durchgängig unterstützt werden, während `HTTP_PROXY` nicht immer unterstützt wird. Python (über urllib) verkompliziert das Bild noch mehr: `HTTP_PROXY` kann so lange verwendet werden, wie `REQUEST_METHOD` nicht in der Umgebung definiert ist.\n\nWährend man erwarten könnte, dass Umgebungsvariablen in Großbuchstaben geschrieben werden, war `http_proxy` zuerst da und ist damit also der De-facto-Standard. Im Zweifelsfall sollte man sich für die Kleinschreibung entscheiden, da diese universell unterstützt wird.\n\nIm Gegensatz zu den meisten Implementierungen versucht Go es mit Großbuchstaben, bevor es auf die Kleinschreibung zurückgreift. Wir werden später noch sehen, warum genau diese Vorgehensweise bei einem GitLab-Kunden zu Problemen führte.\n\n### no_proxy im gleichen Issue\n\nEinige Benutzer(innen) haben das Fehlen der `no_proxy`-Spezifikation in diesem Issue diskutiert. Da `no_proxy` eine Ausschlussliste spezifiziert, stellen sich viele Fragen zu ihrem Verhalten. Nehmen wir zum Beispiel an, deine `no_proxy`-Konfiguration ist definiert:\n\n```sh\nexport no_proxy=example.com\n```\n\nBedeutet dies, dass die Domain ein exaktes Match sein muss oder wird `subdomain.example.com` auch mit dieser Konfiguration übereinstimmen? Die folgende Tabelle zeigt den Status der verschiedenen Implementierungen. Es stellt sich heraus, dass alle Implementierungen Suffixe korrekt abgleichen, wie in der Zeile “Stimmt mit Suffixen überein” zu sehen ist:\n\n|                       | curl      | wget           | Ruby      | Python    | Go        |\n|-----------------------|-----------|----------------|-----------|-----------|-----------|\n| `no_proxy`            | Ja       | Ja             | Ja        | Ja        | Ja        |\n| `NO_PROXY`            | Ja        | Nein            | Ja        | Ja        | Ja        |\n| Präzedenzfall       | Kleinschreibung | Kleinschreibung | Kleinschreibung | Kleinschreibung | Großschreibung |\n| Stimmt mit Suffixen überein?     | Ja       | Ja            | Ja        | Ja        | Ja        |\n| Strips leading `.`?   | Ja       | Nein            | Ja       | Ja       | Nein        |\n| `*` Stimmt mit allen Hosts überein?| Ja       | Nein             | Nein        | Ja       | Ja       |\n| Unterstützt Regexe?     | Nein        | Nein             | Nein        | Nein        | Nein        |\n| Unterstützt CIDR-Blöcke? | Nein        | Nein            | Ja       | Nein        | Ja       |\n| Erkennt Loopback-IPs? | Nein        | Nein          | Nein       | Nein       | Ja       |\n| Referenz            | [Quelle](https://github.com/curl/curl/blob/30e7641d7d2eb46c0b67c0c495a0ea7e52333ee2/lib/url.c#L2152-L2206) | [Quelle](https://github.com/jay/wget/blob/099d8ee3da3a6eea5635581ae517035165f400a5/src/retr.c#L1266-L1274) | [Quelle](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1545-L1554) | [Quelle](https://github.com/python/cpython/blob/030a713183084594659aefd77b76fe30178e23c8/Lib/urllib/request.py#L2519-L2551)| [Quelle](https://github.com/golang/go/blob/682a1d2176b02337460aeede0ff9e49429525195/src/vendor/golang.org/x/net/http/httpproxy/proxy.go#L170-L206) |\n\nWenn jedoch ein vorangestellter. in der `no_proxy`-Einstellung vorhanden ist, variiert das Verhalten. Zum Beispiel verhalten sich `curl` und  `wget` unterschiedlich. `curl` entfernt immer den vorangestellten . und nimmt den Vergleich mit einem Domain-Suffix vor. Dieser Aufruf umgeht den Proxy:\n\n```sh\n$ env https_proxy=http://non.existent/ no_proxy=.gitlab.com curl https://gitlab.com\n\u003Chtml>\u003Cbody>You are being \u003Ca href=\"https://about.gitlab.com/\">redirected\u003C/a>.\u003C/body>\u003C/html>\n```\n\nAllerdings entfernt  `wget` den vorangestellten`.` nicht und führt eine exakte String-Übereinstimmung mit einem Hostnamen durch. Infolgedessen versucht  `wget`, einen Proxy zu verwenden, wenn eine Top-Level-Domain verwendet wird:\n\n```sh\n$ env https_proxy=http://non.existent/ no_proxy=.gitlab.com wget https://gitlab.com\nResolving non.existent (non.existent)... failed: Name or service not known.\nwget: unable to resolve host address 'non.existent'\n```\n\nIn keiner der Implementierungen werden reguläre Ausdrücke unterstützt. Die Verwendung von Regexes würde die Angelegenheit zusätzlich verkomplizieren, da es verschiedene Varianten gibt (z. B. PCRE, POSIX usw.). Darüber hinaus führen Regexes zu potenziellen Leistungs- und Sicherheitsproblemen.\n\nIn einigen Fällen können Proxys durch das Setzen der `no_proxy`-Variable auf * vollständig deaktiviert werden, aber dies ist keine allgemeingültige Regel. Keine Implementierung führt einen DNS-Lookup durch, um einen Hostnamen in eine IP-Adresse aufzulösen, wenn entschieden wird, ob ein Proxy verwendet werden soll. Daher sollten keine IP-Adressen in der `no_proxy`-Variable angegeben werden, es sei denn, es wird erwartet, dass die IPs explizit vom Client verwendet werden.\n\nDasselbe gilt für CIDR-Blöcke wie z. B. 18.240.0.1/24. CIDR-Blöcke funktionieren nur, wenn die Anfrage direkt an eine IP-Adresse gestellt wird. Nur Go und Ruby erlauben die Verwendung von CIDR-Blöcken. Im Gegensatz zu anderen Implementierungen deaktiviert Go sogar automatisch die Verwendung eines Proxys, wenn eine Loopback-IP-Adresse erkannt wird.\n\n## Fehlerbehebung bei Proxy-Konfigurationen: Wie unterschiedliche no_proxy-Einstellungen GitLab-Prozesse beeinträchtigen\n\nWenn die Anwendung in mehreren Sprachen geschrieben ist und hinter einer Unternehmensfirewall mit einem Proxyserver arbeiten muss, solltest du auf diese Unterschiede achten. GitLab besteht zum Beispiel aus einigen in Ruby und Go geschriebenen Diensten. Ein Kunde hat seine Proxy-Konfiguration in etwa wie folgt eingestellt:\n\n```yaml\nHTTP_PROXY: http://proxy.company.com\nHTTPS_PROXY: http://proxy.company.com\nNO_PROXY: .correct-company.com\n```\n\nDer Kunde meldete das folgende Problem mit GitLab:\n\n1. Ein `git push` über die Befehlszeile funktionierte\n2. Über die Web-UI vorgenommene Git-Änderungen schlugen fehl\n\nUnsere Support-Techniker stellten fest, dass aufgrund eines Konfigurationsproblems bei [Kubernetes](https://about.gitlab.com/de-de/solutions/kubernetes/ \"Kubernetes\") einige veraltete Werte zurückblieben. Der Pod hatte eine Umgebung, die in etwa so aussah:\n\n```yaml\nHTTP_PROXY: http://proxy.company.com\nHTTPS_PROXY: http://proxy.company.com\nNO_PROXY: .correct-company.com\nno_proxy: .wrong-company.com\n```\n\nDie inkonsistenten Definitionen in `no_proxy` und `NO_PROXY` waren ein Warnsignal, und wir hätten das Problem lösen können, indem wir sie konsistent gemacht oder den falschen Eintrag entfernt hätten. Aber sehen wir uns an, was passiert ist:\n\n1. Ruby versucht es zuerst mit der kleingeschriebenen Variante\n2. Go versucht es zuerst mit der Variante in Großbuchstaben\n\nInfolgedessen hatten in Go geschriebene Dienste wie GitLab Workhorse die richtige Proxy-Konfiguration. Ein `git push` von der Befehlszeile aus funktionierte problemlos, da die Go-Dienste diesen Vorgang primär abwickelten:\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant W as Workhorse\n    participant G as Gitaly\n    C->>W: git push\n    W->>G: gRPC: PostReceivePack\n    G->>W: OK\n    W->>C: OK\n```\n\nDer gRPC-Aufruf in Schritt 2 hat nie versucht, den Proxy zu verwenden, da `no_proxy` richtig konfiguriert wurde, um eine direkte Verbindung zu Gitaly herzustellen.\n\nWenn jedoch ein(e) Benutzer(in) eine Änderung in der Bedienoberfläche vornimmt, leitet Gitaly die Anfrage an einen `gitaly-ruby`-Service weiter, der in Ruby geschrieben ist.  `gitaly-ruby` nimmt Änderungen am Repository vor und meldet diese über einen gRPC-Aufruf an seinen übergeordneten Prozess zurück. Wie in Schritt 4 unten zu sehen ist, fand der Reporting-Schritt jedoch nicht statt:\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant R as Rails\n    participant G as Gitaly\n    participant GR as gitaly-ruby\n    participant P as Proxy\n    C->>R: Change file in UI\n    R->>G: gRPC: UserCommitFiles\n    G->>GR: gRPC: UserCommitFiles\n    GR->>P: CONNECT\n    P->>GR: FAIL\n```\n\nDa gRPC HTTP/2 als Transport verwendet, versuchte  `gitaly-ruby` einen CONNECT zum Proxy, da es mit der falschen `no_proxy`-Einstellung konfiguriert war. Der Proxy lehnte diese HTTP-Anfrage sofort ab, was den Fehler im Web-UI-Push-Case verursachte.\n\nNachdem wir den Kleinbuchstaben `no_proxy` aus der Umgebung entfernt hatten, funktionierte der Push von der Bedienoberfläche wie erwartet, und  `gitaly-ruby` verband sich direkt mit dem übergeordneten Gitaly-Prozess. Schritt 4 funktionierte, wie im folgenden Diagramm dargestellt:\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant R as Rails\n    participant G as Gitaly\n    participant GR as gitaly-ruby\n    participant P as Proxy\n    C->>R: Change file in UI\n    R->>G: gRPC: UserCommitFiles\n    G->>GR: gRPC: UserCommitFiles\n    GR->>G: OK\n    G->>R: OK\n    R->>C: OK\n```\n\n### Eine überraschende Entdeckung mit gRPC\n\nBeachte, dass der Kunde `HTTPS_PROXY` auf einen unverschlüsselten `HTTP_PROXY` gesetzt hat; beachte, dass `http://` anstelle von `https://` verwendet wird. Dies ist zwar vom Standpunkt der Sicherheit aus nicht ideal, aber es kann gemacht werden, um zu vermeiden, dass Clients aufgrund von Problemen bei der TLS-Zertifikatsüberprüfung scheitern.\n\nIronischerweise wäre dieses Problem nicht aufgetreten, wenn ein HTTPS-Proxy angegeben worden wäre. Wenn ein HTTPS-Proxy verwendet wird, ignoriert gRPC diese Einstellung, da HTTPS-Proxys nicht unterstützt werden.\n\n## Der kleinste gemeinsame Nenner\n\nMan sollte niemals inkonsistente Werte mit Proxy-Einstellungen in Klein- und Großbuchstaben definieren. Falls du allerdings jemals einen Stack verwalten musst, der in mehreren Sprachen geschrieben ist, solltest du in Erwägung ziehen, HTTP-Proxy-Konfigurationen auf den kleinsten gemeinsamen Nenner zu setzen:\n\n#### `http_proxy` und `https_proxy`\n\n* Verwende die Kleinschreibung. `HTTP_PROXY`  wird nicht immer unterstützt oder empfohlen.\n    * Wenn du unbedingt die Variante mit Großbuchstaben verwenden musst, achte darauf, dass sie denselben Wert hat.\n\n#### `no_proxy`\n\n1. Verwende die Kleinschreibung.\n2. Nutze durch Kommas getrennte `hostname:port` Werte.\n3. IP-Adressen sind okay, aber Hostnamen werden nie aufgelöst. \n4. Endungen werden immer zugeordnet (z.B. `example.com` wird `test.example.com` zugeordnet).\n5. Wenn Top-Level-Domains abgeglichen werden müssen, solltest du einen vorangestellten Punkt vermeiden (.).\n6. Vermeide die Verwendung von CIDR-Matching, da dies nur von Go und Ruby unterstützt wird.\n\n## Standardisierung von `no_proxy`\n\nDie Kenntnis des kleinsten gemeinsamen Nenners kann helfen, Probleme zu vermeiden, wenn diese Definitionen für verschiedene Webclients kopiert werden. Aber sollte es für `no_proxy` und die anderen Proxy-Einstellungen einen dokumentierten Standard geben und nicht nur eine Ad-hoc-Übereinstimmung? Die folgende Liste kann als Ausgangspunkt für einen Vorschlag dienen:\n\n1. Bevorzugung von Kleinbuchstaben gegenüber Großbuchstaben bei Variablen (z. B.  `http_proxy` sollte vor `HTTP_PROXY` gesucht werden).\n2. Verwende durch  Kommas getrennte Werte für `hostname:port`.\n    * Jeder Wert kann optionale Leerzeichen enthalten.\n3. Führe niemals DNS-Lookups durch und verwende keine regulären Formeln.\n4. Nutze `*` um alle Hosts zu verbinden.\n5. Führende Punkte (`.`) werden entfernt und mit Domain-Suffixen abgeglichen.\n6. Unterstützung des CIDR-Blockabgleichs.\n7. Stelle niemals Vermutungen über spezielle IP-Adressen an (z. B. Loopback-IP-Adressen in `no_proxy`).\n\n## Fazit \n\nSeit der Veröffentlichung des ersten Web-Proxys sind über 25 Jahre vergangen. Obwohl sich die grundlegenden Mechanismen zur Konfiguration eines Webclients über Umgebungsvariablen (wie z. B. environment no_proxy/env no_proxy) kaum verändert haben, haben sich bei den verschiedenen Implementierungen zahlreiche Feinheiten herausgebildet. Ein Beispiel aus der Praxis zeigt, dass die irrtümliche Definition widersprüchlicher `no_proxy`- und `NO_PROXY`-Variablen zu stundenlanger Fehlersuche führte, da Ruby und Go diese Einstellungen unterschiedlich auswerten. Das Hervorheben dieser Unterschiede kann helfen, zukünftige Probleme in deinem Produktions-Stack zu vermeiden. Es wäre wünschenswert, dass Webclient-Maintainer das Verhalten standardisieren, um solche Probleme von vornherein auszuschließen.",[271,1013,1014,1015],"careers","user stories","startups","2024-10-09",{"slug":1018,"featured":6,"template":672},"we-need-to-talk-no-proxy","content:de-de:blog:we-need-to-talk-no-proxy.yml","We Need To Talk No Proxy","de-de/blog/we-need-to-talk-no-proxy.yml","de-de/blog/we-need-to-talk-no-proxy",{"_path":1024,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1025,"content":1031,"config":1037,"_id":1039,"_type":16,"title":1040,"_source":17,"_file":1041,"_stem":1042,"_extension":20},"/de-de/blog/basics-of-gitlab-ci-updated",{"title":1026,"description":1027,"ogTitle":1026,"ogDescription":1027,"noIndex":6,"ogImage":1028,"ogUrl":1029,"ogSiteName":758,"ogType":784,"canonicalUrls":1029,"schema":1030},"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":1026,"description":1027,"authors":1032,"heroImage":1028,"date":1034,"body":1035,"category":14,"tags":1036,"updatedDate":925},[1033],"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",[880,680],{"slug":1038,"featured":6,"template":672},"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",{"_path":1044,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1045,"content":1051,"config":1058,"_id":1060,"_type":16,"title":1061,"_source":17,"_file":1062,"_stem":1063,"_extension":20},"/de-de/blog/keep-git-history-clean-with-interactive-rebase",{"title":1046,"description":1047,"ogTitle":1046,"ogDescription":1047,"noIndex":6,"ogImage":1048,"ogUrl":1049,"ogSiteName":758,"ogType":784,"canonicalUrls":1049,"schema":1050},"Git-Historie mit Interactive Rebase bereinigen","Erfahre, was Git Rebase ist und wie du damit in ein paar Schritten eine Git-Historie bereinigen kannst.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662593/Blog/Hero%20Images/title-image.png","https://about.gitlab.com/blog/keep-git-history-clean-with-interactive-rebase","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Git-Historie mit Interactive Rebase bereinigen\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tobias Günther\"}],\n        \"datePublished\": \"2020-11-23\",\n      }",{"title":1046,"description":1047,"authors":1052,"heroImage":1048,"date":1054,"body":1055,"category":14,"tags":1056,"updatedDate":1057},[1053],"Tobias Günther","2020-11-23","# Git-Historie mit dem Interactive Rebase bereinigen\n\n\nDas interaktive Rebase ist eines der vielseitigsten Tools von Git. Hier\nerfährst du, wie du damit Commit-Meldungen korrigierst, Fehler behebst und\ndeine Git-Historie ordentlich hältst. \n\n\n## Was ist das Interactive Rebase?\n\n\nDas Interactive [Rebase](/solutions/source-code-management/),\nauch bekannt als Git Interactive Rebase, wird oft als das „Schweizer\nTaschenmesser\" von Git bezeichnet, da es vielfältige Tools für\nunterschiedliche Einsatzmöglichkeiten bietet. Ein zentraler und wichtiger\nAnwendungsbereich ist das Bereinigen der eigenen lokalen Commit-Historie. \n\n\nBeachte hierbei das Wort „lokal”: Es sollte ausschließlich verwendet werden,\num die persönliche Commit-Historie aufzuräumen, z.B. wenn du einen\nFeature-Branch in einen Team-Branch integrierst. Es ist hingegen nicht\ngeeignet für Commits, die bereits an ein entferntes Repository gepusht und\nsomit geteilt wurden, da interaktives Rebase die Git-Historie „umschreibt”.\nIm Folgenden findest du einige Beispiel-Szenarien.\n\n\nAnmerkung: Zur besseren Visualisierung der Szenarios und Workflows in diesem\nBeitrag habe ich das [\"Tower\" Git Desktop\nGUI](https://www.git-tower.com/?utm_source=gitlab&utm_medium=guestpost&utm_campaign=interactive-rebase)\nin einigen der Screenshots verwendet.\n\n{: .note}\n\n\n## Korrektur einer alten Commit-Nachricht mit Git Rebase Interactive\n\n\nEs ist möglich, dass du nach getaner Arbeit einen Tippfehler in einer\n**älteren Commit-Nachricht** entdeckst oder merkst, dass eine wichtige\nInformation in der Beschreibung fehlt. Wäre es der allerletzte Commit,\nkönnte man einfach die Option '--amend' des 'git commit' Befehls nutzen, um\ndie Nachricht zu korrigieren. Bei älteren Commits jedoch ist ein\ninteraktives Rebase notwendig, um Änderungen vorzunehmen.\n\n\nHier ein Beispiel für eine fehlerhafte Commit-Nachricht, die du korrigieren\nmöchtest:\n\n\n![A bad commit message that needs\ncorrection](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/bad-commit-message@2x.png){:\n.shadow.medium.center}\n\nEine fehlerhafte Commit-Meldung, die korrigiert werden muss\n\n{: .note.text-center}\n\n\nBei jeder interaktiven Rebase-Sitzung mit Git musst du zunächst bestimmen,\n**welchen Teil der Commit-Historie du bearbeiten willst.** Um den\nfehlerhaften Commit aus dem vorherigen Beispiel zu ändern, sollte die\nSitzung beim übergeordneten Commit beginnen.\n\n\n![Starting our interactive rebase\nsession](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/start-at-parent-commit@2x.png){:\n.shadow.medium.center}\n\nStart der interaktiven Rebase-Sitzung\n\n{: .note.text-center}\n\n\nDu kannst nun den Hash dieses Start-Commits an den interaktiven Befehl Git\nRebase weitergeben:\n\n\n```\n\n$ git rebase -i 0023cddd\n\n```\n\n\nNun öffnet sich ein Editor-Fenster, in dem eine Liste der ausgewählten\nCommits zur Bearbeitung angezeigt wird. Dabei kann es überraschend sein,\ndass die Commits in *umgekehrter Reihenfolge* aufgelistet sind. Dies liegt\ndaran, dass Git in einer interaktiven Rebase-Sitzung die alten Commits\nschrittweise erneut anwendet. Aus der Perspektive von Git ist diese\numgekehrte Reihenfolge daher korrekt.\n\n\n![Editor window with the selected\ncommits](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/editor-window-start-ir@2x.png){:\n.shadow.medium.center}\n\nEditor-Fenster mit den ausgewählten Commits\n\n{: .note.text-center}\n\n\nEin wichtiger Hinweis zum Editor-Fenster: *Du kannst die Commit-Nachricht\nnicht direkt in diesem Fenster ändern!* Stattdessen verwendest du ein Action\nKeyword (Aktionsschlüsselwort), um den Commit auszuwählen, den du bearbeiten\nmöchtest. Möchtest du die Nachricht eines Commits ändern, markierst du die\nentsprechende Zeile mit „reword”. Nachdem du das Editor-Fenster gespeichert\nund geschlossen hast, öffnet sich ein neues Fenster, in dem die alte\nCommit-Nachricht angezeigt wird. Hier kannst du nun die gewünschten\nÄnderungen vornehmen.\n\n\n![Finally, we can make our\nchanges](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/correct-commit-message.gif){:\n.shadow.medium.center}\n\nDurchführung der Commit-Änderungen\n\n{: .note.text-center}\n\n\nNach erneutem Speichern und Schließen ist die interaktive Rebase-Sitzung\nabgeschlossen und die alte Commit-Nachricht wurde korrigiert!\n\n\n## Kombinieren mehrerer Commits mit interaktivem Rebase\n\nEin weiterer Anwendungsfall für das interaktive Rebase ist **das\nZusammenfassen mehrerer alter Commits zu einem einzigen** – mithilfe von Git\nRebase Interactive Merge Commits. Obwohl die goldene Regel der\nVersionskontrolle empfiehlt, eher mehrere kleinere Commits als wenige große\nzu erstellen, gibt es Situationen, in denen das Zusammenführen sinnvoll ist.\nBeispielsweise kann es vorkommen, dass du rückblickend feststellst, dass ein\nCommit effektiver ist als mehrere.\n\n\n![Let's combine multiple commits into\none](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-selected-commits@2x.png){:\n.shadow.medium.center}\n\nKombinieren von mehrerer Commits zu einem\n\n{: .note.text-center}\n\n\nWie im ersten Fall beginnt die interaktive Rebase-Sitzung spätestens beim\nübergeordneten Commit, das manipuliert werden soll.\n\n```\n\n$ git rebase -i 2b504bee\n\n```\n\n\nEs öffnet sich wieder ein Editor-Fenster, in dem der Teil der\nCommit-Historie aufgelistet ist, der bearbeitet werden soll:\n\n\n![Marking lines with\n\"squash\"](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-mark-commit@2x.png){:\n.shadow.medium.center}\n\nLinien in der Commit-Historie mit „Squash“ markieren\n\n{: .note.text-center}\n\n\nDas hier verwendete Action Keyword heißt „squash“. Um es zu verwenden, musst\ndu noch etwas über „squash“ wissen: *Die Zeile, die wir mit dem\nSchlüsselwort „squash“ markieren, wird mit der Zeile direkt darüber\nkombiniert.* Deshalb wurde, wie im Screenshot zu sehen, die Zeile Nr. 2 mit\n„squash“ markiert, um sie mit der Zeile Nr. 1 zu kombinieren.\n\n\nJetzt kannst du das Editor-Fenster speichern und schließen. Danach erscheint\nein neues Fenster, in dem du aufgefordert wirst, eine Commit-Nachricht für\nden neuen Commit einzugeben, der durch die Kombination der beiden alten\nCommits erzeugt wird. So entstehen neue Git Interactive Rebase Merge\nCommits.\n\n\n![Entering a new message for the new, squashed\ncommit](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-enter-new-message@2x.png){:\n.shadow.medium.center}\n\nEingabe einer neuen Nachricht für den „squash“-Commit\n\n{: .note.text-center}\n\n\nNach dem Speichern und Schließen dieses Editor-Fensters siehst du, dass ein\nneuer Commit erstellt wurde, der die Change-Sets (Änderungssätze) der beiden\nalten Commits enthält.\n\n\n## Behebung eines Fehlers mit Interactive Rebase\n\nEin weiteres Einsatzgebiet für das interaktive Rebase ist die Korrektur\neines Fehlers in einer früheren Übertragung. Es spielt keine Rolle, welche\nArt von Fehler gemacht wurde: Vielleicht wurde eine wichtige Änderung\nvergessen, eine Datei hätte gelöscht werden sollen oder es wurde einfach ein\nTippfehler gemacht.\n\n\nIn solchen Fällen könnte die erste Reaktion sein, einfach einen neuen Commit\nzu erstellen, der den Fehler behebt. Dies kann jedoch die Commit-Historie\nunübersichtlich machen. Ständig einen ursprünglichen Commit zu erstellen und\ndann einen weiteren, nur um kleine Fehler zu korrigieren, kann zu einer\nchaotischen und schwer nachvollziehbaren Commit-Historie führen.\n\n\nAn dieser Stelle kommt „fixup\", eines der Tools, die mit interaktivem Rebase\ngeliefert werden, zum Einsatz. Git Rebase Interactive Fixup nimmt diesen\n„Quick-Fix\"-Commit, wendet seine Änderungen auf den ursprünglichen Commit\nan, korrigiert ihn und entfernt dann den korrigierenden Commit\n(Band-Aid-Commit):\n\n\n![How \"fixup\"\nworks](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/diagram-fixup.png){:\n.medium.center}\n\nSo funktioniert \"fixup\"\n\n{: .note.text-center}\n\n\nNach der Korrektur scheint es, als ob es nie ein Problem mit dem\nursprünglichen Commit gegeben hätte. Hier ist ein weiteres praktisches\nBeispiel für diesen Prozess.\n\n\nZunächst solltest du alles tun, was nötig ist, um das Problem zu beheben:\nDas kann das Hinzufügen einer neuen Datei, das Ändern bestehender Dateien\noder das Löschen veralteter Dateien sein. Der nächste Schritt ist, diese\nÄnderungen an das Repository zu senden.\n\n\nHierbei nutzt du beim Commit die Option '--fixup' und gibst den Commit-Hash\ndes fehlerhaften Commits an, um Git deutlich zu machen, welcher\nursprüngliche Commit korrigiert werden soll.\n\n\n```\n\n$ git add corrections.txt\n\n$ git commit --fixup 2b504bee\n\n```\n\n\nWenn du dir nun die Commit-Historie anschaust, wirst du feststellen, dass\nein recht gewöhnlich aussehender Commit erstellt wurde, der zunächst einmal\nwenig spektakulär scheint. Bei genauerer Betrachtung aber wirst du bemerken,\ndass doch etwas Unerwartetes passiert ist: Dem neuen Commit wurde\nautomatisch „fixup!“ gefolgt vom Betreff des fehlerhaften Commits\nvorangestellt – pure Magie!\n\n\n![The original commit and the fix\ncommit](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_create-fix-commit@2x.png){:\n.shadow.medium.center}\n\nDie ursprüngliche Übertragung und die Korrekturübertragung\n\n{: .note.text-center}\n\n\nDer dritte – wieder etwas gewöhnlichere – Schritt besteht nun darin, die\ninteraktive Rebase-Sitzung zu starten. Auch hier wählst du den Parent der\nfehlerhaften Übertragung als Startpunkt:\n\n```\n\n$ git rebase -i 0023cddd --autosquash\n\n```\n\n\nAls Nächstes verwendest du die Option '--autosquash'. Diese Option sorgt\ndafür, dass du in dem nun geöffneten Editor-Fenster selbst nichts ausführen\nmusst.Wir schauen uns das mal genau an:\n\n\n![Our fix commit is marked \"fixup\" and sorted to the right\nposition](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_editor@2x.png){:\n.shadow.medium.center}\n\nDer Fix-Commit wird als „fixup\" markiert und an die richtige Position\nsortiert\n\n{: .note.text-center}\n\n\nGit hat automatisch zwei Dinge gemacht:\n\n\n1. Es hat den zu korrigierenden Commit als „fixup\" markiert.\n\n2. Es hat die Zeilen neu sortiert, sodass der zu korrigierende Commit direkt\nunter dem fehlerhaften Commit erscheint. Das liegt daran, dass „fixup“ genau\nwie „squash“ funktioniert, indem es mit der darüber liegenden Zeile\nkombiniert wird.\n\n\nNun speicherst du das Editor-Fenster und schließt es dann.\n\n\nDer Commit-Verlauf sieht nun so aus:\n\n\n![A happy\nending!](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_final-corrected@2x.png){:\n.shadow.medium.center}\n\nEin Happy End!\n\n{: .note.text-center}\n\n\nNun sind nicht nur die Korrekturen aus dem „Band-Aid-Commit“ in den\nursprünglich fehlerhaften Commit integriert worden, sondern der fehlerhafte\nCommit ist auch aus der Commit-Historie verschwunden. Alles ist nun so\nbereinigt, dass es scheint, als hätte es nie ein Problem gegeben.\n\n\n## Entdecke die Leistungsfähigkeit von Git Rebase Interactive\n\n\nWie du gesehen hast, gibt es für interaktives Rebase viele\nEinsatzmöglichkeiten, vor allem im Bereich der Fehlerbehebung. Für einen\nÜberblick über weitere nützliche Anwendungen ist das **kostenlose** [\"First\nAid Kit for\nGit\"](https://www.git-tower.com/learn/git/first-aid-kit?utm_source=gitlab&utm_medium=guestpost&utm_campaign=interactive-rebase)\nempfehlenswert. Diese Sammlung besteht aus kurzen Videos (2-3 Minuten pro\nEpisode), die dir zeigen, wie du Fehler mit interaktivem Rebase und anderen\nGit-Tools rückgängig machen kannst.\n\n\n## Weitere Git-Tipps und -Tricks\n\n\n- [15 Git tips to improve your\nworkflow](/blog/15-git-tips-improve-workflow/)\n(englischsprachiger Artikel)\n\n- [How Git Partial Clone lets you fetch only the large file you\nneed](/blog/partial-clone-for-massive-repositories/)\n(englischsprachiger Artikel)\n\n- [Git happens! 6 Common Git mistakes and how to fix\nthem](/blog/git-happens/) (englischsprachiger Artikel)\n\n\n### Über den Gastautor\n\n\n_[Tobias Günther](https://twitter.com/gntr) ist der CEO von\n[Tower](https://www.git-tower.com/?utm_source=gitlab&utm_medium=guestpost&utm_campaign=interactive-rebase),\nder beliebten Git-Desktopanwendung, welche bereits über 100.000\nEntwicklerinnen und Entwickler dabei geholfen hat, noch produktiver zu\nwerden._\n\n\nCoverbild von [David Taljat](https://www.pexels.com/@david-taljat-3748658)\nbei\n[Pexels](https://www.pexels.com/photo/yellow-and-blue-line-on-gray-asphalt-road-5690623/)\n\n{: .note}\n",[681,680],"2024-12-18",{"slug":1059,"featured":6,"template":672},"keep-git-history-clean-with-interactive-rebase","content:de-de:blog:keep-git-history-clean-with-interactive-rebase.yml","Keep Git History Clean With Interactive Rebase","de-de/blog/keep-git-history-clean-with-interactive-rebase.yml","de-de/blog/keep-git-history-clean-with-interactive-rebase",{"_path":1065,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1066,"content":1072,"config":1082,"_id":1084,"_type":16,"title":1085,"_source":17,"_file":1086,"_stem":1087,"_extension":20},"/de-de/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"ogTitle":1067,"schema":1068,"ogImage":1069,"ogDescription":1070,"ogSiteName":758,"noIndex":6,"ogType":784,"ogUrl":1071,"title":1067,"canonicalUrls":1071,"description":1070},"Konfigurationsmanagement mit GitLab und Ansible | Ein Leitfaden","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Konfigurationsmanagement mit GitLab und Ansible\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brad Downey\"},{\"@type\":\"Person\",\"name\":\"Sara Kassabian\"}],\n        \"datePublished\": \"2019-07-01\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665322/Blog/Hero%20Images/gitlab-ansible-cover.png","Wir zeigen dir, wie das Konfigurationsmanagement mit GitLab und Ansible funktioniert! ✓ Definition ✓ Einstellungen ✓ Anleitung ✓ Demo ➤Jetzt Tutorial lesen!","https://about.gitlab.com/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"title":1073,"description":1074,"authors":1075,"heroImage":1069,"date":1078,"body":1079,"category":14,"tags":1080},"Konfigurationsmanagement mit GitLab und Ansible","Entdecke die beeindruckende Leistungsfähigkeit von GitLab CI, wenn es darum geht, Ansible-Playbooks im Rahmen von Infrastructure as Code umzusetzen.",[1076,1077],"Brad Downey","Sara Kassabian","2019-07-01","[GitLab CI](https://about.gitlab.com/de-de/solutions/continuous-integration/\n\"GitLab CI\") ist ein vielseitiges Tool, das für eine Vielzahl von\nAufgabenbereichen wie [Infrastructure as\nCode](https://about.gitlab.com/topics/gitops/infrastructure-as-code/\n\"Infrastructure as Code\") und\n[GitOps](https://about.gitlab.com/de-de/topics/gitops/ \"GitOps\") eingesetzt\nwerden kann. Eine der Eigenschaften von GitLab ist seine Unabhängigkeit von\nspezifischen Tools. In dieser Demonstration liegt der Fokus auf Ansible, da\nviele Entwickler(innen) dieses Tool für Konfigurationsmanagement bevorzugen.\n\n\n## Was ist Ansible?\n\n\nAnsible ist ein Open-Source-Automatisierungstool, das für die Bereitstellung, Konfiguration und Verwaltung von Computersystemen genutzt wird. Es gehört zur Kategorie der Konfigurationsmanagement-Tools. Entwickler(innen) und Systemadministrator(inn)en können damit komplexe, wiederholbare Prozesse wie Serverkonfiguration, Anwendungsbereitstellung und Netzwerkgerätemanagement automatisieren. Ansible verwendet YAML, um deklarative Aufgabenbeschreibungen zu erstellen, bekannt als Playbooks. Diese beschreiben den gewünschten Systemzustand, den Ansible durch SSH-Verbindungen zu den Zielhosts erreicht, um Befehle auszuführen.\n\n\n## Demo: GitLab CI und Ansible\n\n\nEine Funktion von GitLab CI ist die Möglichkeit, den Code aus dem Ansible-Playbook zu bearbeiten und bereitzustellen, ohne lokale Abhängigkeiten zu installieren. So kann das Demo-Projekt, das eine monatliche Aktualisierung der SNMP-Strings auf allen Geräten gemäß unseren Sicherheitsrichtlinien erfordert, problemlos auf [GitLab.com](https://about.gitlab.com/de-de/pricing/ \"GitLab Pricing\") durchgeführt werden.\n\n\nBeginnen Sie, indem Sie das Ansible-Playbook öffnen, das vier Aufgaben beinhaltet:\n\n\n- Erfassen der Router-Fakten\n\n- Anzeigen der Version\n\n- Anzeigen der Seriennummer\n\n- Konfigurieren von SNMP\n\n\nDer Schwerpunkt dieser Demo liegt auf der Konfiguration der SNMP-Strings, die in einer einfachen Reihe von Schritten durchgeführt werden kann.\n\n\n## Zu Beginn: das Issue Board\n\n\nJeder Plan bei GitLab beginnt an derselben Stelle: mit einem Problem. Der erste Schritt im GitLab-Workflows besteht darin, das Issue Board des [„ansible-demo“-Projekts (auf Englisch)](https://gitlab.com/bdowney/ansible-demo/-/boards \"ansible-demo\") zu überprüfen. Dort sehen wir bereits ein Issue zur Änderung der SNMP-Strings auf allen Routern. Das Issue verweist auf das GitLab-Sicherheitsrichtlinien-Wiki, das besagt, dass SNMP-Strings monatlich geändert werden müssen und unterschiedliche Strings für „read-only“ und „read-write“ erforderlich sind.\n\n\n![Security policies](https://about.gitlab.com/images/blogimages/ansible_screenshots/security_policies_1A.png){: .shadow.medium.center}\n\n\nGemäß unserer GitLab-Sicherheitsrichtlinien müssen die SNMP-Strings monatlich aktualisiert werden. Als Nächstes prüfst du, ob die Befehle zur Konfiguration der SNMP-Strings in der [Zwei-Router-Demo (auf Englisch)](https://gitlab.com/bdowney/ansible-demo/blob/master/ci-cd-demo/ci.yml \"Zwei-Router-Demo\") den in diesem Issue beschriebenen GitLab-Sicherheitsrichtlinien entsprechen.\n\n\n![Ansible SNMP change](https://about.gitlab.com/images/blogimages/ansible_screenshots/ansible_snmp_change_2.png){: .shadow.medium.center}\n\n\nDie Befehle zur Konfiguration der SNMP-Strings findest du im Ansible-Playbook.\n\n\nGeh danach zurück zum Issue und weise es dir selbst zu. Ändere in der rechten Seitenleiste des Issues oder indem du es zwischen den Spalten des Issue Boards von „to-do“ auf „doing“ ziehst.\n\n\n## Merge Request erstellen\n\n\nAls Nächstes erstellst du einen Merge Request (MR) für das Issue. Stelle sicher, dass du das Kennzeichen „Draft“ deinem MR hinzufügst, damit er nicht vorzeitig mit dem Master zusammengeführt wird. Statt eine lokale Verbindung herzustellen, nutze die Web IDE von GitLab, da die Änderungen an den SNMP-Strings minimal sind. \n\n\n- Öffne den CI/CD-Demo-Bereich\n\n- Rufe das Ansible-Playbook auf\n\n- Bearbeite den SNMP-Abschnitt wie folgt:\n\n```\n\n-snmp-server community New-SNMP-DEMO1 RO\n\n\n-snmp-server community Fun-SNMP-RW-STR RW\n\n```\n\n- Achte darauf, dass read-only (RO) und read-write (RW) auf unterschiedliche Strings gemäß den GitLab-Sicherheitsrichtlinien gesetzt sind, wie sie im Issue beschrieben werden.\n\n\n## Änderungen übertragen\n\n\nNachdem du den SNMP-String gemäß den Richtlinien aktualisiert hast, committe die Änderungen. Öffne den Seite-an-Seite-Vergleich der Änderungen, um zu sehen, dass der MR mit deinem letzten Commit aktualisiert wurde.\n\n\n![Commit changes](https://about.gitlab.com/images/blogimages/ansible_screenshots/side-by-side_3.png){: .shadow.medium.center}\n\n\nDer Seite-an-Seite-Vergleich ist eine einfache Möglichkeit, deine Änderungen zu visualisieren.\n\n\n## Ausgabe des Merge-Request\n\n\nDurch den Commit der Änderungen wird automatisch eine GitLab CI-Pipeline gestartet. Diese führt beispielsweise folgende Aufgaben durch:\n\n\n- Syntaxprüfung\n\n- Dry Run\n\n- Testen der Änderungen in einer Labor-/Simulationsumgebung\n\n\nDu kannst den Fortschritt und die Ausgabe jedes Auftrags in der GitLab-CI-Pipeline anzeigen, um die SNMP-Aktualisierungen durchzuführen.\n\n\n![Job running](https://about.gitlab.com/images/blogimages/ansible_screenshots/job_running_4.png){: .shadow.medium.center}\n\n\nSchau dir die Ergebnisse deines Auftrags an, die zeigen, dass die SNMP-Aktualisierungen in der simulierten Umgebung erfolgreich waren. Alle diese Aufgaben werden im Merge Request durchgeführt und dokumentiert.\n\n\n![Pipeline](https://about.gitlab.com/images/blogimages/ansible_screenshots/pipeline_5A.png){: .shadow.medium.center}\n\n\nDie grünen Häkchen zeigen an, dass jeder Job in der GitLab CI-Pipeline erfolgreich abgeschlossen wurde. Anschließend kannst du dich auf den Lab-Routern einloggen und die durchgeführten Änderungen sehen.\n\n\n![routers snmp](https://about.gitlab.com/images/blogimages/ansible_screenshots/routersnmp_6.png){: .shadow.medium.center}\n\n\nDie Änderungen an den RO- und RW-SNMP-Strings werden in den Routern berücksichtigt.\n\n\n## MR-Review\n\n\nEine weitere Möglichkeit besteht darin, MR-Approvals zu aktivieren. Dadurch haben mehr Benutzer(innen) die Chance, Änderungen zu überprüfen, bevor sie in die Produktionsumgebung übernommen werden.\n\n\n![approvers](https://about.gitlab.com/images/blogimages/ansible_screenshots/approvers_7.png){: .shadow.medium.center}\n\n\nDu kannst den MR so einstellen, dass eine andere Person deine Arbeit überprüfen muss, bevor sie in den Master-Branch übernommen wird.\n\n\n## Merge in den Master-Branch\n\n\nSobald die Tests abgeschlossen sind, können die Änderungen in den Master-Branch übernommen werden, welcher den Code der Produktionsumgebung enthält.\n\nWenn du bereit bist, klickst du auf die Schaltfläche Mark as ready (Als bereit markieren). Anschließend klickst du auf `Merge`.\n\n\nDurch das Auflösen des WIP-Status kann der MR zusammengeführt und das Issue abgeschlossen werden.\n\n\nNun startet eine neue Pipeline, die alle durchgeführten Tests erneut ausführt, mit dem zusätzlichen Schritt, das Playbook in der Produktionsumgebung auszuführen.\n\n\nDu kannst den Fortschritt und die Protokolle auf dem „Pipelines“-Seite anzeigen. Sobald dieser Prozess abgeschlossen ist, kannst du dich bei deinen Produktionsroutern anmelden und sehen, dass die SNMP-Sicherheitsstrings aktualisiert wurden.\n\n\n## Die Magie von GitLab CI\n\n\nDie Magie, die all dies möglich gemacht hat, ist GitLab CI. GitLab CI-Pipelines sind eine Reihe von aufeinanderfolgenden Aufgaben, die alles ausführen, was du zum Testen und Implementieren deines Ansible-Codes benötigst.\n\n\nGitLab CI wird mit einer einzigen einfachen YAML-Datei konfiguriert, die im Repository unter dem Namen `.gitlab-ci.yml` zu finden ist.\n\nIn dieser Demo siehst du, dass die `.gitlab-ci.yml` Datei drei Schritte beinhaltet:\n\n\n1. Deploy: Damit wird das Zwei-Router-Simulationsnetzwerk in AWS mithilfe von Ansible erstellt.\n\n2. Demo: Damit wird das Playbook ausgeführt, das die SNMP-Strings ändert.\n\n3. Destroy: Hiermit wird das Zwei-Router-Simulationsnetzwerk zerstört.\n\n\nGitLab CI startet mit einem Basis-Image. In diesem Fall verwenden wir ein Docker-Image, das alle erforderlichen Ansible-Binärdateien und Abhängigkeiten enthält. Wir geben die Befehle an, die in jeder Phase ausgeführt werden sollen, und die Abhängigkeiten, soweit erforderlich.\n\n\n![More code](https://about.gitlab.com/images/blogimages/ansible_screenshots/more_code_9A.png){: .shadow.medium.center}\n\n\nEine einfache YAML-Datei enthält die drei Phasen des GitLab-CI.\n\n\n![More Code](https://about.gitlab.com/images/blogimages/ansible_screenshots/more_code_10A.png){: .shadow.medium.center}\n\n\nEin Blick in die Demostufe von GitLab CI, die das Ansible-Playbook ausführt.\n\n\nWenn du dir die Pipelines ansiehst, kannst du sehen, wie GitLab CI verwendet wird, um Konfigurationsmanagement umzusetzen, ohne Ansible auf deinem Computer installieren zu müssen. Dies ist nur ein Beispiel dafür, wie GitLab CI genutzt werden kann, um Infrastruktur als Code auszuführen. Schau dir das Video unten an, um das vollständige Tutorial zu sehen:\n\n\n\u003C!-- blank line -->\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/M-SgRTKSeOg\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n\u003C!-- blank line -->\n\n\n## FAQ – Häufig gestellte Fragen\n\n\n### Wie nutze ich den Ansible Tower?\n\n\nAnsible Tower ist eine webbasierte Benutzeroberfläche und eine Enterprise-Ergänzung zu Ansible, die zusätzliche Funktionen zur Automatisierung, Verwaltung und Überwachung von Ansible-Umgebungen bietet. Teams können mit Ansible Tower ihre Automatisierungsprozesse zentralisieren, Zugriffskontrollen verwalten, Zeitpläne für Aufgaben erstellen, Berichte generieren und mehr. Es erleichtert die Skalierung und den Einsatz von Ansible in großen Umgebungen und bietet eine benutzerfreundliche Oberfläche für die Automatisierung von IT-Abläufen.\n\n\n### Was ist der Ansible GitLab Runner?\n\n\nEin Ansible GitLab Runner ist ein integraler Bestandteil des GitLab CI/CD-Ökosystems, der speziell für die Ausführung von Ansible-Playbooks entwickelt wurde. Er ist ein Prozess, der von GitLab genutzt wird, um Jobs in CI/CD-Pipelines auszuführen. Entwickler(innen) können einen GitLab Runner so konfigurieren, dass er Ansible-Playbooks auf den Zielhosts ausführt, was es ermöglicht, die Infrastruktur automatisiert und ohne zusätzliche Ressourcen zu verwalten.\n",[1081,110],"demo",{"slug":1083,"featured":6,"template":672},"using-ansible-and-gitlab-as-infrastructure-for-code","content:de-de:blog:using-ansible-and-gitlab-as-infrastructure-for-code.yml","Using Ansible And Gitlab As Infrastructure For Code","de-de/blog/using-ansible-and-gitlab-as-infrastructure-for-code.yml","de-de/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"_path":1089,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1090,"content":1096,"config":1104,"_id":1106,"_type":16,"title":1107,"_source":17,"_file":1108,"_stem":1109,"_extension":20},"/de-de/blog/keeping-git-commit-history-clean",{"title":1091,"description":1092,"ogTitle":1091,"ogDescription":1092,"noIndex":6,"ogImage":1093,"ogUrl":1094,"ogSiteName":758,"ogType":784,"canonicalUrls":1094,"schema":1095},"4 Situationen, in denen sich eine aufgeräumte Git-Commit-Historie lohnt ","Erfahre, warum eine saubere Git-Commit-Historie die Nachvollziehbarkeit verbessert, Fehler behebt und die Codequalität steigert.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659457/Blog/Hero%20Images/keep-git-commit-history-clean.jpg","https://about.gitlab.com/blog/keeping-git-commit-history-clean","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"4 Situationen, in denen sich eine aufgeräumte Git-Commit-Historie lohnt \",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kushal Pandya\"}],\n        \"datePublished\": \"2018-06-07\",\n      }",{"title":1091,"description":1092,"authors":1097,"heroImage":1093,"date":1099,"body":1100,"category":14,"tags":1101,"updatedDate":1103},[1098],"Kushal Pandya","2018-06-07","Git-Commits sind einer der Eckpfeiler eines Git-Repositorys. Die\nCommit-Nachrichten sind wie ein Lebensprotokoll für das Repository. Während\nsich das Projekt/Repository im Laufe der Zeit entwickelt – sei es durch das\nHinzufügen neuer Funktionen, das Beheben von Fehlern oder die Überarbeitung\nder Architektur – geben die Commit-Nachrichten Aufschluss darüber, was genau\ngeändert wurde. Daher ist es entscheidend, dass diese Nachrichten die\nzugrunde liegende Änderung präzise und kurz wiedergeben. Die Commit-Historie\nkann leicht verfälscht werden. In diesem Artikel erfährst du, wie du sie\nkorrigieren kannst!\n\n\n## Warum eine aussagekräftige Git-Commit-Historie wichtig ist\n\n\nWas bewirkt ein Git-Commit? Git-Commit-Nachrichten sind die Fingerabdrücke,\ndie du auf dem Code hinterlässt, den du bearbeitest. Wenn du heute einen\nCode festlegst, ist es wichtig, eine klare und aussagekräftige\nCommit-Nachricht zu schreiben, damit du diese auch später noch\nnachvollziehen kannst. Indem Git-Commits kontextabhängig isoliert werden,\nist ein Fehler, der durch einen einzelnen Commit verursacht wurde, schneller\nzu finden. Zudem ist es einfacher, den Commit rückgängig zu machen, der den\nFehler verursacht hat.\n\n\nBei der Arbeit an großen Projekten haben wir oft mit vielen verschiedenen\nKomponenten, die aktualisiert, hinzugefügt oder entfernt werden, zu tun. In\nsolchen Fällen kann es schwierig sein, die Commit-Nachrichten zu pflegen,\ninsbesondere wenn sich die Entwicklung über Tage, Wochen oder sogar Monate\nerstreckt. Um die Wartung eines übersichtlichen Commit-Verlaufs zu\nerleichtern, findest du nachfolgend die vier häufigsten Situationen, mit\ndenen ein Entwickler(innen) bei der Arbeit an einem Git-Repository\nkonfrontiert werden kann.\n\n\n1. Situation 1: Ich muss den letzten Commit ändern\n\n2. Situation 2: Ich muss einen bestimmten Commit ändern\n\n3. Situation 3: Ich muss Commits hinzufügen, entfernen oder kombinieren\n\n4. Situation 4: Mein Commit-Verlauf macht keinen Sinn, ich muss nochmal von\nvorne anfangen\n\n\nBevor wir jedoch tiefer eintauchen, werfen wir einen kurzen Blick auf einen\ntypischen Entwicklungsablauf in unserer hypothetischen Ruby-Anwendung.\n\n\n__Hinweis:__ In diesem Artikel wird vorausgesetzt, dass du mit den\nGrundlagen von Git vertraut bist und weißt, wie Branches funktionieren, wie\nnicht übertragene Änderungen eines Branches zum Staging-Bereich hinzugefügt\nund wie Änderungen übertragen werden. Wenn du unsicher bist, bietet unsere\nDokumentation einen guten Ausgangspunkt.\n\n\n## Beispielprojekt: Neue Navigationsansicht\n\n\nNachfolgend siehst du ein Ruby-on-Rails-Projekt, in dem eine\nNavigationsansicht auf der Homepage hinzugefügt werden muss. Dazu müssen\nmehrere Dateien aktualisiert und hinzugefügt werden. Im Folgenden findest du\neine schrittweise Aufschlüsselung des gesamten Ablaufs:\n\n\n- Du startest die Arbeit an einem Feature, indem du eine einzelne Datei\naktualisierst. Zum Beispiel: `application_controller.rb`\n\n- Für dieses Feature musst du auch eine Ansicht aktualisieren:\n`index.html.haml`\n\n- Du hast einen Teilbereich hinzugefügt, der auf der Indexseite verwendet\nwird: `_navigation.html.haml`\n\n- Die Formatvorlagen für die Seite müssen ebenfalls aktualisiert werden, um\nden hinzugefügten Teil widerzuspiegeln: `styles.css.scss`\n\n- Das Feature ist nun mit den gewünschten Änderungen fertiggestellt. Jetzt\nmusst du die Tests aktualisieren. Dazu gehören die folgenden Dateien:\n  - `application_controller_spec.rb`\n  - `navigation_spec.rb`\n- Die Tests wurden aktualisiert und laufen wie erwartet. Jetzt werden die\nÄnderungen übertragen.\n\n\nDa alle Dateien zu verschiedenen Bereichen der Architektur gehören, werden\ndie Änderungen isoliert voneinander übertragen. Dies gewährleistet, dass\njede Übertragung einen spezifischen Kontext repräsentiert und in einer\nbestimmten Reihenfolge durchgeführt wird. Im Allgemeinen wird die\nReihenfolge von Backend -> Frontend bevorzugt. Dies bedeutet, dass die\nmeisten Backend-bezogenen Änderungen zuerst übertragen werden, gefolgt von\nder mittleren Schicht und dann von den Frontend-bezogenen Änderungen in den\nGit-Commits.\n\n\n1. `application_controller.rb` & `application_controller_spec.rb`:\n__Hinzufügen von Routen für die Navigation.__\n\n2. `_navigation.html.haml` & `navigation_spec.rb`: __Ansicht der\nSeitennavigation.__\n\n3. `index.html.haml`: __Navigation teilweise rendern.__\n\n4. `styles.css.scss`: __Stile für die Navigation hinzufügen.__\n\n\nNachdem die Änderungen übertragen wurden, wird eine Anfrage zur\nZusammenführung mit dem Branch erstellt. Sobald du eine Merge-Anfrage\ngeöffnet hast, wird sie in der Regel von deinem Peer überprüft, bevor die\nÄnderungen im Master-Branch des Repositories zusammengeführt werden. Im\nFolgenden werden die verschiedenen Situationen beschrieben, die bei der\nCodeüberprüfung auftreten können.\n\n\n## Situation 1: Ändern des letzten Git-Commits\n\n\nIm Fall, dass der Prüfer die Datei `styles.css.scss` überprüft und eine\nÄnderung vorgeschlagen hat, ist es recht einfach, die Änderung vorzunehmen,\nda die Stylesheet-Änderungen Teil des __letzten__ Commits in deinem Branch\nsind. So kannst du damit umgehen:\n\n\n- Führe die erforderlichen Änderungen an `styles.css.scss` direkt in deinem\naktuellen Branch durch.\n\n- Sobald du mit den Änderungen fertig bist, füge sie zum Staging-Bereich\nhinzu, indem du `git add styles.css.scss` ausführst.\n\n- Nachdem die Änderungen bereitgestellt wurden, füge sie zu deinem letzten\nCommit hinzu, indem du `git commit --amend` ausführst.\n    - __Aufschlüsselung des Befehls__: Mit dem `git commit`-Befehl werden alle Änderungen, die sich im Staging-Bereich befinden, dem letzten Commit hinzugefügt.\n- Dadurch wird der von Git definierte Texteditor geöffnet, der die\nCommit-Nachricht __„Stile für die Navigation hinzufügen”__ enthält, die\nbereits beim vorherigen Commit festgelegt wurde.\n\n- Da nur die CSS-Deklaration aktualisiert wurde, muss die Commit-Nachricht\nnicht geändert werden. An dieser Stelle kannst du einfach speichern und den\nTexteditor, den Git für dich geöffnet hat, beenden. Deine Änderungen werden\ndann in den Commit übernommen.\n\n\nDa du ein bestehendes Git-Commit geändert hast, müssen diese Änderungen\nzwangsweise in dein Repository übertragen werden. Dazu nutzt du  `git push\n--force-with-lease \u003Cremote_name> \u003Cbranch_name>`. Dieser Befehl überschreibt\ndas Commit `Add styles for navigation` im entfernten Repository mit dem\naktualisierten Commit, das gerade im lokalen Repository vorgenommen wurde.\n\n\nWenn mehrere Personen an einem Branch arbeiten, kann ein erzwungener Push\nvon Branches dazu führen, dass andere Benutzer Probleme bekommen, wenn sie\nversuchen, ihre Änderungen auf einen entfernten Branch zu pushen, in dem\nbereits neue Commits gepusht wurden. Daher sollte diese Funktion mit Bedacht\neingesetzt werden. Weitere Informationen zu den Force-Push-Optionen von Git\nfindest du\n[hier](https://git-scm.com/docs/git-push#git-push---no-force-with-lease\n\"hier\").\n\n\n## Situation 2: Ändern einer bestimmten Git-Commit-Änderung\n\n\nIn der vorherigen Situation war die Änderung des Git-Commits recht einfach,\nda nur der letzte Git-Commit geändert werden musste. Stell dir jedoch vor,\nein Prüfer würde vorschlagen, etwas in `_navigation.html.haml` zu ändern. In\ndiesem Fall handelt es sich um den zweiten Commit von oben, sodass die\nÄnderung nicht so direkt ist wie in der ersten Situation. \n\n\nJeder Commit in einem Branch wird durch eine eindeutige\nSHA-1-Hash-Zeichenkette identifiziert. Diese dient als eine Art eindeutige\nID, die einen Commit von einem anderen unterscheidet. Du kannst alle\nvorherigen Commits zusammen mit ihren SHA-1-Hashes in einem Branch anzeigen,\nindem du den Befehl `git log` ausführst. Das Ergebnis ist eine Liste von\nCommits, wobei die neuesten Commits ganz oben stehen.\n\n\n```\n\ncommit aa0a35a867ed2094da60042062e8f3d6000e3952 (HEAD ->\nadd-page-navigation)\n\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\n\nDate: Wed May 2 15:24:02 2018 +0530\n\n    Add styles for navigation\n\ncommit c22a3fa0c5cdc175f2b8232b9704079d27c619d0\n\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\n\nDate: Wed May 2 08:42:52 2018 +0000\n\n    Render navigation partial\n\ncommit 4155df1cdc7be01c98b0773497ff65c22ba1549f\n\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\n\nDate: Wed May 2 08:42:51 2018 +0000\n\n    Page Navigation View\n\ncommit 8d74af102941aa0b51e1a35b8ad731284e4b5a20\n\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\n\nDate: Wed May 2 08:12:20 2018 +0000\n\n    Add routes for navigation\n```\n\n\nAn dieser Stelle kommt der Befehl `git rebase` ins Spiel. Wenn wir einen\nbestimmten Commit mit `git rebase` bearbeiten wollen, müssen wir zunächst\nunseren Branch neu erstellen, indem wir HEAD bis zu dem Punkt vor dem Commit\nzurücksetzen, den wir bearbeiten wollen. In unserem Fall müssen wir den\nCommit ändern, der `Page Navigation View` lautet.\n\n\n![Ansicht Page Navigation\nView](https://about.gitlab.com/images/blogimages/keeping-git-commit-history-clean/GitRebase.png){:\n.shadow.center.medium}\n\n\n- Achte auf den Hash des Commits, der direkt vor dem Commit liegt, den wir\nändern möchten. Kopiere den Hash und führe die folgenden Schritte aus:\n\n- Verschiebe den Branch auf einen Commit vor unserem Ziel-Commit; führe `git\nrebase -i8d74af102941aa0b51e1a35b8ad731284e4b5a20` aus.\n    - __Aufschlüsselung der Git-Befehle:__ Hier führen wir den Git-Befehl `rebase` im interaktiven Modus aus und geben einen SHA-1-Hash als Commit an, auf den `rebase` erfolgen soll.\n- Dieser Befehl führt den rebase-Befehl für Git im interaktiven Modus aus\nund öffnet den Texteditor, der alle Commits anzeigt, die auf den Commit\nfolgen, auf den du den `rebase` durchführen möchtest. Der Texteditor sollte\nin etwa so aussehen:\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick c22a3fa0c5c Render navigation partial\n\npick aa0a35a867e Add styles for navigation\n\n\n# Rebase 8d74af10294..aa0a35a867e onto 8d74af10294 (3 commands)\n\n#\n\n# Commands:\n\n# p, pick = use commit\n\n# r, reword = use commit, but edit the commit message\n\n# e, edit = use commit, but stop for amending\n\n# s, squash = use commit, but meld into previous commit\n\n# f, fixup = like \"squash\", but discard this commit's log message\n\n# x, exec = run command (the rest of the line) using shell\n\n# d, drop = remove Git commit\n\n#\n\n# These lines can be re-ordered; they are executed from top to bottom.\n\n#\n\n# If you remove a line here THAT COMMIT WILL BE LOST.\n\n#\n\n# However, if you remove everything, the rebase will be aborted.\n\n#\n\n# Note that empty commits are commented out\n\n```\n\n\nBeachte, dass jedem Commit das Wort `pick` vorangestellt ist. Im Inhalt\nunten sind alle möglichen Schlüsselwörter aufgeführt, die du verwenden\nkannst. Da du eine Übertragung bearbeiten möchtest, musst du `pick\n4155df1cdc7 Page Navigation View in edit 4155df1cdc7 Page Navigation View`\nändern. Speichere die Änderungen und verlasse den Editor.\n\n\nDer Branch wird nun auf den Zeitpunkt vor der Commit-Übergabe zurückgesetzt,\ndie die Datei `_navigation.html.haml` enthielt. Öffne die Datei und führe\ndie gewünschten Änderungen gemäß dem Feedback der Überprüfung durch. Sobald\ndu mit den Änderungen fertig bist, füge sie zum Staging-Bereich hinzu, indem\ndu `git add _navigation.html.haml` ausführst.\n\n\nNachdem die Änderungen bereitgestellt wurden, ist es an der Zeit, den Branch\nHEAD wieder auf den ursprünglichen Commit zurückzusetzen, wobei auch die neu\nhinzugefügten Änderungen berücksichtigt werden. Führe `git rebase\n--continue` aus. Dadurch wird dein Standardeditor im Terminal geöffnet und\nzeigt die Commit-Nachricht an, die während des Rebase bearbeitet wurde; in\ndiesem Fall Page `Navigation View`. Du kannst diese Nachricht ändern, wenn\ndu möchtest – zunächst bleibt sie jedoch unverändert. Speichere und beende\nden Editor.\n\n\nJetzt zeigt Git alle Commits an, die auf den Commit folgten, den du gerade\nbearbeitet hast. Der Branch `HEAD` ist jetzt wieder auf dem ursprünglichen\nobersten Commit. Er enthält auch die neuen Änderungen, die du an einem der\nCommits vorgenommen hast.\n\n\nDa du erneut einen Commit geändert hast, der bereits im entfernten\nRepository vorhanden ist, musst du diesen Branch noch einmal mit `git push\n--force-with-lease \u003Cremote_name> \u003Cbranch_name>` pushen.\n\n\n## Situation 3: Hinzufügen, Entfernen oder Kombinieren von Git-Commits\n\n\nEs kommt häufig vor, dass mehrere Commits gemacht wurden, nur um etwas zu\nkorrigieren, das bereits zuvor committed wurde. Jetzt möchtest du diese\nCommits so weit wie möglich reduzieren und mit den ursprünglichen Commits\nkombinieren.\n\n\nDazu musst du einfach den interaktiven Rebase wie in den anderen Szenarien\nstarten.\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick c22a3fa0c5c Render navigation partial\n\npick aa0a35a867e Add styles for navigation\n\npick 62e858a322 Fix a typo\n\npick 5c25eb48c8 Ops another fix\n\npick 7f0718efe9 Fix 2\n\npick f0ffc19ef7 Argh Another fix!\n\n```\n\n\nNun stell dir vor, du möchtest all diese Korrekturen in `c22a3fa0c5c Render\nnavigation partial` kombinieren. Dazu musst du nur Folgendes tun:\n\n\n1. Verschiebe die Korrekturen nach oben, sodass sie sich direkt unter der\nCommit-Übergabe befinden, die du am Ende behalten möchtest.\n\n2. Ändere `pick` auf `squash` oder `fixup` für jede der Korrekturen.\n\n\n*Hinweis:* `squash` behält die Commit-Nachrichten der Git-Fixes in der\nBeschreibung bei. `fixup` vergisst die Commit-Nachrichten der Fixes und\nbehält das Original bei.\n\nDas Ergebnis sieht dann etwa so aus:\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick c22a3fa0c5c Render navigation partial\n\nfixup 62e858a322 Fix a typo\n\nfixup 5c25eb48c8 Ops another fix\n\nfixup 7f0718efe9 Fix 2\n\nfixup f0ffc19ef7 Argh Another fix!\n\npick aa0a35a867e Add styles for navigation\n\n```\n\n\nSpeichere die Änderungen, beende den Editor und schon bist du fertig! Dies\nist der resultierende Verlauf:\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick 96373c0bcf Render navigation partial\n\npick aa0a35a867e Add styles for navigation\n\n```\n\n\nWie zuvor musst du jetzt nur noch `git push --force-with-lease \u003Cremote_name>\n\u003Cbranch_name>` ausführen, damit die Änderungen sichtbar sind.\n\n\nWenn du einen Git-Commit vollständig aus dem Branch entfernen möchtest,\nschreibe statt `squash` oder `fixup` einfach `drop` oder lösche diese Zeile.\n\n\n## Vermeiden von Konflikten bei Git-Commits\n\n\nUm Konflikte zu vermeiden, solltest du sicherstellen, dass die Commits, die\ndu in der Zeitleiste nach vorne schiebst, nicht dieselben Dateien berühren,\ndie von den Commits nach ihnen bearbeitet werden.\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick c22a3fa0c5c Render navigation partial\n\nfixup 62e858a322 Fix a typo                 # this changes styles.css\n\nfixup 5c25eb48c8 Ops another fix            # this changes image/logo.svg\n\nfixup 7f0718efe9 Fix 2                      # this changes styles.css\n\nfixup f0ffc19ef7 Argh Another fix!          # this changes styles.css\n\npick aa0a35a867e Add styles for navigation  # this changes index.html (no\nconflict)\n\n```\n\n\n## Extra-Tipp: Schnelle Git commit fixups\n\n\nWenn du genau weißt, welchen Commit du reparieren möchtest, musst du beim\nCommit keine Zeit damit verschwenden, dir gute temporäre Namen für \"Fix 1\",\n\"Fix 2\", ..., \"Fix 42\" auszudenken.\n\n\n### Step 1: `--fixup`\n\n\nNachdem du die Änderungen vorgenommen hast, um das zu reparieren, was\nrepariert werden muss, übergibst du einfach alle Änderungen mit Git wie\nfolgt:\n\n\n```\n\ngit commit --fixup c22a3fa0c5c\n\n```\n\n(Dies ist der Hash für den Commit `c22a3fa0c5c Render navigation partial`)\n\nDadurch wird diese Commit-Nachricht erzeugt: `fixup! Render navigation\npartial`.\n\n\n### Step 2: `--autosquash`\n\n\nEinfaches interaktives Rebase. Du kannst `git` die `fixups` automatisch an\nder richtigen Stelle platzieren lassen.\n\n\n`git rebase -i 4155df1cdc7 --autosquash`\n\n\nDer Verlauf wird folgendermaßen dargestellt:\n\n\n```\n\npick 4155df1cdc7 Page Navigation View\n\npick c22a3fa0c5c Render navigation partial\n\nfixup 62e858a322 Fix a typo\n\nfixup 5c25eb48c8 Ops another fix\n\nfixup 7f0718efe9 Fix 2\n\nfixup f0ffc19ef7 Argh Another fix!\n\npick aa0a35a867e Add styles for navigation\n\n```\n\n\nDu kannst sie einfach überprüfen und fortsetzen. \n\n\nFalls du experimentierfreudig bist, besteht die Möglichkeit, ein nicht\ninteraktives Rebase mit `git rebase --autosquash` durchzuführen. Dies sollte\njedoch mit Vorsicht geschehen, da du keine Möglichkeit hast, die Squashs vor\nihrer Anwendung zu überprüfen, was potenziell zu unerwarteten Ergebnissen\nführen kann.\n\n\n## Situation 4: Der Verlauf meiner Git-Commits ergibt keinen Sinn, ich\nmöchte von vorn beginnen!\n\n\nWenn wir an einer umfangreichen Funktion arbeiten, ist es üblich, dass wir\nmehrere Korrekturen und Rückmeldungen vornehmen, die häufig übertragen\nwerden. Anstatt den Branch ständig zu ändern, können wir das Aufräumen der\nGit-Commits bis zum Ende der Entwicklung aufschieben.\n\n\nIn solchen Fällen erweisen sich Patch-Dateien als äußerst praktisch. Bevor\nGit-basierte Dienste wie GitLab den Entwickler(inne)n zur Verfügung standen,\nwaren Patch-Dateien die wichtigste Methode, um bei der Zusammenarbeit an\ngroßen Open-Source-Projekten Code per E-Mail auszutauschen.\n\n\nAngenommen, du hast einen solchen Branch (z. B. \"`add-page-navigation`\"), in\ndem es tonnenweise Commits gibt, die die zugrunde liegenden Änderungen nicht\nklar vermitteln, dann kannst du folgendermaßen eine Patch-Datei für alle\nÄnderungen erstellen, die du in diesem Branch vorgenommen hast:\n\n\n- Um eine Patch-Datei zu erstellen, muss zunächst sichergestellt werden,\ndass der Branch alle Änderungen aus dem `master`-Branch enthält und keine\nKonflikte damit aufweist.\n\n- Um alle Änderungen vom Master-Branch in deinen\n`add-page-navigation`-Branch zu übernehmen, kannst du entweder `git rebase\nmaster` oder `git merge master` ausführen, während du im\n`add-page-navigation-Branch` ausgecheckt bist.\n\n- Nun erstellst du die Patch-Datei. Führe `git diff master\nadd-page-navigation > ~/add_page_navigation.patch` aus.\n  - __Aufschlüsselung des Befehls:__ Hier verwenden wir die Diff-Funktion von Git und fordern einen Vergleich zwischen dem `master`-Branch und dem `add-page-navigation`-Branch an. Die Ausgabe wird über das \"`>`\"-Symbol in eine Datei namens `add_page_navigation.patch` in unserem Benutzerverzeichnis (typischerweise ~/ in Unix-basierten Betriebssystemen) umgeleitet.\n  - Du kannst einen beliebigen Pfad angeben, in dem die Datei gespeichert werden soll. Der Dateiname und die Erweiterung können beliebig gewählt werden.\n  - Sobald der Befehl ausgeführt wurde und keine Fehler angezeigt werden, wird die Patch-Datei erstellt.\n  - Checke jetzt den `master`-Branch aus; führe `git checkout master` aus.\n  - Du kannst den Branch `add-page-navigation` aus deinem lokalen Repository löschen, indem du `git branch -D add-page-navigation` ausführst. Denke daran, dass die Änderungen dieses Branchs bereits in einer erstellten Patch-Datei enthalten sind.\n  - Erstelle nun einen neuen Branch mit demselben Namen (während `master` ausgecheckt ist); führe `git checkout -b add-page-navigation` aus.\n  - Zu diesem Zeitpunkt ist dies ein neuer Branch, der noch keine der Änderungen enthält.\n  - Zum Schluss werden die Änderungen aus der Patch-Datei übernommen; `git apply ~/add_page_navigation.patch`.\n  - Hier werden alle Änderungen in einen Branch übernommen und erscheinen als \"uncommitted\", so, als ob du alle Änderungen vorgenommen hättest, aber keine der Änderungen tatsächlich in den Branch übernommen wurden.\n  - Jetzt kannst du einzelne Dateien oder nach Einflussbereich gruppierte Dateien in der gewünschten Reihenfolge mit prägnanten Commit-Nachrichten übertragen.\n\nWie in vorherigen Situationen wurde der gesamte Branch geändert, also ist es\nan der Zeit, einen Push zu erzwingen!\n\n\n## Gründe, deine Git-Commit-Historie aufzuräumen\n\n\nBasierend auf den beschriebenen Situationen, gibt es sechs wichtige Gründe,\ndeine Git-Commit-Historie aufzuräumen:\n\n\n- __Bessere Nachvollziehbarkeit:__ Eine übersichtliche Commit-Historie\nerleichtert es Entwickler(innen)n, den [Verlauf des\nCodes](https://about.gitlab.com/de-de/solutions/source-code-management/\n\"Verlauf des Codes\") zu verstehen und Änderungen nachzuvollziehen.\n\n- __Effiziente Fehlerbehebung:__ Durch klare Commit-Nachrichten und eine\nstrukturierte Historie können Fehler schneller identifiziert und behoben\nwerden.\n\n- __Verbesserte Zusammenarbeit:__ Ein aufgeräumter Commit-Verlauf\nerleichtert die Zusammenarbeit im Team, da Entwickler(innen)schnell den\nKontext und den Zweck früherer Änderungen verstehen können.\n\n- __Effizientere Wartung:__ Weniger Zeit wird mit der Suche nach\nspezifischen Änderungen und deren Kontext verschwendet, was die Wartung des\nCodes effizienter macht.\n\n- __Verbesserte Codequalität:__ Eine saubere Commit-Historie fördert\nbewusstere Entscheidungen beim Committen und trägt so zur Verbesserung der\nCodequalität bei.\n\n- __Gesamtproduktivität steigern:__ Indem Entwickler(innen) weniger Zeit mit\nder Suche nach Informationen in der Commit-Historie verbringen, können sie\nsich besser auf die eigentliche Entwicklung konzentrieren und die\nGesamtproduktivität des Teams steigern.\n\n\nWenn du dich mit den Tipps vertraut gemacht hast, kannst du in der\n[offiziellen\nGit-Dokumentation](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History\n\"offiziellen Git-Dokumentation\") mehr über fortgeschrittene Konzepte zu\ndiesem Thema erfahren. Viel Spaß mit Git!\n",[681,1102],"workflow","2024-10-10",{"slug":1105,"featured":6,"template":672},"keeping-git-commit-history-clean","content:de-de:blog:keeping-git-commit-history-clean.yml","Keeping Git Commit History Clean","de-de/blog/keeping-git-commit-history-clean.yml","de-de/blog/keeping-git-commit-history-clean",{"_path":1111,"_dir":248,"_draft":6,"_partial":6,"_locale":7,"seo":1112,"content":1118,"config":1124,"_id":1126,"_type":16,"title":1127,"_source":17,"_file":1128,"_stem":1129,"_extension":20},"/de-de/blog/gitlab-container-registry",{"title":1113,"description":1114,"ogTitle":1113,"ogDescription":1114,"noIndex":6,"ogImage":1115,"ogUrl":1116,"ogSiteName":758,"ogType":784,"canonicalUrls":1116,"schema":1117},"Was ist das Gitlab Container Registry?"," Die auf Open Source basierende GitLab Container Registry ist nicht nur eine eigenständige Registry, sondern vollständig in GitLab integriert.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665223/Blog/Hero%20Images/containers.jpg","https://about.gitlab.com/blog/gitlab-container-registry","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Was ist das Gitlab Container Registry?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mark Pundsack\"}],\n        \"datePublished\": \"2016-05-23\",\n      }",{"title":1113,"description":1114,"authors":1119,"heroImage":1115,"date":1121,"body":1122,"category":14,"updatedDate":1123},[1120],"Mark Pundsack","2016-05-23","# Was ist das GitLab Container Registry? \n\nSeit dem Launch von GitLab 8.8. ist es möglich, eine Pipeline in GitLab aufzubauen und deine Builds, Tests, Deploys und jede andere Phase des Lebenszyklus deiner Software zu visualisieren. Dafür nutzt du die GitLab Container Registry.\n\nIn diesem Artikel erfährst du, was das Container Registry ist, wie du es anwendest und wie es dir dein Arbeitsleben leichter machen kann.\n\n## GitLab Container Registry – wie funktioniert’s?\n\nDie GitLab Container Registry bietet eine sichere und private Speicherlösung für Docker-Images. Sie ist nicht nur eine eigenständige Datenbank, sondern auch nahtlos in GitLab integriert. Unser Ziel bei GitLab ist es, ein konsistentes und integriertes Benutzererlebnis zu bieten. Die Registry ist dabei keine Ausnahme. Mit ihrer Integration kannst du deine Images problemlos für GitLab CI verwenden, spezielle Images für Tags oder Branches erstellen und vieles mehr.\nSie ist bei Installation bereits vollständig in die Git-Repository-Verwaltung integriert – es ist also keine zusätzliche Installation erforderlich. Zudem ermöglicht sie ein einfaches Hoch- und Herunterladen von Images über GitLab CI.\n\nIn der Verwaltungsdokumentation findest du detaillierte Anleitungen, wie du die Container-Registry in deiner GitLab-Instanz aktivieren kannst. Diese umfassende Dokumentation deckt alles ab, von der Konfiguration selbstsignierter Zertifikate bis hin zu Umgebungsvariablen, Garbage-Collect-Befehlen, verschiedenen APIs, Curl-Befehlen, der Festlegung von Ratenlimits und der Integration einer externen Registry. \n\n## Grundlagen zu Docker\n\nEin unverzichtbarer Bestandteil eines Docker-orientierten Arbeitsablaufs ist ein Image, das sämtliche Ressourcen für die Ausführung einer Anwendung beinhaltet. Häufig werden Images automatisch im Rahmen der Continuous Integration erstellt, wodurch sie bei jeder Codeänderung aktualisiert werden. Wenn Images für die gemeinsame Nutzung zwischen Entwickler(innen) und Maschinen erstellt werden sollen, ist es wichtig, dass sie an einem zentralen Ort gespeichert sind. Hierbei kommt eine Container Registry ins Spiel.\n\nDie Registry fungiert als Speicherort für Images. Hier können sie gehostet und für zukünftige Verwendung markiert werden. Entwickler(innen) können ihre eigene Registry einrichten, um private Images zu speichern oder temporäre Images für Testzwecke zu nutzen. Mit der Nutzung der GitLab Container Registry ist es nicht erforderlich, einen zusätzlichen Dienst einzurichten und zu verwalten oder auf eine öffentliche Registry zurückzugreifen.\n\n## Vollständige Integration\n\nDie GitLab Container Registry ist vollständig in GitLab integriert und erleichtert Entwickler(innen) das Programmieren, Testen und Bereitstellen von Docker-Container-Images mit GitLab [CI](https://about.gitlab.com/de-de/topics/ci-cd/) und anderen Docker-kompatiblen Tools.\n\nDie Benutzerauthentifizierung erfolgt über GitLab selbst, sodass alle Benutzer- und Gruppendefinitionen beachtet werden. Es müssen keine Repositories in der Registry erstellt werden, da das Projekt bereits in GitLab definiert ist.\n\nProjekte haben eine neue Registerkarte, Container Registry, in der alle mit dem Projekt verbundenen Images aufgelistet sind. Jedes Projekt kann über ein Image-Repository verfügen, das jedoch projektspezifisch ausgeschaltet werden kann. Entwickler(innen) können Images einfach von GitLab CI hoch- und herunterladen. Es ist nicht erforderlich, zusätzliche Software herunterzuladen oder zu installieren.\n\n## Sicherheit mit dem GitLab Container Scanning\n\nGitLab Container Scanning ist eine Sicherheitsfunktion, die in GitLab integriert ist und dazu dient, Docker-Images auf potenzielle Sicherheitsrisiken zu überprüfen. Diese Funktion ermöglicht es Entwickler(innen), während des Entwicklungsprozesses automatisch Sicherheitsanalysen auf Docker-Images durchzuführen, bevor sie in Produktionsumgebungen eingesetzt werden.\n\nKonkret scannt das GitLab Container Scanning Tool die Docker-Images nach bekannten Sicherheitslücken, Schwachstellen und Bedrohungen. Dies erfolgt durch die Analyse der in den Images enthaltenen Pakete und Bibliotheken sowie deren Abhängigkeiten. \n\nEs identifiziert dabei potenzielle Sicherheitsprobleme und liefert den Entwickler(innen) oder dem Team detaillierte Berichte darüber, was gefunden wurde und wie diese Schwachstellen behoben werden können. Durch die Integration von Docker Container Scanning in den Entwicklungsworkflow können Sicherheitslücken frühzeitig erkannt und behoben werden, noch bevor die Software in Produktion geht. Dies trägt dazu bei, die Sicherheit der Anwendungen zu erhöhen und das Risiko von Sicherheitsverletzungen zu minimieren.\n\n## Wie kann die GitLab Container Registry meinen Workflow vereinfachen?\n\nDie GitLab Container Registry ist nahtlos und sicher. Hier sind einige Beispiele dafür, wie sie Entwicklungs- und Bereitstellungsabläufe vereinfachen kann:\n\n- Erstelle ganz einfach Docker-Images mithilfe von GitLab CI und speichere sie in der GitLab Container Registry.\n\n- Erstelle Images basierend auf Branches, Tags oder nach beliebigen Workflow-Anforderungen und speichere sie unkompliziert auf GitLab.\n\n- Nutze deine eigenen Build-Images aus der Registry, um Anwendungen gegen sie zu testen und den Docker-Workflow zu vereinfachen.\n\n- Ermögliche dem Team, einfach an den Images mitzuarbeiten, indem es den vertrauten Workflow verwendet. Mithilfe von GitLab CI können Images, die auf deinem Image basieren, automatisch aktualisiert werden, sodass Korrekturen und neue Funktionen problemlos auf Basis-Images angewendet werden können, die von anderen Teams verwendet werden.\n\n- Implementiere einen vollständigen Continuous-Deployment- und Delivery-Workflow, indem du dein Container-as-a-Service (CaaS) so konfigurierst, dass es Images direkt aus der GitLab Container Registry verwendet. Dadurch kannst du automatisch Anwendungen in der Cloud bereitstellen (Docker Cloud, Docker Swarm, Kubernetes und andere), sobald du deine Images erstellt und getestet hast.\n\n## So startest du mit GitLab Container Registry\n\nUm mit der GitLab Container Registry zu beginnen, wende dich zunächst an deine(n) Systemadministrator(in) und bitte sie/ihn, die Container Registry gemäß den Anweisungen in der Administrationsdokumentation zu aktivieren. Nach der Aktivierung durch die/den Administrator(in) kannst du die Container Registry für dein spezifisches Projekt aktivieren.\n\nUm deine neue Container Registry nutzen zu können, musst du dich zunächst anmelden:\ndocker login registry.example.com\n\nDanach kannst du einfach Images erstellen und an GitLab senden:\ndocker build -t registry.example.com/group/project .\ndocker push registry.example.com/group/project\n\nGitLab bietet eine unkomplizierte Verwaltung der Container Registry. Gehe einfach zu deinem Projekt, öffne den Deploy-Tab und wähle  Container Registry. Dort werden alle Tags in deinem Repository aufgeführt. Hier kannst du sie löschen sowie Details zu jedem Tag anzeigen, wie beispielsweise das Veröffentlichungsdatum und den Speicherplatzverbrauch.\n\nWeitere Informationen findest du im GitLab-Container-Registry-Benutzerhandbuch.\n\n## Verwendung mit GitLab CI\nMithilfe der integrierten CI-Lösung in GitLab kannst du deine Container-Images erstellen, pushen und bereitstellen.\n\nHinweis: Um Docker-in-Docker-Images zu verwenden, muss das Flag privileged in der Konfiguration deines Runners gesetzt sein. \n\nNachfolgend siehst du ein Beispiel für eine GitLab CI-Konfigurationsdatei (.gitlab-ci.yml), die ein Image erstellt, Tests ausführt und bei erfolgreichem Test das Build taggt und in das Container Repository hochlädt:\n\nbuild_image:\n  image: docker:git\n  services:\n  - docker:dind\n  script:\n    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.example.com\n    - docker build -t registry.example.com/my-group/my-project .\n    - docker run registry.example.com/my-group/my-project /script/to/run/tests\n    - docker push registry.example.com/my-group/my-project:latest\n  only:\n    - master\n\nHier ist ein detailliertes Beispiel, bei dem die Aufgaben in vier Phasen aufgeteilt werden, einschließlich zweier paralleler Tests. Der Build wird in der Container Registry gespeichert und von den nachfolgenden Phasen verwendet, wobei das Image bei Bedarf automatisch heruntergeladen wird. Änderungen am master werden auch als latest getaggt und mithilfe eines spezifischen Bereitstellungsskripts für die Anwendung bereitgestellt.\n\nimage: docker:git\nservices:\n- docker:dind\n\nstages:\n- build\n- test\n- release\n- deploy\n\nvariables:\n  CONTAINER_TEST_IMAGE: registry.example.com/my-group/my-project:$CI_BUILD_REF_NAME\n  CONTAINER_RELEASE_IMAGE: registry.example.com/my-group/my-project:latest\n\nbefore_script:\n  - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.example.com\n\nbuild:\n  stage: build\n  script:\n    - docker build -t $CONTAINER_TEST_IMAGE .\n    - docker push $CONTAINER_TEST_IMAGE\n\ntest1:\n  stage: test\n  script:\n    - docker run $CONTAINER_TEST_IMAGE /script/to/run/tests\n\ntest2:\n  stage: test\n  script:\n    - docker run $CONTAINER_TEST_IMAGE /script/to/run/another/test\n\nrelease-image:\n  stage: release\n  script:\n    - docker pull $CONTAINER_TEST_IMAGE\n    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE\n    - docker push $CONTAINER_RELEASE_IMAGE\n  only:\n    - master\n\ndeploy:\n  stage: deploy\n  script:\n    - ./deploy.sh\n  only:\n    - master\n\n## Fazit\n\nMit der GitLab Container Registry wird das Testen und Bereitstellen von Docker-Containern so einfach wie nie zuvor. Sie ist sowohl in der GitLab Community Edition (CE) als auch in der GitLab Enterprise Edition (EE) ohne zusätzliche Kosten verfügbar und wird in derselben Infrastruktur wie der Rest deiner GitLab-Instanz installiert.\n\nDie Aktivierung der Container Registry auf GitLab.com ist unkompliziert – zudem entstehen dadurch keine weiteren Kosten. Du kannst sie sofort nutzen, um deine Container-Images zu verwalten und bereitzustellen.\n","2024-12-17",{"slug":1125,"featured":6,"template":672},"gitlab-container-registry","content:de-de:blog:gitlab-container-registry.yml","Gitlab Container Registry","de-de/blog/gitlab-container-registry.yml","de-de/blog/gitlab-container-registry",3,[690,709,729,751,777,798,819,843,866],1758662293008]