[{"data":1,"prerenderedAt":820},["ShallowReactive",2],{"/de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab":3,"navigation-de-de":47,"banner-de-de":460,"footer-de-de":470,"blog-post-authors-de-de-Tim Rizzi":705,"blog-related-posts-de-de-automating-container-image-migration-from-amazon-ecr-to-gitlab":719,"blog-promotions-de-de":757,"next-steps-de-de":810},{"id":4,"title":5,"authorSlugs":6,"authors":8,"body":10,"category":11,"categorySlug":11,"config":12,"content":16,"date":20,"description":17,"extension":29,"externalUrl":30,"featured":14,"heroImage":19,"isFeatured":14,"meta":31,"navigation":14,"path":32,"publishedDate":20,"rawbody":33,"seo":34,"slug":13,"stem":39,"tagSlugs":40,"tags":45,"template":15,"updatedDate":28,"__hash__":46},"blogPosts/de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab.yml","Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab",[7],"tim-rizzi",[9],"Tim Rizzi","„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```yaml\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).","engineering",{"slug":13,"featured":14,"template":15},"automating-container-image-migration-from-amazon-ecr-to-gitlab",true,"BlogPost",{"title":5,"description":17,"authors":18,"heroImage":19,"date":20,"body":10,"category":11,"tags":21,"updatedDate":28},"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.",[9],"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663129/Blog/Hero%20Images/blog-image-template-1800x945__28_.png","2025-02-13",[22,23,24,25,26,27],"CI/CD","AWS","tutorial","DevSecOps platform","product","solutions architecture","2025-04-10","yml",null,{},"/de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab","seo:\n  title: 'Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab'\n  description: >-\n    Wenn Plattformteams ihre CI/CD zu GitLab verschieben, sollte die Migration\n    von Container-Images kein Engpass sein. Befolge diese\n    Schritt-für-Schritt-Anleitung, um den Pipeline-Migrationsprozess zu\n    automatisieren.\n  ogTitle: 'Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab'\n  ogDescription: >-\n    Wenn Plattformteams ihre CI/CD zu GitLab verschieben, sollte die Migration\n    von Container-Images kein Engpass sein. Befolge diese\n    Schritt-für-Schritt-Anleitung, um den Pipeline-Migrationsprozess zu\n    automatisieren.\n  noIndex: false\n  ogImage: >-\n    https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663129/Blog/Hero%20Images/blog-image-template-1800x945__28_.png\n  ogUrl: >-\n    https://about.gitlab.com/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab\n  ogSiteName: https://about.gitlab.com\n  ogType: article\n  canonicalUrls: >-\n    https://about.gitlab.com/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab\ncontent:\n  title: 'Automatisierung der Migration von Container-Images von Amazon ECR zu GitLab'\n  description: >-\n    Wenn Plattformteams ihre CI/CD zu GitLab verschieben, sollte die Migration\n    von Container-Images kein Engpass sein. Befolge diese\n    Schritt-für-Schritt-Anleitung, um den Pipeline-Migrationsprozess zu\n    automatisieren.\n  authors:\n    - Tim Rizzi\n  heroImage: >-\n    https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663129/Blog/Hero%20Images/blog-image-template-1800x945__28_.png\n  date: '2025-02-13'\n  body: \"„Wir müssen Hunderte von Container-Images von Amazon Elastic Container\n    Registry (ECR) zu GitLab migrieren. Könnt ihr uns helfen?“ Diese Frage\n    taucht immer wieder in Gesprächen mit Platform Engineers auf. Sie\n    modernisierten also ihre DevSecOps-Toolchain mit GitLab, kamen aber beim\n    Verschieben ihrer Container-Images nicht weiter. Während ein einzelner\n    Image-Transfer einfach ist, erscheint das schiere Volumen überwältigend.\n\n\n    Ein Platform Engineer brachte es auf den Punkt: „Ich weiß genau, was zu tun\n    ist – pullen, neu kennzeichnen, pushen. Aber ich habe 200 Microservices mit\n    jeweils mehreren Tags. Ich kann es nicht rechtfertigen, Wochen für diese\n    Migration aufzuwenden, während wichtige Infrastrukturarbeiten anstehen.“\n\n\n    ## Die Herausforderung\n\n\n    Dieses Gespräch führte zu einer Idee. Was wäre, wenn wir den gesamten\n    Prozess automatisieren könnten? Wenn Plattformteams ihre\n    [CI/CD](https://about.gitlab.com/de-de/topics/ci-cd/) zu GitLab verschieben,\n    sollte die Migration von Container-Images kein Engpass sein. Der manuelle\n    Prozess ist einfach, aber repetitiv: Jedes Image pullen, neu kennzeichnen\n    und in die Container-Registry von GitLab pushen. Angesichts dutzender\n    Repositories und mehrerer Tags pro Image, bedeutet dies Tage oder Wochen\n    langwieriger Arbeit.\n\n\n    ## Die Lösung\n\n\n    Wir haben uns daran gemacht, eine GitLab-Pipeline zu erstellen, die all\n    diese schwierigen Aufgaben automatisch erledigt. Das Ziel war einfach: Wir\n    wollten Platform Engineers ein Tool zur Verfügung stellen, das sie in\n    wenigen Minuten einrichten und über Nacht ausführen können, sodass am\n    nächsten Morgen alle ihre Images erfolgreich migriert wurden.\n\n\n    ### Einrichten des Zugriffs\n\n\n    Das Wichtigste zuerst: die Sicherheit. Teams sollen diese Migration mit\n    minimalen AWS-Berechtigungen durchführen können. Hier ist die\n    schreibgeschützte Identitäts- und Zugriffsmanagement (IAM)-Richtlinie dafür:\n\n\n    ```json\n\n    {\n\n    \\    \\\"Version\\\": \\\"2012-10-17\\\",\n\n    \\    \\\"Statement\\\": [\n\n    \\        {\n\n    \\            \\\"Effect\\\": \\\"Allow\\\",\n\n    \\            \\\"Action\\\": [\n\n    \\                \\\"ecr:GetAuthorizationToken\\\",\n\n    \\                \\\"ecr:BatchCheckLayerAvailability\\\",\n\n    \\                \\\"ecr:GetDownloadUrlForLayer\\\",\n\n    \\                \\\"ecr:DescribeRepositories\\\",\n\n    \\                \\\"ecr:ListImages\\\",\n\n    \\                \\\"ecr:DescribeImages\\\",\n\n    \\                \\\"ecr:BatchGetImage\\\"\n\n    \\            ],\n\n    \\            \\\"Resource\\\": \\\"*\\\"\n\n    \\        }\n\n    \\    ]\n\n    }\n\n    ```\n\n\n    ### GitLab-Konfiguration\n\n\n    Nachdem die Sicherheit gewährleistet ist, ist der nächste Schritt die\n    Einrichtung von GitLab. Wir haben uns auf das Wesentliche beschränkt. Du\n    musst diese Variablen in deinen CI/CD-Einstellungen konfigurieren:\n\n\n    ```yaml\n\n    AWS_ACCOUNT_ID: Your AWS account number\n\n    AWS_DEFAULT_REGION: Your ECR region\n\n    AWS_ACCESS_KEY_ID: [Masked]\n\n    AWS_SECRET_ACCESS_KEY: [Masked]\n\n    BULK_MIGRATE: true\n\n    ```\n\n\n    ### Die Migrationspipeline\n\n\n    Jetzt wird es interessant. Wir haben die Pipeline mit Docker-in-Docker\n    erstellt, um alle Image-Vorgänge zuverlässig zu verarbeiten:\n\n\n    ```yaml\n\n    image: docker:20.10\n\n    services:\n\n    \\  - docker:20.10-dind\n\n\n    before_script:\n\n    \\  - apk add --no-cache aws-cli jq\n\n    \\  - aws sts get-caller-identity\n\n    \\  - aws ecr get-login-password | docker login --username AWS\n    --password-stdin\n\n    \\  - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD}\n    ${CI_REGISTRY}\n\n    ```\n\n\n    Die Pipeline hat drei Phasen, die jeweils auf der letzten aufbauen:\n\n\n    1. Entdeckung\n\n\n    Zuerst findet sie alle deine Repositories:\n\n\n    ```bash\n\n    REPOS=$(aws ecr describe-repositories --query\n    'repositories[*].repositoryName' --output text)\n\n    ```\n\n\n    2. Tag-Auflistung\n\n\n    Dann ruft sie für jedes Repository alle Tags ab:\n\n\n    ```bash\n\n    TAGS=$(aws ecr describe-images --repository-name $repo --query\n    'imageDetails[*].imageTags[]' --output text)\n\n    ```\n\n\n    3. Übertragung\n\n\n    Schließlich übernimmt sie die eigentliche Migration:\n\n\n    ```bash\n\n    docker pull\n    ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag}\n\n    docker tag\n    ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag}\n    ${CI_REGISTRY_IMAGE}/${repo}:${tag}\n\n    docker push ${CI_REGISTRY_IMAGE}/${repo}:${tag}\n\n    ```\n\n\n    ## Das Ergebnis\n\n\n    Erinnerst du dich an den Platform Engineer, der nicht wochenlang mit der\n    Migration verbringen wollte? Diese Lösung bietet Folgendes:\n\n\n    - automatisierte Erkennung und Migration aller Repositories und Tags\n\n    - konsistente Image-Benennung zwischen ECR und GitLab\n\n    - Fehlerbehandlung für fehlgeschlagene Übertragungen\n\n    - klare Protokollierung zur Verfolgung des Fortschritts\n\n\n    Anstatt Skripte zu schreiben und die Migration zu überwachen, konnte sich\n    der Plattform Engineer auf wertvollere Arbeit konzentrieren.\n\n\n    ## Verwendung\n\n\n    Die ersten Schritte sind einfach:\n\n\n    1. Kopiere die Datei `.gitlab-ci.yml` in dein Repository.\n\n    2. Konfiguriere die AWS- und GitLab-Variablen.\n\n    3. Setze `BULK_MIGRATE` auf „true“, um die Migration zu starten.\n\n\n    ## Best Practices\n\n\n    Bei der Unterstützung von Teams bei ihren Migrationen haben wir einige Dinge\n    gelernt:\n\n\n    - Der Prozess sollte außerhalb der Stoßzeiten durchgeführt werden, um die\n    Auswirkungen auf dein Team zu minimieren.\n\n    - Die Pipeline-Protokolle sind wichtig – darin findest du Informationen,\n    wenn es ein Problem gibt.\n\n    - Die Elastic Container Registry (ECR) sollte erst deaktiviert werden, wenn\n    du überprüft hast, dass alle Images erfolgreich übertragen wurden.\n\n    - Bei sehr großen Migrationen solltest du eine Ratenbegrenzung in Betracht\n    ziehen, um eine Überlastung deines Netzwerks zu vermeiden.\n\n\n    Wir haben diese Pipeline in unserem öffentlichen GitLab-Repository\n    quelloffen verfügbar gemacht, weil wir der Meinung sind, dass Plattform\n    Engineers Zeit damit verbringen sollten, wertvolle Infrastrukturen\n    aufzubauen, anstatt Container-Images zu kopieren. Passe sie an deine\n    Bedürfnisse an und stelle Fragen zur Implementierung, wenn etwas unklar ist.\n\n\n    > #### Informationen dazu und zu anderen Paketkomponenten findest du in\n    unserer\n    [CI/CD-Katalog-Dokumentation](https://gitlab.com/explore/catalog/components\\\n    /package).\"\n  category: engineering\n  tags:\n    - CI/CD\n    - AWS\n    - tutorial\n    - DevSecOps platform\n    - product\n    - solutions architecture\n  updatedDate: '2025-04-10'\nconfig:\n  slug: automating-container-image-migration-from-amazon-ecr-to-gitlab\n  featured: true\n  template: BlogPost\n",{"title":5,"description":17,"ogTitle":5,"ogDescription":17,"noIndex":35,"ogImage":19,"ogUrl":36,"ogSiteName":37,"ogType":38,"canonicalUrls":36},false,"https://about.gitlab.com/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab","https://about.gitlab.com","article","de-de/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab",[41,42,24,43,26,44],"cicd","aws","devsecops-platform","solutions-architecture",[22,23,24,25,26,27],"Kw7ufMFvbh6cizs3VcTYPAZoHvuYHQXEnTAy_CpAQDk",{"data":48},{"logo":49,"freeTrial":54,"sales":59,"login":64,"items":69,"search":378,"minimal":412,"duo":430,"switchNav":439,"pricingDeployment":450},{"config":50},{"href":51,"dataGaName":52,"dataGaLocation":53},"/de-de/","gitlab logo","header",{"text":55,"config":56},"Kostenlose Testversion anfordern",{"href":57,"dataGaName":58,"dataGaLocation":53},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de&glm_content=default-saas-trial/","free trial",{"text":60,"config":61},"Vertrieb kontaktieren",{"href":62,"dataGaName":63,"dataGaLocation":53},"/de-de/sales/","sales",{"text":65,"config":66},"Anmelden",{"href":67,"dataGaName":68,"dataGaLocation":53},"https://gitlab.com/users/sign_in/","sign in",[70,97,193,198,299,359],{"text":71,"config":72,"cards":74},"Plattform",{"dataNavLevelOne":73},"platform",[75,81,89],{"title":71,"description":76,"link":77},"Die intelligente Orchestrierungsplattform für DevSecOps",{"text":78,"config":79},"Die Plattform erkunden",{"href":80,"dataGaName":73,"dataGaLocation":53},"/de-de/platform/",{"title":82,"description":83,"link":84},"GitLab Duo Agent Platform","Agentische KI für den gesamten Software-Lebenszyklus",{"text":85,"config":86},"Lerne GitLab Duo kennen",{"href":87,"dataGaName":88,"dataGaLocation":53},"/de-de/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":90,"description":91,"link":92},"Warum GitLab?","Erfahre, warum sich Unternehmen für GitLab entscheiden",{"text":93,"config":94},"Mehr erfahren",{"href":95,"dataGaName":96,"dataGaLocation":53},"/de-de/why-gitlab/","why gitlab",{"text":98,"left":14,"config":99,"link":101,"lists":105,"footer":175},"Produkt",{"dataNavLevelOne":100},"solutions",{"text":102,"config":103},"Alle Lösungen anzeigen",{"href":104,"dataGaName":100,"dataGaLocation":53},"/de-de/solutions/",[106,130,153],{"title":107,"description":108,"link":109,"items":114},"Automatisierung","CI/CD und Automatisierung zur Beschleunigung der Bereitstellung",{"config":110},{"icon":111,"href":112,"dataGaName":113,"dataGaLocation":53},"AutomatedCodeAlt","/de-de/solutions/delivery-automation/","automated software delivery",[115,118,121,126],{"text":22,"config":116},{"href":117,"dataGaLocation":53,"dataGaName":22},"/de-de/solutions/continuous-integration/",{"text":82,"config":119},{"href":87,"dataGaLocation":53,"dataGaName":120},"gitlab duo agent platform - product menu",{"text":122,"config":123},"Quellcodeverwaltung",{"href":124,"dataGaLocation":53,"dataGaName":125},"/de-de/solutions/source-code-management/","Source Code Management",{"text":127,"config":128},"Automatische Softwarebereitstellung",{"href":112,"dataGaLocation":53,"dataGaName":129},"Automated software delivery",{"title":131,"description":132,"link":133,"items":138},"Sicherheit","Entwickle Code schneller ohne Abstriche bei der Sicherheit",{"config":134},{"href":135,"dataGaName":136,"dataGaLocation":53,"icon":137},"/de-de/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[139,143,148],{"text":140,"config":141},"Anwendungssicherheitstests",{"href":135,"dataGaName":142,"dataGaLocation":53},"Application security testing",{"text":144,"config":145},"Schutz der Software-Lieferkette",{"href":146,"dataGaLocation":53,"dataGaName":147},"/de-de/solutions/supply-chain/","Software supply chain security",{"text":149,"config":150},"Software-Compliance",{"href":151,"dataGaName":152,"dataGaLocation":53},"/de-de/solutions/software-compliance/","software compliance",{"title":154,"link":155,"items":160},"Auswertung",{"config":156},{"icon":157,"href":158,"dataGaName":159,"dataGaLocation":53},"DigitalTransformation","/de-de/solutions/visibility-measurement/","visibility and measurement",[161,165,170],{"text":162,"config":163},"Sichtbarkeit und Auswertung",{"href":158,"dataGaLocation":53,"dataGaName":164},"Visibility and Measurement",{"text":166,"config":167},"Wertstrommanagement",{"href":168,"dataGaLocation":53,"dataGaName":169},"/de-de/solutions/value-stream-management/","Value Stream Management",{"text":171,"config":172},"Analysen und Einblicke",{"href":173,"dataGaLocation":53,"dataGaName":174},"/de-de/solutions/analytics-and-insights/","Analytics and insights",{"title":176,"items":177},"GitLab für",[178,183,188],{"text":179,"config":180},"Enterprise",{"href":181,"dataGaLocation":53,"dataGaName":182},"/de-de/enterprise/","enterprise",{"text":184,"config":185},"Kleinunternehmen",{"href":186,"dataGaLocation":53,"dataGaName":187},"/de-de/small-business/","small business",{"text":189,"config":190},"Öffentlicher Sektor",{"href":191,"dataGaLocation":53,"dataGaName":192},"/de-de/solutions/public-sector/","public sector",{"text":194,"config":195},"Preise",{"href":196,"dataGaName":197,"dataGaLocation":53,"dataNavLevelOne":197},"/de-de/pricing/","pricing",{"text":199,"config":200,"link":202,"lists":206,"feature":286},"Ressourcen",{"dataNavLevelOne":201},"resources",{"text":203,"config":204},"Alle Ressourcen anzeigen",{"href":205,"dataGaName":201,"dataGaLocation":53},"/de-de/resources/",[207,240,258],{"title":208,"items":209},"Erste Schritte",[210,215,220,225,230,235],{"text":211,"config":212},"Installieren",{"href":213,"dataGaName":214,"dataGaLocation":53},"/de-de/install/","install",{"text":216,"config":217},"Kurzanleitungen",{"href":218,"dataGaName":219,"dataGaLocation":53},"/de-de/get-started/","quick setup checklists",{"text":221,"config":222},"Lernen",{"href":223,"dataGaLocation":53,"dataGaName":224},"https://university.gitlab.com/","learn",{"text":226,"config":227},"Produktdokumentation",{"href":228,"dataGaName":229,"dataGaLocation":53},"https://docs.gitlab.com/","product documentation",{"text":231,"config":232},"Best-Practice-Videos",{"href":233,"dataGaName":234,"dataGaLocation":53},"/de-de/getting-started-videos/","best practice videos",{"text":236,"config":237},"Integrationen",{"href":238,"dataGaName":239,"dataGaLocation":53},"/de-de/integrations/","integrations",{"title":241,"items":242},"Entdecken",[243,248,253],{"text":244,"config":245},"Kundenerfolge",{"href":246,"dataGaName":247,"dataGaLocation":53},"/de-de/customers/","customer success stories",{"text":249,"config":250},"Blog",{"href":251,"dataGaName":252,"dataGaLocation":53},"/de-de/blog/","blog",{"text":254,"config":255},"Remote",{"href":256,"dataGaName":257,"dataGaLocation":53},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":259,"items":260},"Vernetzen",[261,266,271,276,281],{"text":262,"config":263},"GitLab Services",{"href":264,"dataGaName":265,"dataGaLocation":53},"/de-de/services/","services",{"text":267,"config":268},"Community",{"href":269,"dataGaName":270,"dataGaLocation":53},"/community/","community",{"text":272,"config":273},"Forum",{"href":274,"dataGaName":275,"dataGaLocation":53},"https://forum.gitlab.com/","forum",{"text":277,"config":278},"Veranstaltungen",{"href":279,"dataGaName":280,"dataGaLocation":53},"/events/","events",{"text":282,"config":283},"Partner",{"href":284,"dataGaName":285,"dataGaLocation":53},"/de-de/partners/","partners",{"background":287,"textColor":288,"text":289,"image":290,"link":294},"#2f2a6b","#fff","Perspektiven für die Softwareentwicklung der Zukunft",{"altText":291,"config":292},"The Source Promo-Karte",{"src":293},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":295,"config":296},"Aktuelles",{"href":297,"dataGaName":298,"dataGaLocation":53},"/de-de/the-source/","the source",{"text":300,"config":301,"lists":303},"Unternehmen",{"dataNavLevelOne":302},"company",[304],{"items":305},[306,311,317,319,324,329,334,339,344,349,354],{"text":307,"config":308},"Über",{"href":309,"dataGaName":310,"dataGaLocation":53},"/de-de/company/","about",{"text":312,"config":313,"footerGa":316},"Karriere",{"href":314,"dataGaName":315,"dataGaLocation":53},"/jobs/","jobs",{"dataGaName":315},{"text":277,"config":318},{"href":279,"dataGaName":280,"dataGaLocation":53},{"text":320,"config":321},"Geschäftsführung",{"href":322,"dataGaName":323,"dataGaLocation":53},"/company/team/e-group/","leadership",{"text":325,"config":326},"Team",{"href":327,"dataGaName":328,"dataGaLocation":53},"/company/team/","team",{"text":330,"config":331},"Handbuch",{"href":332,"dataGaName":333,"dataGaLocation":53},"https://handbook.gitlab.com/","handbook",{"text":335,"config":336},"Investor Relations",{"href":337,"dataGaName":338,"dataGaLocation":53},"https://ir.gitlab.com/","investor relations",{"text":340,"config":341},"Trust Center",{"href":342,"dataGaName":343,"dataGaLocation":53},"/de-de/security/","trust center",{"text":345,"config":346},"AI Transparency Center",{"href":347,"dataGaName":348,"dataGaLocation":53},"/de-de/ai-transparency-center/","ai transparency center",{"text":350,"config":351},"Newsletter",{"href":352,"dataGaName":353,"dataGaLocation":53},"/company/contact/#contact-forms","newsletter",{"text":355,"config":356},"Presse",{"href":357,"dataGaName":358,"dataGaLocation":53},"/press/","press",{"text":360,"config":361,"lists":362},"Kontakt",{"dataNavLevelOne":302},[363],{"items":364},[365,368,373],{"text":60,"config":366},{"href":62,"dataGaName":367,"dataGaLocation":53},"talk to sales",{"text":369,"config":370},"Support-Portal",{"href":371,"dataGaName":372,"dataGaLocation":53},"https://support.gitlab.com","support portal",{"text":374,"config":375},"Kundenportal",{"href":376,"dataGaName":377,"dataGaLocation":53},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":379,"login":380,"suggestions":387},"Schließen",{"text":381,"link":382},"Um Repositorys und Projekte zu durchsuchen, melde dich an bei",{"text":383,"config":384},"gitlab.com",{"href":67,"dataGaName":385,"dataGaLocation":386},"search login","search",{"text":388,"default":389},"Vorschläge",[390,392,397,399,404,409],{"text":82,"config":391},{"href":87,"dataGaName":82,"dataGaLocation":386},{"text":393,"config":394},"Codevorschläge (KI)",{"href":395,"dataGaName":396,"dataGaLocation":386},"/de-de/solutions/code-suggestions/","Code Suggestions (AI)",{"text":22,"config":398},{"href":117,"dataGaName":22,"dataGaLocation":386},{"text":400,"config":401},"GitLab auf AWS",{"href":402,"dataGaName":403,"dataGaLocation":386},"/de-de/partners/technology-partners/aws/","GitLab on AWS",{"text":405,"config":406},"GitLab auf Google Cloud",{"href":407,"dataGaName":408,"dataGaLocation":386},"/de-de/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":90,"config":410},{"href":95,"dataGaName":411,"dataGaLocation":386},"Why GitLab?",{"freeTrial":413,"mobileIcon":418,"desktopIcon":423,"secondaryButton":426},{"text":414,"config":415},"Kostenlos testen",{"href":416,"dataGaName":58,"dataGaLocation":417},"https://gitlab.com/-/trials/new/","nav",{"altText":419,"config":420},"GitLab-Symbol",{"src":421,"dataGaName":422,"dataGaLocation":417},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":419,"config":424},{"src":425,"dataGaName":422,"dataGaLocation":417},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":208,"config":427},{"href":428,"dataGaName":429,"dataGaLocation":417},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de/get-started/","get started",{"freeTrial":431,"mobileIcon":435,"desktopIcon":437},{"text":432,"config":433},"Mehr über GitLab Duo erfahren",{"href":87,"dataGaName":434,"dataGaLocation":417},"gitlab duo",{"altText":419,"config":436},{"src":421,"dataGaName":422,"dataGaLocation":417},{"altText":419,"config":438},{"src":425,"dataGaName":422,"dataGaLocation":417},{"button":440,"mobileIcon":445,"desktopIcon":447},{"text":441,"config":442},"/Option",{"href":443,"dataGaName":444,"dataGaLocation":417},"#contact","switch",{"altText":419,"config":446},{"src":421,"dataGaName":422,"dataGaLocation":417},{"altText":419,"config":448},{"src":449,"dataGaName":422,"dataGaLocation":417},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":451,"mobileIcon":456,"desktopIcon":458},{"text":452,"config":453},"Zurück zur Preisübersicht",{"href":196,"dataGaName":454,"dataGaLocation":417,"icon":455},"back to pricing","GoBack",{"altText":419,"config":457},{"src":421,"dataGaName":422,"dataGaLocation":417},{"altText":419,"config":459},{"src":425,"dataGaName":422,"dataGaLocation":417},{"title":461,"button":462,"config":467},"Sieh dir an, wie agentische KI die Softwarebereitstellung transformiert",{"text":463,"config":464},"GitLab Transcend jetzt ansehen",{"href":465,"dataGaName":466,"dataGaLocation":53},"/de-de/events/transcend/virtual/","transcend event",{"layout":468,"icon":469,"disabled":14},"release","AiStar",{"data":471},{"text":472,"source":473,"edit":479,"contribute":484,"config":489,"items":494,"minimal":696},"Git ist eine Marke von Software Freedom Conservancy und unsere Verwendung von „GitLab“ erfolgt unter Lizenz.",{"text":474,"config":475},"Quelltext der Seite anzeigen",{"href":476,"dataGaName":477,"dataGaLocation":478},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":480,"config":481},"Diese Seite bearbeiten",{"href":482,"dataGaName":483,"dataGaLocation":478},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":485,"config":486},"Beteilige dich",{"href":487,"dataGaName":488,"dataGaLocation":478},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":490,"facebook":491,"youtube":492,"linkedin":493},"https://x.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[495,540,592,634,661],{"title":194,"links":496,"subMenu":511},[497,501,506],{"text":498,"config":499},"Tarife anzeigen",{"href":196,"dataGaName":500,"dataGaLocation":478},"view plans",{"text":502,"config":503},"Vorteile von Premium",{"href":504,"dataGaName":505,"dataGaLocation":478},"/de-de/pricing/premium/","why premium",{"text":507,"config":508},"Vorteile von Ultimate",{"href":509,"dataGaName":510,"dataGaLocation":478},"/de-de/pricing/ultimate/","why ultimate",[512],{"title":360,"links":513},[514,516,518,520,525,530,535],{"text":60,"config":515},{"href":62,"dataGaName":63,"dataGaLocation":478},{"text":369,"config":517},{"href":371,"dataGaName":372,"dataGaLocation":478},{"text":374,"config":519},{"href":376,"dataGaName":377,"dataGaLocation":478},{"text":521,"config":522},"Status",{"href":523,"dataGaName":524,"dataGaLocation":478},"https://status.gitlab.com/","status",{"text":526,"config":527},"Nutzungsbedingungen",{"href":528,"dataGaName":529,"dataGaLocation":478},"/terms/","terms of use",{"text":531,"config":532},"Datenschutzerklärung",{"href":533,"dataGaName":534,"dataGaLocation":478},"/de-de/privacy/","privacy statement",{"text":536,"config":537},"Cookie-Einstellungen",{"dataGaName":538,"dataGaLocation":478,"id":539,"isOneTrustButton":14},"cookie preferences","ot-sdk-btn",{"title":98,"links":541,"subMenu":550},[542,546],{"text":543,"config":544},"DevSecOps-Plattform",{"href":80,"dataGaName":545,"dataGaLocation":478},"devsecops platform",{"text":547,"config":548},"KI-unterstützte Entwicklung",{"href":87,"dataGaName":549,"dataGaLocation":478},"ai-assisted development",[551],{"title":552,"links":553},"Themen",[554,557,562,567,572,577,582,587],{"text":22,"config":555},{"href":556,"dataGaName":41,"dataGaLocation":478},"/de-de/topics/ci-cd/",{"text":558,"config":559},"GitOps",{"href":560,"dataGaName":561,"dataGaLocation":478},"/de-de/topics/gitops/","gitops",{"text":563,"config":564},"DevOps",{"href":565,"dataGaName":566,"dataGaLocation":478},"/de-de/topics/devops/","devops",{"text":568,"config":569},"Versionskontrolle",{"href":570,"dataGaName":571,"dataGaLocation":478},"/de-de/topics/version-control/","version control",{"text":573,"config":574},"DevSecOps",{"href":575,"dataGaName":576,"dataGaLocation":478},"/de-de/topics/devsecops/","devsecops",{"text":578,"config":579},"Cloud-nativ",{"href":580,"dataGaName":581,"dataGaLocation":478},"/de-de/topics/cloud-native/","cloud native",{"text":583,"config":584},"KI für das Programmieren",{"href":585,"dataGaName":586,"dataGaLocation":478},"/de-de/topics/devops/ai-for-coding/","ai for coding",{"text":588,"config":589},"Agentische KI",{"href":590,"dataGaName":591,"dataGaLocation":478},"/de-de/topics/agentic-ai/","agentic ai",{"title":593,"links":594},"Lösungen",[595,598,600,605,609,612,615,618,620,622,624,629],{"text":140,"config":596},{"href":135,"dataGaName":597,"dataGaLocation":478},"Application Security Testing",{"text":127,"config":599},{"href":112,"dataGaName":113,"dataGaLocation":478},{"text":601,"config":602},"Agile Entwicklung",{"href":603,"dataGaName":604,"dataGaLocation":478},"/de-de/solutions/agile-delivery/","agile delivery",{"text":606,"config":607},"SCM",{"href":124,"dataGaName":608,"dataGaLocation":478},"source code management",{"text":22,"config":610},{"href":117,"dataGaName":611,"dataGaLocation":478},"continuous integration & delivery",{"text":166,"config":613},{"href":168,"dataGaName":614,"dataGaLocation":478},"value stream management",{"text":558,"config":616},{"href":617,"dataGaName":561,"dataGaLocation":478},"/de-de/solutions/gitops/",{"text":179,"config":619},{"href":181,"dataGaName":182,"dataGaLocation":478},{"text":184,"config":621},{"href":186,"dataGaName":187,"dataGaLocation":478},{"text":189,"config":623},{"href":191,"dataGaName":192,"dataGaLocation":478},{"text":625,"config":626},"Bildungswesen",{"href":627,"dataGaName":628,"dataGaLocation":478},"/de-de/solutions/education/","education",{"text":630,"config":631},"Finanzdienstleistungen",{"href":632,"dataGaName":633,"dataGaLocation":478},"/de-de/solutions/finance/","financial services",{"title":199,"links":635},[636,638,640,642,645,647,649,651,653,655,657,659],{"text":211,"config":637},{"href":213,"dataGaName":214,"dataGaLocation":478},{"text":216,"config":639},{"href":218,"dataGaName":219,"dataGaLocation":478},{"text":221,"config":641},{"href":223,"dataGaName":224,"dataGaLocation":478},{"text":226,"config":643},{"href":228,"dataGaName":644,"dataGaLocation":478},"docs",{"text":249,"config":646},{"href":251,"dataGaName":252,"dataGaLocation":478},{"text":244,"config":648},{"href":246,"dataGaName":247,"dataGaLocation":478},{"text":254,"config":650},{"href":256,"dataGaName":257,"dataGaLocation":478},{"text":262,"config":652},{"href":264,"dataGaName":265,"dataGaLocation":478},{"text":267,"config":654},{"href":269,"dataGaName":270,"dataGaLocation":478},{"text":272,"config":656},{"href":274,"dataGaName":275,"dataGaLocation":478},{"text":277,"config":658},{"href":279,"dataGaName":280,"dataGaLocation":478},{"text":282,"config":660},{"href":284,"dataGaName":285,"dataGaLocation":478},{"title":300,"links":662},[663,665,667,669,671,673,675,680,685,687,689,691],{"text":307,"config":664},{"href":309,"dataGaName":302,"dataGaLocation":478},{"text":312,"config":666},{"href":314,"dataGaName":315,"dataGaLocation":478},{"text":320,"config":668},{"href":322,"dataGaName":323,"dataGaLocation":478},{"text":325,"config":670},{"href":327,"dataGaName":328,"dataGaLocation":478},{"text":330,"config":672},{"href":332,"dataGaName":333,"dataGaLocation":478},{"text":335,"config":674},{"href":337,"dataGaName":338,"dataGaLocation":478},{"text":676,"config":677},"Nachhaltigkeit",{"href":678,"dataGaName":679,"dataGaLocation":478},"/sustainability/","Sustainability",{"text":681,"config":682},"Vielfalt, Inklusion und Zugehörigkeit",{"href":683,"dataGaName":684,"dataGaLocation":478},"/de-de/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":340,"config":686},{"href":342,"dataGaName":343,"dataGaLocation":478},{"text":350,"config":688},{"href":352,"dataGaName":353,"dataGaLocation":478},{"text":355,"config":690},{"href":357,"dataGaName":358,"dataGaLocation":478},{"text":692,"config":693},"Transparenzerklärung zu moderner Sklaverei",{"href":694,"dataGaName":695,"dataGaLocation":478},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":697},[698,700,703],{"text":526,"config":699},{"href":528,"dataGaName":529,"dataGaLocation":478},{"text":701,"config":702},"Cookies",{"dataGaName":538,"dataGaLocation":478,"id":539,"isOneTrustButton":14},{"text":531,"config":704},{"href":533,"dataGaName":534,"dataGaLocation":478},[706],{"id":707,"title":9,"body":30,"config":708,"content":710,"description":30,"extension":29,"meta":714,"navigation":14,"path":715,"seo":716,"stem":717,"__hash__":718},"blogAuthors/en-us/blog/authors/tim-rizzi.yml",{"template":709},"BlogAuthor",{"name":9,"config":711},{"headshot":712,"ctfId":713},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749661866/Blog/Author%20Headshots/trizzi-headshot.jpg","trizzi",{},"/en-us/blog/authors/tim-rizzi",{},"en-us/blog/authors/tim-rizzi","ADPqrpcnKveFJS0m_zFV0VLtb_h_txu59QVgz_YwKMc",[720,732,746],{"content":721,"config":730},{"title":722,"description":723,"authors":724,"heroImage":726,"date":727,"body":728,"category":11,"tags":729},"CI/CD-Observability im Unternehmensmaßstab aufbauen","Dieser Praxisleitfaden zu GitLab Pipeline Analytics hilft Self-Managed-Nutzern, mit Prometheus und Grafana operationale Insights zu gewinnen.",[725],"Paul Meresanu","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28","CI/CD-Optimierung beginnt mit Transparenz. Eine erfolgreiche DevOps-Plattform\nim Unternehmensmaßstab umfasst das Verständnis von Pipeline-Performance,\nJob-Ausführungsmustern und quantifizierbaren operationalen Insights – insbesondere\nfür Unternehmen, die GitLab Self-Managed betreiben.\n\nUm GitLab-Kund(inn)en dabei zu helfen, den vollen Nutzen ihrer Plattform\nauszuschöpfen, haben wir die GitLab CI/CD Observability-Lösung als Teil unseres\nPlatform Excellence-Programms entwickelt. Sie verwandelt rohe Pipeline-Metriken\nin handlungsrelevante operationale Erkenntnisse.\n\nEin führendes Finanzdienstleistungsunternehmen hat gemeinsam mit GitLabs Customer\nSuccess Architect Transparenz über seine GitLab Self-Managed-Deployments\ngewonnen. Gemeinsam haben wir eine containerisierte Observability-Lösung\nimplementiert, die den Open-Source-gitlab-ci-pipelines-exporter mit\nunternehmensgerechter Prometheus- und Grafana-Infrastruktur kombiniert.\n\nIn diesem Artikel werden die Herausforderungen beim Pipeline-Management im\nUnternehmensmaßstab erläutert – und wie GitLab CI/CD Observability diese mit\neiner praxisnahen End-to-End-Implementierung adressiert.\n\n\n## Die Herausforderung: CI/CD-Performance messen\n\nVor der Implementierung einer Observability-Lösung sollte die\nMessdimension klar definiert sein:\n\n* **Welche Metriken sind relevant?** Pipeline-Dauer, Job-Erfolgsraten,\n  Queue-Zeiten, Runner-Auslastung\n* **Wer braucht Transparenz?** Entwickler(innen), DevOps-Engineers,\n  Plattformteams, Führungsebene\n* **Welche Entscheidungen werden damit getroffen?** Infrastrukturinvestitionen,\n  Engpass-Behebung, Kapazitätsplanung\n\n\n## Lösungsarchitektur: Ein vollständiges Dashboard-Set für Observability\n\nNach dem Deployment stellt der Observability-Stack ein Set von\nGrafana-Dashboards bereit, das Echtzeit- und historische Transparenz über die\nCI/CD-Plattform bietet. Ein typisches Deployment umfasst:\n\n* **Pipeline Overview Dashboard:** Eine übergeordnete Ansicht mit Gesamtzahl\n  der Pipeline-Läufe, Erfolgs-/Fehlerquoten über die Zeit (als gestapelte\n  Balken- oder Zeitreihencharts) und Trends bei der durchschnittlichen\n  Pipeline-Dauer. Panels verwenden farbcodierte Statusindikatoren (Grün für\n  Erfolg, Rot für Fehler, Gelb für Abbruch), damit Plattformteams\n  Verschlechterungen auf einen Blick erkennen.\n* **Job Performance Dashboard:** Drill-down-Panels mit Verteilungen der\n  einzelnen Job-Dauern (Histogramm), den 10 langsamsten Jobs nach\n  Durchschnittsdauer und Job-Fehler-Heatmaps nach Projekt und Stage. Hier\n  identifizieren Teams konkrete Engpass-Jobs, die sich zu optimieren lohnen.\n* **Runner & Infrastructure Dashboard:** Kombiniert Node-Exporter-Host-Metriken\n  (CPU, Arbeitsspeicher, Disk) mit Pipeline-Queue-Zeit-Daten, um\n  Infrastruktur-Sättigung mit Pipeline-Wartezeiten zu korrelieren. Nützlich\n  für Kapazitätsplanungsentscheidungen wie die Skalierung von Runner-Pools oder\n  das Upgrade von Instanzgrößen.\n* **Deployment Frequency Dashboard:** Verfolgt Deployment-Anzahl und\n  -Dauer über die Zeit pro Umgebung, abgestimmt auf DORA-Metriken. Hilft\n  der Engineering-Führungsebene, Lieferdurchsatz und Environment-Drift\n  (Commits hinter main) zu bewerten.\n\nJedes Dashboard wird automatisch über Grafanas dateibasiertes Provisioning\nbereitgestellt, sodass es konsistent über alle Umgebungen hinweg deployed wird.\nDie Dashboards lassen sich über Grafana-Variablen weiter anpassen, um nach\nProjekt, Ref/Branch oder Zeitraum zu filtern.\n\n![Lösungsarchitektur](https://res.cloudinary.com/about-gitlab-com/image/upload/v1777382608/Blog/Imported/blog-building-ci-cd-observability-stack-for-gitlab-self-managed/image1.png)\n\nDie Lösung benötigt zwei Exporter:\n\n* **Pipeline Exporter:** Erfasst CI/CD-Metriken über die GitLab API\n  (Pipeline-Dauer, Job-Status, Deployments)\n* **Node Exporter:** Erfasst Host-Metriken (CPU, Arbeitsspeicher, Disk)\n  für die Infrastruktur-Korrelation\n\n**Voraussetzungen:**\n\n* GitLab Self-Managed Version 18.1+\n* **Container-Orchestrierungsplattform:** Ein Kubernetes-Cluster (empfohlen\n  für Unternehmens-Deployments) oder eine Container-Runtime wie Docker/Podman\n  für kleinere Umgebungen oder Proof-of-Concept-Deployments. Die primäre\n  Deployment-Anleitung unten zielt auf Kubernetes; eine Docker-Compose-Alternative\n  ist im Anhang für lokales Testen und Evaluation verfügbar\n* GitLab Personal Access Token (Scope **read_api**)\n\nDie vollständige Implementierungsanleitung mit allen Kubernetes-Manifesten\nfolgt direkt im Anschluss.\n\n\n## Kubernetes-Deployment (empfohlen)\n\nFür Unternehmensumgebungen wird jede Komponente als separates Deployment in\neinem dedizierten Namespace deployed. Dieser Ansatz integriert sich in\nbestehende Cluster-Infrastruktur, Secrets-Management und Network-Policies.\n\n### 1. Namespace und Secret erstellen\n\n```bash\nkubectl create namespace gitlab-observability\n\n# GitLab-Token-Secret erstellen (siehe Abschnitt Secrets-Management\n# für unternehmensgerechte Ansätze mit externen Secret-Operatoren)\nkubectl create secret generic gitlab-token \\\n  --from-literal=token=glpat-xxxxxxxxxxxx \\\n  -n gitlab-observability\n```\n\n### 2. Pipeline Exporter deployen\n\n```yaml\n# exporter-deployment.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: gitlab-ci-pipelines-exporter\n  namespace: gitlab-observability\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: gitlab-ci-pipelines-exporter\n  template:\n    metadata:\n      labels:\n        app: gitlab-ci-pipelines-exporter\n    spec:\n      containers:\n        - name: exporter\n          image: mvisonneau/gitlab-ci-pipelines-exporter:latest\n          ports:\n            - containerPort: 8080\n          env:\n            - name: GCPE_GITLAB_TOKEN\n              valueFrom:\n                secretKeyRef:\n                  name: gitlab-token\n                  key: token\n            - name: GCPE_CONFIG\n              value: /etc/gcpe/config.yml\n          volumeMounts:\n            - name: config\n              mountPath: /etc/gcpe\n      volumes:\n        - name: config\n          configMap:\n            name: gcpe-config\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: gitlab-ci-pipelines-exporter\n  namespace: gitlab-observability\nspec:\n  selector:\n    app: gitlab-ci-pipelines-exporter\n  ports:\n    - port: 8080\n      targetPort: 8080\n```\n\n### 3. Node Exporter deployen (DaemonSet)\n\n```yaml\n# node-exporter-daemonset.yaml\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: node-exporter\n  namespace: gitlab-observability\nspec:\n  selector:\n    matchLabels:\n      app: node-exporter\n  template:\n    metadata:\n      labels:\n        app: node-exporter\n    spec:\n      containers:\n        - name: node-exporter\n          image: prom/node-exporter:latest\n          ports:\n            - containerPort: 9100\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: node-exporter\n  namespace: gitlab-observability\nspec:\n  selector:\n    app: node-exporter\n  ports:\n    - port: 9100\n      targetPort: 9100\n```\n\n### 4. Prometheus deployen\n\n```yaml\n# prometheus-deployment.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: prometheus\n  namespace: gitlab-observability\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: prometheus\n  template:\n    metadata:\n      labels:\n        app: prometheus\n    spec:\n      containers:\n        - name: prometheus\n          image: prom/prometheus:latest\n          ports:\n            - containerPort: 9090\n          volumeMounts:\n            - name: config\n              mountPath: /etc/prometheus\n      volumes:\n        - name: config\n          configMap:\n            name: prometheus-config\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: prometheus\n  namespace: gitlab-observability\nspec:\n  selector:\n    app: prometheus\n  ports:\n    - port: 9090\n      targetPort: 9090\n```\n\n### 5. Grafana deployen\n\nDas folgende Grafana-Deployment startet mit deaktivierter Authentifizierung\n(`GF_AUTH_ANONYMOUS_ENABLED: true`) für den einfachen Einstieg.\n\n**Diese Einstellung erlaubt jedem mit Netzwerkzugang, alle Dashboards ohne\nAnmeldung einzusehen.** Für Produktions-Deployments diese Variable entfernen\noder auf false setzen und einen geeigneten Authentifizierungs-Provider\n(LDAP, SAML/SSO oder OAuth) konfigurieren, um den Zugriff auf autorisierte\nNutzende zu beschränken.\n\n```yaml\n# grafana-deployment.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grafana\n  namespace: gitlab-observability\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: grafana\n  template:\n    metadata:\n      labels:\n        app: grafana\n    spec:\n      containers:\n        - name: grafana\n          image: grafana/grafana:10.0.0\n          ports:\n            - containerPort: 3000\n          env:\n            # Für Produktion ENTFERNEN oder auf 'false' setzen.\n            # Bei 'true' können alle Nutzenden mit Netzwerkzugang\n            # Dashboards ohne Authentifizierung einsehen.\n            - name: GF_AUTH_ANONYMOUS_ENABLED\n              value: 'true'\n          volumeMounts:\n            - name: dashboards-provider\n              mountPath: /etc/grafana/provisioning/dashboards\n            - name: datasources\n              mountPath: /etc/grafana/provisioning/datasources\n            - name: dashboards\n              mountPath: /var/lib/grafana/dashboards\n      volumes:\n        - name: dashboards-provider\n          configMap:\n            name: grafana-dashboards-provider\n        - name: datasources\n          configMap:\n            name: grafana-datasources\n        - name: dashboards\n          configMap:\n            name: grafana-dashboards\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: grafana\n  namespace: gitlab-observability\nspec:\n  selector:\n    app: grafana\n  ports:\n    - port: 3000\n      targetPort: 3000\n```\n\n### 6. Network Policy setzen\n\nDen Inter-Pod-Traffic auf die erforderlichen Kommunikationspfade beschränken:\n\n```yaml\n# network-policy.yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: observability-policy\n  namespace: gitlab-observability\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n  ingress:\n    # Prometheus scrapt Exporter und Node-Exporter\n    - from:\n        - podSelector:\n            matchLabels:\n              app: prometheus\n      ports:\n        - port: 8080\n        - port: 9100\n    # Grafana fragt Prometheus ab\n    - from:\n        - podSelector:\n            matchLabels:\n              app: grafana\n      ports:\n        - port: 9090\n```\n\n### 7. Validieren\n\n```bash\nkubectl get pods -n gitlab-observability\nkubectl port-forward svc/grafana 3000:3000 -n gitlab-observability\ncurl http://localhost:3000/api/health\n```\n\n\n## Konfigurationsreferenz\n\n### Exporter-Konfiguration\n\n```yaml\n# gitlab-ci-pipelines-exporter.yml (ConfigMap: gcpe-config)\nlog:\n  level: info\ngitlab:\n  url: https://gitlab.your-domain.com\n  maximum_requests_per_second: 10\nproject_defaults:\n  pull:\n    pipeline:\n      jobs:\n        enabled: true\nwildcards:\n  - owner:\n      name: your-group-name\n      kind: group\n    archived: false\n```\n\n### Prometheus-Konfiguration\n\n```yaml\n# prometheus.yml (ConfigMap: prometheus-config)\nglobal:\n  scrape_interval: 15s\nscrape_configs:\n  - job_name: 'gitlab-ci-pipelines-exporter'\n    static_configs:\n      - targets: ['gitlab-ci-pipelines-exporter:8080']\n  - job_name: 'node-exporter'\n    static_configs:\n      - targets: ['node-exporter:9100']\n```\n\n### Grafana-Datenquellen\n\n```yaml\n# datasources.yml (ConfigMap: grafana-datasources)\napiVersion: 1\ndatasources:\n  - name: Prometheus\n    type: prometheus\n    access: proxy\n    url: http://prometheus:9090\n    isDefault: true\n# dashboards.yml (ConfigMap: grafana-dashboards-provider)\napiVersion: 1\nproviders:\n  - name: 'default'\n    folder: 'GitLab CI/CD'\n    type: file\n    options:\n      path: /var/lib/grafana/dashboards\n```\n\n\n## Wichtige Metriken\n\n### Pipeline-Exporter-Metriken\n\n| Metrik | Beschreibung |\n| :---- | :---- |\n| `gitlab_ci_pipeline_duration_seconds` | Pipeline-Ausführungszeit |\n| `gitlab_ci_pipeline_status` | Pipeline-Erfolg/-Fehler nach Projekt |\n| `gitlab_ci_pipeline_job_duration_seconds` | Einzelne Job-Ausführungszeit |\n| `gitlab_ci_pipeline_job_status` | Job-Erfolgs-/-Fehlerstatus |\n| `gitlab_ci_pipeline_job_artifact_size_bytes` | Artifact-Speicherverbrauch |\n| `gitlab_ci_pipeline_coverage` | Code-Coverage-Prozentsatz |\n| `gitlab_ci_environment_deployment_count` | Deployment-Häufigkeit |\n| `gitlab_ci_environment_deployment_duration_seconds` | Deployment-Ausführungszeit |\n| `gitlab_ci_environment_behind_commits_count` | Environment-Drift gegenüber main |\n\n### Node-Exporter-Metriken\n\n| Metrik | Beschreibung |\n| :---- | :---- |\n| `node_cpu_seconds_total` | CPU-Auslastung |\n| `node_memory_MemAvailable_bytes` | Verfügbarer Arbeitsspeicher |\n| `node_filesystem_avail_bytes` | Verfügbarer Festplattenspeicher |\n| `node_load1` | 1-Minuten-Lastdurchschnitt |\n\n\n## Fehlerbehebung\n\n### Grafana-Plugin-Installation in Air-gapped-Umgebungen\n\nFür Offline-Umgebungen Plugins manuell installieren. Beispiel für Kubernetes:\n\n```bash\n# Plugin-ZIP in den Grafana-Pod kopieren\nkubectl cp grafana-polystat-panel-2.1.16.zip \\\n  gitlab-observability/grafana-\u003Cpod-id>:/tmp/\n# Plugin entpacken\nkubectl exec -it -n gitlab-observability deploy/grafana -- \\\n  sh -c \"unzip /tmp/grafana-polystat-panel-2.1.16.zip -d /var/lib/grafana/plugins/\"\n# Grafana-Pod neu starten\nkubectl rollout restart deployment/grafana -n gitlab-observability\n# Installation prüfen\nkubectl exec -it -n gitlab-observability deploy/grafana -- \\\n  ls -al /var/lib/grafana/plugins/\n```\n\n\n## Unternehmensaspekte\n\nFür regulierte Branchen gilt:\n\n* **Token-Sicherheit:** GitLab Personal Access Tokens in einem dedizierten\n  Secrets-Manager speichern, nicht hartcodiert in ConfigMaps. Token-Rotation\n  durchsetzen und den Scope auf **read\\_api** beschränken.\n* **Netzwerksegmentierung:** Hinter einem Reverse Proxy mit TLS-Terminierung\n  deployen. In Kubernetes einen Ingress-Controller mit automatisierter\n  Zertifikatsbereitstellung verwenden.\n* **Authentifizierung:** Grafana mit dem Identity Provider der Organisation\n  konfigurieren (SAML, LDAP oder OAuth/OIDC), um rollenbasierte\n  Zugriffskontrolle auf Dashboards durchzusetzen.\n\n\n## Warum GitLab?\n\nGitLabs API-First-Design ermöglicht individuelle Observability-Lösungen, die\nnative Funktionen wie Value Stream Analytics und DORA-Metriken ergänzen. Die\noffene Architektur erlaubt es Unternehmen, bewährte Open-Source-Werkzeuge –\nwie den gitlab-ci-pipelines-exporter – direkt in bestehende\nUnternehmensinfrastruktur zu integrieren, ohne etablierte Workflows zu\nunterbrechen.\n\nMit wachsender Observability-Reife bieten GitLabs eingebaute\nObservability-Funktionen einen natürlichen nächsten Schritt – tiefere,\nintegrierte Transparenz ohne zusätzliche Werkzeuge. Mehr zu den nativen\nPlattformfunktionen unter\n[GitLab Observability](https://docs.gitlab.com/operations/observability/observability/).\n",[22,26,24],{"featured":35,"template":15,"slug":731},"how-to-build-ci-cd-observability-at-scale",{"content":733,"config":744},{"body":734,"title":735,"description":736,"authors":737,"heroImage":739,"date":740,"category":11,"tags":741},"## Abschnitt 1: Das Modell verstehen\n*Für Engineering-Leads und Entscheidungsträger: Konzept, Anwendungsfälle und Architekturprinzipien. Konfigurationsdetails folgen in Abschnitt 2.*\n\nDie meisten CI/CD-Werkzeuge können einen Build ausführen und ein Deployment anstoßen. Der Unterschied zeigt sich erst dann, wenn die Delivery-Anforderungen komplexer werden: ein Monorepo mit einem Dutzend Services, Microservices über mehrere Repositories verteilt, Deployments in Dutzende von Umgebungen gleichzeitig – oder ein Platform-Team, das organisationsweite Standards durchsetzen will, ohne dabei zum Engpass zu werden.\n\nGitLabs Pipeline-Modell wurde für genau diese Komplexität entwickelt. Parent-Child-Pipelines, DAG-Execution, dynamische Pipeline-Generierung, Multi-Project-Trigger, Merge-Request-Pipelines mit Merged-Results-Verarbeitung und CI/CD Components lösen jeweils eine eigene Klasse von Problemen. Da sich diese Bausteine kombinieren lassen, erschließt das vollständige Modell mehr als nur kürzere Pipeline-Laufzeiten.\n\nDieser Artikel beschreibt die fünf Muster, bei denen das Modell seine Stärken deutlich zeigt – jeweils zugeordnet zu einem konkreten Engineering-Szenario. Konfigurationen und Implementierungsdetails folgen in Abschnitt 2.\n\n### 1. Monorepos: Parent-Child-Pipelines und DAG-Execution\n\n**Das Problem:** Ein Monorepo enthält Frontend, Backend und Dokumentation. Jeder Commit löst einen vollständigen Rebuild aller Komponenten aus – auch wenn sich nur eine README-Datei geändert hat.\n\nGitLab kombiniert zwei sich ergänzende Mechanismen: [Parent-Child-Pipelines](https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#parent-child-pipelines) ermöglichen es einer übergeordneten Pipeline, isolierte Child-Pipelines zu starten. [DAG-Execution via `needs`](https://docs.gitlab.com/ci/yaml/#needs) bricht die starre Stage-Reihenfolge auf und startet Jobs, sobald ihre Abhängigkeiten abgeschlossen sind – nicht erst, wenn alle Jobs einer Stage fertig sind.\n\nEine Parent-Pipeline erkennt, welche Teile des Repos sich geändert haben, und löst ausschließlich die betroffenen Child-Pipelines aus. Jeder Service verwaltet seine eigene Pipeline-Konfiguration; Änderungen in einem Service können keine anderen beeinflussen. Damit bleibt die Komplexität beherrschbar, während das Repository und das Team wachsen.\n\nEinen technischen Aspekt gilt es dabei zu kennen: Wenn mehrere Dateien an einen einzelnen `trigger: include:`-Block übergeben werden, fusioniert GitLab sie zu einer einzigen Child-Pipeline-Konfiguration. Jobs aus diesen Dateien teilen denselben Pipeline-Kontext und können sich gegenseitig per `needs:` referenzieren – das ist die Voraussetzung für die DAG-Optimierung. Werden die Dateien stattdessen auf separate Trigger-Jobs aufgeteilt, entsteht jeweils eine isolierte Pipeline, und dateiübergreifende `needs:`-Referenzen funktionieren nicht.\n\nIn großen Monorepos lassen sich Pipeline-Laufzeiten durch DAG-Execution deutlich reduzieren, da Jobs nicht mehr auf unabhängige Arbeitsschritte in derselben Stage warten.\n\n### 2. Microservices: Cross-Repo-Pipelines über mehrere Projekte\n\n**Das Problem:** Frontend und Backend leben in separaten Repositories. Wenn das Frontend-Team eine Änderung ausliefert, ist nicht erkennbar, ob sie die Backend-Integration beeinträchtigt – und umgekehrt.\n\n[Multi-Project-Pipelines](https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#multi-project-pipelines) ermöglichen es, aus einem Projekt heraus eine Pipeline in einem anderen Projekt auszulösen und auf das Ergebnis zu warten. Das auslösende Projekt sieht die verknüpfte Downstream-Pipeline direkt in seiner eigenen Pipeline-Ansicht.\n\nIn der Praxis erstellt die Frontend-Pipeline ein API-Contract-Artifact und veröffentlicht es, bevor die Backend-Pipeline ausgelöst wird. Das Backend ruft dieses Artifact über die [Jobs API](https://docs.gitlab.com/api/jobs/#download-a-single-artifact-file-from-specific-tag-or-branch) ab und validiert es, bevor weitere Schritte erlaubt sind. Wird eine Breaking Change erkannt, schlägt die Backend-Pipeline fehl – und mit ihr die Frontend-Pipeline. Probleme, die bisher erst in der Produktion sichtbar wurden, werden damit im Pipeline-Prozess abgefangen. Die Abhängigkeit zwischen Services wird sichtbar, nachvollziehbar und aktiv verwaltbar.\n\n![Cross-project pipelines](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738762/Blog/Imported/hackathon-fake-blog-post-s/image4_h6mfsb.png \"Cross-project pipelines\") *Cross-project pipelines*\n\n### 3. Multi-Tenant/Matrix-Deployments: Dynamische Child-Pipelines\n\n**Das Problem:** Dieselbe Anwendung wird in 15 Kundenumgebungen, drei Cloud-Regionen oder den Stages Dev/Staging/Prod deployed. Manuelle Anpassungen je Umgebung führen zu Konfigurationsdrift. Eine separate Pipeline pro Umgebung ist von Anfang an nicht wartbar.\n\n[Dynamische Child-Pipelines](https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#dynamic-child-pipelines) generieren die Pipeline-Struktur zur Laufzeit. Ein Job führt ein Skript aus, das eine YAML-Datei erzeugt – und diese YAML-Datei wird zur Pipeline für den nächsten Schritt. Die Pipeline-Struktur selbst wird damit zu Daten.\n\nDas Generierungsskript iteriert über eine `ENVIRONMENTS`-Variable, statt jede Umgebung fest zu kodieren. Eine neue Umgebung lässt sich durch Anpassen der Variable hinzufügen – ohne Änderungen an der Pipeline-Konfiguration selbst. Trigger-Jobs erben mit `extends:` eine gemeinsame Template-Konfiguration, sodass `strategy: depend` einmal definiert und nicht für jeden Trigger-Job wiederholt wird. Ein `when: manual`-Gate für das Produktions-Deployment ist direkt in den Pipeline-Graph integriert.\n\nPlatform-Teams nutzen dieses Muster, um Dutzende von Umgebungen zu verwalten, ohne Pipeline-Logik zu duplizieren.\n\n![Dynamic pipeline](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738765/Blog/Imported/hackathon-fake-blog-post-s/image7_wr0kx2.png \"Dynamic pipeline\")\n\n### 4. MR-First-Delivery: Merge-Request-Pipelines, Merged-Results und Workflow-Routing\n\n**Das Problem:** Die Pipeline läuft bei jedem Push auf jeden Branch. Aufwändige Tests werden auf Feature-Branches ausgeführt, die nie gemergt werden. Gleichzeitig gibt es keine Garantie, dass das Getestete dem entspricht, was nach dem Merge auf `main` tatsächlich landet.\n\nGitLab kombiniert drei ineinandergreifende Mechanismen: [Merge-Request-Pipelines](https://docs.gitlab.com/ci/pipelines/merge_request_pipelines/) laufen ausschließlich dann, wenn ein Merge Request existiert – nicht bei jedem Branch-Push. Allein dadurch entfällt ein erheblicher Anteil unnötiger Compute-Ausführungen. [Merged-Results-Pipelines](https://docs.gitlab.com/ci/pipelines/merged_results_pipelines/) gehen einen Schritt weiter: GitLab erstellt einen temporären Merge-Commit aus dem Branch und dem aktuellen Ziel-Branch und führt die Pipeline dagegen aus. Getestet wird damit das tatsächliche Ergebnis des Merges – nicht der Branch in Isolation. [Workflow-Rules](https://docs.gitlab.com/ci/yaml/workflow/) definieren schließlich, welcher Pipeline-Typ unter welchen Bedingungen ausgeführt wird. Die `$CI_OPEN_MERGE_REQUESTS`-Guard verhindert dabei, dass für einen Branch mit offenem MR doppelte Pipelines ausgelöst werden.\n\nDas Ergebnis ist ein Pipeline-Verhalten, das sich je nach Kontext unterscheidet: Ein Push auf einen Feature-Branch ohne offenen MR führt nur Lint und Unit-Tests aus. Sobald ein MR geöffnet wird, wechseln die Workflow-Rules auf eine MR-Pipeline mit der vollständigen Test-Suite gegen das Merged-Result. Ein Merge auf `main` stellt ein manuelles Produktions-Deployment in die Warteschlange. Der Nightly-Scan läuft einmalig als geplante Pipeline – nicht bei jedem Commit.\n\nMerged-Results-Pipelines fangen dabei die Klasse von Fehlern ab, die erst nach einem Merge sichtbar werden – bevor sie `main` erreichen.\n\n### 5. Governed Pipelines: CI/CD Components\n\n**Das Problem:** Das Platform-Team hat den richtigen Weg für Build, Test und Deploy definiert. Jedes Anwendungsteam pflegt jedoch eine eigene `.gitlab-ci.yml` mit subtilen Abweichungen. Security-Scanning wird übersprungen. Deployment-Standards driften. Audits werden aufwändig.\n\n[CI/CD Components](https://docs.gitlab.com/ci/components/) ermöglichen es Platform-Teams, versionierte, wiederverwendbare Pipeline-Bausteine zu veröffentlichen. Anwendungsteams binden sie mit einer einzigen `include:`-Zeile ein – kein Copy-Paste, kein Drift. Components sind über den [CI/CD Catalog](https://docs.gitlab.com/ci/components/#cicd-catalog) auffindbar, sodass Teams bewährte Bausteine finden und übernehmen können, ohne das Platform-Team direkt einschalten zu müssen.\n\nDrei Zeilen `include:` ersetzen hunderte von duplizierten YAML-Zeilen. Das Platform-Team kann einen Security-Fix in einer neuen Komponentenversion veröffentlichen – Teams steigen auf ihrem eigenen Zeitplan um, oder das Platform-Team fixiert alle auf eine Mindestversion. In beiden Fällen propagiert eine Änderung organisationsweit, statt repo-für-repo angewendet zu werden.\n\nKombiniert mit [Resource Groups](https://docs.gitlab.com/ci/resource_groups/) zur Vermeidung konkurrierender Deployments und [Protected Environments](https://docs.gitlab.com/ci/environments/protected_environments/) für Freigabe-Gates entsteht eine governed Delivery-Plattform, auf der **Compliance der Standard ist, nicht die Ausnahme**. Platform-Teams setzen Vorgaben durch, ohne zum Engpass zu werden.\n\n![Component pipeline (imported jobs)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738776/Blog/Imported/hackathon-fake-blog-post-s/image2_pizuxd.png \"Component pipeline (imported jobs)\")\n\n## Das Modell als Ganzes\n\nKeines dieser Muster existiert isoliert. Der Wert von GitLabs Pipeline-Modell liegt in der Kombinierbarkeit seiner Bausteine:\n\n- Ein Monorepo nutzt Parent-Child-Pipelines, und jede Child-Pipeline nutzt DAG-Execution.\n- Eine Microservices-Plattform nutzt Multi-Project-Pipelines, und jedes Projekt nutzt MR-Pipelines mit Merged-Results.\n- Eine governed Plattform nutzt CI/CD Components, um die obigen Muster organisationsweit zu standardisieren.\n\nDie meisten Teams entdecken eines dieser Muster, wenn sie auf ein konkretes Problem stoßen. Teams, die das vollständige Modell verstehen, entwickeln daraus eine Delivery-Infrastruktur, die tatsächlich abbildet, wie ihre Engineering-Organisation arbeitet – und mit ihr wächst.\n\n## Weitere Muster\n\nDas Pipeline-Modell geht über die fünf vorgestellten Muster hinaus:\n\n- [Review Apps mit dynamischen Umgebungen](https://docs.gitlab.com/ci/environments/) erstellen für jeden Feature-Branch eine Live-Vorschau und räumen sie automatisch auf, wenn der MR geschlossen wird.\n- [Caching- und Artifact-Strategien](https://docs.gitlab.com/ci/caching/) sind nach der strukturellen Arbeit häufig der direkteste Weg zur weiteren Laufzeitoptimierung – ohne die Pipeline-Struktur zu verändern.\n- [Geplante und API-ausgelöste Pipelines](https://docs.gitlab.com/ci/pipelines/schedules/) eignen sich für Workloads, die nicht bei jedem Code-Push laufen sollten: Nightly-Security-Scans, Compliance-Reports und Release-Automatisierung lassen sich als geplante oder [API-ausgelöste](https://docs.gitlab.com/ci/triggers/) Pipelines mit `$CI_PIPELINE_SOURCE`-Routing modellieren.\n\n> [GitLab Ultimate kostenlos testen](https://about.gitlab.com/de-de/free-trial/) und Pipeline-Logik ab heute einsetzen.\n\n## Für deutsche Unternehmen: Regulatorischer Kontext\n\nTeams, die Pipeline-Governance nach Muster 5 einführen, adressieren dabei möglicherweise auch Anforderungen, die regulatorische Frameworks an sichere Softwareentwicklungsprozesse stellen.\n\nCI/CD Components mit erzwungenen Security-Gates könnten Anforderungen an sichere Entwicklungsprozesse betreffen – beispielsweise in Bereichen, die Frameworks wie NIS2, ISO 27001 oder BSI IT-Grundschutz an den Software-Entwicklungslebenszyklus adressieren. Protected Environments und Resource Groups betreffen ähnliche Themen im Bereich Änderungskontrolle und Umgebungstrennung, wie sie in Governance-Frameworks typischerweise explizit formuliert sind.\n\nMulti-Project-Pipelines mit API-Contract-Validierung (Muster 2) schaffen Sichtbarkeit über Service-Abhängigkeiten hinweg – ein Aspekt, den Frameworks zur Lieferkettensicherheit adressieren.\n\nMerged-Results-Pipelines (Muster 4) dokumentieren automatisch, dass das tatsächliche Merge-Ergebnis getestet wurde, nicht nur der Feature-Branch in Isolation. Dies könnte Anforderungen an nachvollziehbare Änderungsprozesse betreffen, wie sie in Change-Management-Kontrollen verschiedener Sicherheitsframeworks formuliert sind.\n\nFür konkrete Compliance-Anforderungen im eigenen regulatorischen Umfeld empfiehlt sich Rücksprache mit entsprechender Fachberatung.\n\n## Abschnitt 2: Konfiguration und Implementierung\n\n*Für Entwicklungsteams und DevOps-Praktiker: ausgewählte Konfigurationsbeispiele zu den Mustern 1, 4 und 5. Für vollständige Konfigurationen aller Muster: [englischer Originalartikel](https://about.gitlab.com/blog/5-ways-gitlab-pipeline-logic-solves-real-engineering-problems/).*\n\nDie folgenden Konfigurationen sind illustrativ aufgebaut. Die Skripte verwenden `echo`-Befehle, um das Wesentliche sichtbar zu halten. Für den produktiven Einsatz werden die `echo`-Befehle durch die tatsächlichen Build-, Test- und Deploy-Schritte ersetzt.\n\n### Muster 1: Parent-Child-Pipelines und DAG-Execution\n\nEine Parent-Pipeline erkennt Änderungen und löst nur die betroffenen Child-Pipelines aus:\n\n```yaml # .gitlab-ci.yml stages:\n  - trigger\n\ntrigger-services:\n  stage: trigger\n  trigger:\n    include:\n      - local: '.gitlab/ci/api-service.yml'\n      - local: '.gitlab/ci/web-service.yml'\n      - local: '.gitlab/ci/worker-service.yml'\n    strategy: depend\n```\n\nInnerhalb der Child-Pipeline ermöglicht `needs:` DAG-Execution – der Test startet, sobald der Build abgeschlossen ist, ohne auf andere Jobs in derselben Stage zu warten:\n\n```yaml # .gitlab/ci/api-service.yml stages:\n  - build\n  - test\n\nbuild-api:\n  stage: build\n  script:\n    - echo \"Building API service\"\n\ntest-api:\n  stage: test\n  needs: [build-api]\n  script:\n    - echo \"Running API tests\"\n```\n\n![Local downstream pipelines](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738759/Blog/Imported/hackathon-fake-blog-post-s/image3_vwj3rz.png \"Local downstream pipelines\")\n\n### Muster 4: MR-First-Delivery\n\nWorkflow-Rules, MR-Pipelines und Merged-Results zusammen ergeben ein kontextabhängiges Pipeline-Verhalten:\n\n```yaml # .gitlab-ci.yml workflow:\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS\n      when: never\n    - if: $CI_COMMIT_BRANCH\n    - if: $CI_PIPELINE_SOURCE == \"schedule\"\n\nstages:\n  - fast-checks\n  - expensive-tests\n  - deploy\n\nlint-code:\n  stage: fast-checks\n  script:\n    - echo \"Running linter\"\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"push\"\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH == \"main\"\n\nunit-tests:\n  stage: fast-checks\n  script:\n    - echo \"Running unit tests\"\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"push\"\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH == \"main\"\n\nintegration-tests:\n  stage: expensive-tests\n  script:\n    - echo \"Running integration tests (15 min)\"\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH == \"main\"\n\ne2e-tests:\n  stage: expensive-tests\n  script:\n    - echo \"Running E2E tests (30 min)\"\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH == \"main\"\n\nnightly-comprehensive-scan:\n  stage: expensive-tests\n  script:\n    - echo \"Running full nightly suite (2 hours)\"\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"schedule\"\n\ndeploy-production:\n  stage: deploy\n  script:\n    - echo \"Deploying to production\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n      when: manual\n```\n\n![Conditional pipelines (within a branch with no MR)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738768/Blog/Imported/hackathon-fake-blog-post-s/image6_dnfcny.png \"Conditional pipelines (within a branch with no MR)\")\n\n![Conditional pipelines (within an MR)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738772/Blog/Imported/hackathon-fake-blog-post-s/image1_wyiafu.png \"Conditional pipelines (within an MR)\")\n\n![Conditional pipelines (on the main branch)](https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738774/Blog/Imported/hackathon-fake-blog-post-s/image5_r6lkfd.png \"Conditional pipelines (on the main branch)\")\n\n### Muster 5: CI/CD Components\n\nEine Komponentendefinition aus einer gemeinsamen Bibliothek:\n\n```yaml # templates/deploy.yml spec:\n  inputs:\n    stage:\n      default: deploy\n    environment:\n      default: production\n--- deploy-job:\n  stage: $[[ inputs.stage ]]\n  script:\n    - echo \"Deploying $APP_NAME to $[[ inputs.environment ]]\"\n    - echo \"Deploy URL: $DEPLOY_URL\"\n  environment:\n    name: $[[ inputs.environment ]]\n```\n\nSo bindet ein Anwendungsteam die Komponenten ein:\n\n```yaml # Application repo: .gitlab-ci.yml variables:\n  APP_NAME: \"my-awesome-app\"\n  DEPLOY_URL: \"https://api.example.com\"\n\ninclude:\n  - component: gitlab.com/my-org/component-library/build@v1.0.6\n  - component: gitlab.com/my-org/component-library/test@v1.0.6\n  - component: gitlab.com/my-org/component-library/deploy@v1.0.6\n    inputs:\n      environment: staging\n\nstages:\n  - build\n  - test\n  - deploy\n```\n\n### Orientierung zu den Mustern 2 und 3\n\n**Muster 2 (Multi-Project-Pipelines):** Das Frontend-Repository publiziert ein API-Contract-Artifact und löst anschließend die Backend-Pipeline aus. Das Backend ruft das Artifact über die GitLab Jobs API ab und validiert es. Der `integration-test`-Job läuft dabei nur dann, wenn er von einer Upstream-Pipeline ausgelöst wurde (`$CI_PIPELINE_SOURCE == \"pipeline\"`), nicht bei einem eigenständigen Push. Die Frontend-Projekt-ID wird als CI/CD-Variable gesetzt, um Hardcoding zu vermeiden. Vollständige Konfigurationen beider Repositories: [englischer Originalartikel](https://about.gitlab.com/blog/5-ways-gitlab-pipeline-logic-solves-real-engineering-problems/#2-microservices-cross-repo-multi-project-pipelines).\n\n**Muster 3 (Dynamische Child-Pipelines):** Ein `generate-config`-Job erzeugt zur Laufzeit environment-spezifische YAML-Dateien. Trigger-Jobs nutzen `extends:` für gemeinsam genutzte Konfiguration und `needs:` für sequenzielle Promotion (dev → staging → prod mit manuellem Gate). Vollständige Konfiguration: [englischer Originalartikel](https://about.gitlab.com/blog/5-ways-gitlab-pipeline-logic-solves-real-engineering-problems/#3-multi-tenant--matrix-deployments-dynamic-child-pipelines).\n\n## Weiterführende Artikel\n\n- [Variable and artifact sharing in GitLab parent-child pipelines](https://about.gitlab.com/blog/variable-and-artifact-sharing-in-gitlab-parent-child-pipelines/)\n- [CI/CD inputs: Secure and preferred method to pass parameters to a pipeline](https://about.gitlab.com/blog/ci-cd-inputs-secure-and-preferred-method-to-pass-parameters-to-a-pipeline/)\n- [Tutorial: How to set up your first GitLab CI/CD component](https://about.gitlab.com/blog/tutorial-how-to-set-up-your-first-gitlab-ci-cd-component/)\n- [How to include file references in your CI/CD components](https://about.gitlab.com/blog/how-to-include-file-references-in-your-ci-cd-components/)\n- [FAQ: GitLab CI/CD Catalog](https://about.gitlab.com/blog/faq-gitlab-ci-cd-catalog/)\n- [Building a GitLab CI/CD pipeline for a monorepo the easy way](https://about.gitlab.com/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way/)\n- [A CI/CD component builder's journey](https://about.gitlab.com/blog/a-ci-component-builders-journey/)\n- [CI/CD Catalog goes GA: No more building pipelines from scratch](https://about.gitlab.com/blog/ci-cd-catalog-goes-ga-no-more-building-pipelines-from-scratch/)","5 GitLab-Pipeline-Muster für komplexe Engineering-Herausforderungen","Wie Parent-Child-Pipelines, DAG-Execution, MR-Pipelines und CI/CD Components komplexe Delivery-Probleme lösen – von Monorepos bis zur governed Plattform.",[738],"Omid Khan","https://res.cloudinary.com/about-gitlab-com/image/upload/v1772721753/frfsm1qfscwrmsyzj1qn.png","2026-04-09",[22,742,24,743],"DevOps platform","features",{"featured":14,"template":15,"slug":745},"5-ways-gitlab-pipeline-logic-solves-real-engineering-problems",{"content":747,"config":755},{"title":748,"description":749,"authors":750,"heroImage":751,"date":752,"body":753,"category":11,"tags":754},"GitLab Container Virtual Registry mit Docker Hardened Images einrichten","Mehrere Registries hinter einem Endpunkt – GitLab Container Virtual Registry mit Docker Hardened Images, Caching und Audit-Trail.",[9],"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772111172/mwhgbjawn62kymfwrhle.png","2026-03-12","Wer im Plattformteam arbeitet, kennt solche Gespräche:\n\n*„Security sagt: Wir müssen gehärtete Base-Images verwenden.\"*\n\n*„Prima – wo trage ich jetzt die Credentials für noch eine weitere Registry ein?\"*\n\n*„Und wie stellen wir sicher, dass alle sie auch wirklich nutzen?\"*\n\nOder diese hier:\n\n*„Warum sind unsere Builds so langsam?\"*\n\n*„Wir pullen dasselbe 500-MB-Image in jedem einzelnen Job neu von Docker Hub.\"*\n\n*„Kann man die nicht irgendwo cachen?\"*\n\nIch arbeite bei GitLab an der [Container Virtual Registry](https://docs.gitlab.com/user/packages/virtual_registry/container/) – einem Pull-Through-Cache, der vor den vorgelagerten Registries sitzt: Docker Hub, dhi.io (Docker Hardened Images), MCR und Quay. Teams erhalten einen einzigen Endpunkt zum Pullen. Images werden beim ersten Abruf gecacht; alle nachfolgenden Pulls kommen aus dem Cache. Das Entwicklungsteam muss nicht wissen, aus welchem Upstream ein bestimmtes Image stammt.\n\nDieser Artikel zeigt die Einrichtung der Container Virtual Registry – mit Docker Hardened Images als konkretem Anwendungsfall, da diese Kombination für Teams mit Sicherheitsanforderungen besonders naheliegt.\n\n## Das Problem: Registry-Wildwuchs im Plattformteam\n\nDie Plattformteams, mit denen ich spreche, verwalten Container-Images über drei bis fünf Registries:\n\n- **Docker Hub** für die meisten Base-Images\n- **dhi.io** für Docker Hardened Images (sicherheitskritische Workloads)\n- **MCR** für .NET- und Azure-Tooling\n- **Quay.io** für das Red-Hat-Ökosystem\n- **Interne Registries** für proprietäre Images\n\nJede davon hat eigene Authentifizierungsmechanismen, unterschiedliche Netzwerklatenz und eine eigene Pfadstruktur für Images.\n\nCI/CD-Konfigurationen füllen sich mit registry-spezifischer Logik. Credential-Management wird zum eigenständigen Projekt. Und jeder Pipeline-Job lädt dieselben Base-Images erneut über das Netz – obwohl sie sich seit Wochen nicht geändert haben.\n\nContainer Virtual Registry konsolidiert das: eine Registry-URL, ein Authentifizierungsfluss über GitLab, gecachte Images aus GitLab-Infrastruktur statt wiederholter Internet-Traversierung.\n\n## Funktionsweise\n\nDas Modell ist geradlinig:\n\n```text\n\nPipeline ruft ab:\n  gitlab.com/virtual_registries/container/1000016/python:3.13\n\nVirtual Registry prüft:\n  1. Im Cache vorhanden? → Direkt zurückgeben\n  2. Nein? → Vom Upstream laden, cachen, zurückgeben\n\n\n```\n\nUpstreams werden in Prioritätsreihenfolge konfiguriert. Bei einem eingehenden Pull-Request durchsucht die Virtual Registry die Upstreams der Reihe nach, bis das Image gefunden wird. Das Ergebnis wird für einen konfigurierbaren Zeitraum gecacht – standardmäßig 24 Stunden.\n\n\n```text\n\n┌─────────────────────────────────────────────────────────┐ │                    CI/CD Pipeline                       │ │                          │                              │ │                          ▼                              │ │   gitlab.com/virtual_registries/container/\u003Cid>/image   │ └─────────────────────────────────────────────────────────┘\n                           │\n                           ▼\n┌─────────────────────────────────────────────────────────┐ │            Container Virtual Registry                   │ │                                                         │ │  Upstream 1: Docker Hub ────────────────┐               │ │  Upstream 2: dhi.io (Hardened) ────────┐│               │ │  Upstream 3: MCR ─────────────────────┐││               │ │  Upstream 4: Quay.io ────────────────┐│││               │ │                                      ││││               │ │                    ┌─────────────────┴┴┴┴──┐            │ │                    │        Cache          │            │ │                    │  (manifests + layers) │            │ │                    └───────────────────────┘            │ └─────────────────────────────────────────────────────────┘\n\n```\n\n## Was das konkret bringt – besonders mit Docker Hardened Images\n\n[Docker Hardened Images](https://docs.docker.com/dhi/) zeichnen sich durch minimale Angriffsfläche, nahezu keine bekannten CVEs, vollständige Software Bills of Materials (SBOMs) und SLSA-Provenance aus. Für Teams, die Base-Images für sicherheitskritische Workloads evaluieren, gehören sie auf die Shortlist.\n\nDer Wechsel zu dhi.io erzeugt jedoch dieselbe operative Reibung wie jede neue Registry:\n\n- **Credential-Verteilung**: Docker-Credentials müssen auf alle Systeme verteilt werden, die Images von dhi.io abrufen.\n- **CI/CD-Anpassungen**: Jede Pipeline muss für die Authentifizierung mit dhi.io aktualisiert werden.\n- **Akzeptanzproblem**: Ohne zentrale Steuerung greifen Teams weiterhin auf reguläre Images zurück.\n- **Fehlende Transparenz**: Ob Teams tatsächlich die gehärteten Varianten nutzen, ist kaum nachvollziehbar.\n\nDie Virtual Registry löst jeden dieser Punkte:\n\n**Einzelne Credential**: Teams authentifizieren sich bei GitLab. Die Virtual Registry übernimmt die Upstream-Authentifizierung. Docker-Credentials werden einmalig auf Registry-Ebene konfiguriert und gelten für alle Pulls.\n\n**Keine per-Team-CI/CD-Änderungen**: Pipelines auf die Virtual Registry zeigen lassen – fertig. Die Upstream-Konfiguration ist zentralisiert.\n\n**Schrittweise Einführung**: Da Images mit ihrem vollständigen Pfad gecacht werden, ist im Cache sichtbar, was tatsächlich abgerufen wird. Wird `library/python:3.11` statt der gehärteten Variante gepullt, ist das erkennbar.\n\n**Audit-Trail**: Der Cache zeigt exakt, welche Images aktiv genutzt werden – nachvollziehbar für Compliance-Zwecke und als Grundlage für das Verständnis der tatsächlichen Infrastruktur-Abhängigkeiten.\n\nWer das Konzept verstanden hat und die Einrichtung zu einem späteren Zeitpunkt in Angriff nimmt: Die wesentlichen Konzepte sind damit abgedeckt. Die technische Konfiguration folgt im nächsten Abschnitt.\n\n## Einrichtung\n\nDie folgende Einrichtung nutzt den Python-Client aus dem Demo-Projekt.\n\n### Virtual Registry erstellen\n\n```python\nfrom virtual_registry_client import VirtualRegistryClient\nclient = VirtualRegistryClient()\nregistry = client.create_virtual_registry(\n    group_id=\"785414\",  # ID der obersten Gruppe\n    name=\"platform-images\",\n    description=\"Cached container images for platform teams\"\n)\nprint(f\"Registry ID: {registry['id']}\") # Diese ID wird für die Pull-URL benötigt\n```\n\n### Docker Hub als Upstream hinzufügen\n\nFür offizielle Images wie Alpine, Python usw.:\n\n```python\n\ndocker_upstream = client.create_upstream(\n    registry_id=registry['id'],\n    url=\"https://registry-1.docker.io\",\n    name=\"Docker Hub\",\n    cache_validity_hours=24\n)\n\n```\n\n### Docker Hardened Images (dhi.io) hinzufügen\n\nDocker Hardened Images werden auf `dhi.io` gehostet – einer separaten Registry mit Authentifizierungspflicht:\n\n```python\n\ndhi_upstream = client.create_upstream(\n    registry_id=registry['id'],\n    url=\"https://dhi.io\",\n    name=\"Docker Hardened Images\",\n    username=\"your-docker-username\",\n    password=\"your-docker-access-token\",\n    cache_validity_hours=24\n)\n\n```\n\n### Weitere Upstreams hinzufügen\n\n```python\n\n# MCR für .NET-Teams client.create_upstream(\n    registry_id=registry['id'],\n    url=\"https://mcr.microsoft.com\",\n    name=\"Microsoft Container Registry\",\n    cache_validity_hours=48\n)\n# Quay für das Red-Hat-Ökosystem client.create_upstream(\n    registry_id=registry['id'],\n    url=\"https://quay.io\",\n    name=\"Quay.io\",\n    cache_validity_hours=24\n)\n\n```\n\n### CI/CD aktualisieren\n\nEine `.gitlab-ci.yml`, die über die Virtual Registry pullt:\n\n```yaml\n\nvariables:\n  VIRTUAL_REGISTRY_ID: \u003Cyour_virtual_registry_ID>\n\n  \nbuild:\n  image: docker:24\n  services:\n    - docker:24-dind\n  before_script:\n    # Authentifizierung bei GitLab – Upstream-Auth wird übernommen\n    - echo \"${CI_JOB_TOKEN}\" | docker login -u gitlab-ci-token --password-stdin gitlab.com\n  script:\n    # Alle Pulls laufen über die zentrale Virtual Registry\n    \n    # Offizielle Docker Hub Images (library/-Präfix erforderlich)\n    - docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/library/alpine:latest\n    \n    # Docker Hardened Images von dhi.io (kein Präfix nötig)\n    - docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/python:3.13\n    \n    # .NET von MCR\n    - docker pull gitlab.com/virtual_registries/container/${VIRTUAL_REGISTRY_ID}/dotnet/sdk:8.0\n\n\n```\n\n### Image-Pfadformate\n\nVerschiedene Registries verwenden unterschiedliche Pfadkonventionen:\n\n| Registry | Beispiel-Pull-URL |\n|----------|-------------------|\n| Docker Hub (offiziell) | `.../library/python:3.11-slim` |\n| Docker Hardened Images (dhi.io) | `.../python:3.13` |\n| MCR | `.../dotnet/sdk:8.0` |\n| Quay.io | `.../prometheus/prometheus:latest` |\n\n### Funktionsprüfung\n\nNach einigen Pulls lässt sich der Cache überprüfen:\n\n```python\n\nupstreams = client.list_registry_upstreams(registry['id']) for upstream in upstreams:\n    entries = client.list_cache_entries(upstream['id'])\n    print(f\"{upstream['name']}: {len(entries)} cached entries\")\n\n\n```\n\n## Messergebnisse\n\nTestergebnisse beim Pullen über die Virtual Registry:\n\n| Messgröße | Ohne Cache | Mit warmem Cache |\n|-----------|------------|-----------------|\n| Pull-Zeit (Alpine) | 10,3 s | 4,2 s |\n| Pull-Zeit (Python 3.13 DHI) | 11,6 s | ~4 s |\n| Netzwerk-Roundtrips zum Upstream | Jeder Pull | Nur Cache-Misses |\n\nDer erste Pull hat dieselbe Dauer – das Image muss vom Upstream geladen werden. Jeder weitere Pull innerhalb der Cache-Gültigkeitsdauer kommt direkt aus GitLab-Storage: kein Netzwerk-Hop zu Docker Hub, dhi.io, MCR oder einer anderen Registry.\n\nBei Teams mit vielen Pipeline-Jobs pro Tag summiert sich das zu einem messbaren Gewinn bei den Build-Laufzeiten.\n\n## Praktische Hinweise\n\n### Cache-Gültigkeit\n\nDer Standard sind 24 Stunden. Für sicherheitskritische Images, bei denen Patches schnell verfügbar sein sollen, empfiehlt sich ein kürzeres Intervall:\n\n```python\n\nclient.create_upstream(\n    registry_id=registry['id'],\n    url=\"https://dhi.io\",\n    name=\"Docker Hardened Images\",\n    username=\"your-username\",\n    password=\"your-token\",\n    cache_validity_hours=12\n)\n\n```\n\nFür stabile Images mit fixen Versions-Tags ist ein längeres Intervall problemlos.\n\n### Upstream-Priorität\n\nUpstreams werden der Reihe nach geprüft. Bei gleichnamigen Images in verschiedenen Registries gewinnt der erste passende Upstream.\n\n### Limits\n\n- Maximal 20 Virtual Registries pro Gruppe\n- Maximal 20 Upstreams pro Virtual Registry\n\n## Konfiguration über die Oberfläche\n\nVirtual Registries und Upstreams lassen sich auch direkt in der GitLab-Oberfläche einrichten – ohne API-Aufrufe. Unter **Einstellungen > Pakete und Registries > Virtual Registry** der jeweiligen Gruppe stehen folgende Optionen zur Verfügung:\n\n- Virtual Registries erstellen und verwalten\n- Upstreams hinzufügen, bearbeiten und neu anordnen\n- Cache anzeigen und verwalten\n- Überblick, welche Images abgerufen werden\n\n## Ausblick\n\nIn Entwicklung:\n\n- **Allow/Deny-Listen**: Regex-basierte Steuerung, welche Images aus welchen Upstreams abgerufen werden dürfen.\n\nContainer Virtual Registry befindet sich in der Beta-Phase. Die Funktion wird produktiv eingesetzt und wird weiterentwickelt – Feedback fließt direkt in die Priorisierung ein.\n\n## Feedback\n\nWer als Plattformteam mit Registry-Wildwuchs zu kämpfen hat: Ich möchte verstehen, wie die aktuelle Situation aussieht.\n\n- Wie viele Upstream-Registries werden verwaltet?\n- Wo liegt der größte Schmerzpunkt?\n- Würde ein solcher Ansatz helfen – und falls nicht: Was fehlt?\n\nErfahrungen und Rückmeldungen gerne im [Container Virtual Registry Feedback-Issue](https://gitlab.com/gitlab-org/gitlab/-/work_items/589630) teilen.\n\n## Weiterführende Ressourcen\n\n- [Neue GitLab-Metriken und Registry-Funktionen zur Optimierung von CI/CD-Pipelines](https://about.gitlab.com/de-de/blog/new-gitlab-metrics-and-registry-features-help-reduce-ci-cd-bottlenecks/)\n- [Container Virtual Registry – Dokumentation](https://docs.gitlab.com/user/packages/virtual_registry/container/)\n- [Container Virtual Registry – API](https://docs.gitlab.com/api/container_virtual_registries/)\n\n## Für deutsche Unternehmen könnte dies folgende Themen betreffen\n\nTeams, die sicherheitsgehärtete Base-Images mit vollständigen SBOMs und SLSA-Provenance einsetzen, haben möglicherweise auch Compliance-Überlegungen – beispielsweise in Bereichen wie Sicherheit der Software-Lieferkette, Nachvollziehbarkeit von Image-Abhängigkeiten und zentralem Audit-Trail.\n\nRegulatorische Frameworks wie NIS2 und der Cyber Resilience Act adressieren ähnliche Themen rund um Software-Lieferketten und SBOM-Transparenz. Für konkrete Compliance-Anforderungen empfiehlt sich Rücksprache mit entsprechender Fachberatung.",[24,26,743],{"featured":35,"template":15,"slug":756},"using-gitlab-container-virtual-registry-with-docker-hardened-images",{"promotions":758},[759,773,784,796],{"id":760,"categories":761,"header":763,"text":764,"button":765,"image":770},"ai-modernization",[762],"ai-ml","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":766,"config":767},"Get your AI maturity score",{"href":768,"dataGaName":769,"dataGaLocation":252},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":771},{"src":772},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":774,"categories":775,"header":776,"text":764,"button":777,"image":781},"devops-modernization",[26,576],"Are you just managing tools or shipping innovation?",{"text":778,"config":779},"Get your DevOps maturity score",{"href":780,"dataGaName":769,"dataGaLocation":252},"/assessments/devops-modernization-assessment/",{"config":782},{"src":783},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":785,"categories":786,"header":788,"text":764,"button":789,"image":793},"security-modernization",[787],"security","Are you trading speed for security?",{"text":790,"config":791},"Get your security maturity score",{"href":792,"dataGaName":769,"dataGaLocation":252},"/assessments/security-modernization-assessment/",{"config":794},{"src":795},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":797,"paths":798,"header":801,"text":802,"button":803,"image":808},"github-azure-migration",[799,800],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":804,"config":805},"See how GitLab compares to GitHub",{"href":806,"dataGaName":807,"dataGaLocation":252},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":809},{"src":783},{"header":811,"blurb":812,"button":813,"secondaryButton":818},"Beginne noch heute, schneller zu entwickeln","Entdecke, was dein Team mit der intelligenten Orchestrierungsplattform für DevSecOps erreichen kann.\n",{"text":814,"config":815},"Kostenlosen Test starten",{"href":816,"dataGaName":58,"dataGaLocation":817},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/de-de/","feature",{"text":60,"config":819},{"href":62,"dataGaName":63,"dataGaLocation":817},1777493578410]