Blog

Anwendungen mit Pipelines erstellen

Joris Conijn

Aktualisiert Oktober 15, 2025
7 Minuten

In größeren Unternehmen gibt es eine Menge Dinge, die bereits vorhanden sind. Denken Sie an Dinge wie Bereitstellungspipelines für Ihre Anwendungen. Aber wie richten Sie diese mit den Services von AWS ein? In diesem Blogbeitrag zeige ich Ihnen, wie ich das für meine Lieblingsprojekte mache.

Ich bin ein großer Fan von CloudFormation, daher sind die Beispiele, die ich zeigen werde, CloudFormation-Snippets.

Das Git-Repository

Ich verwende AWS CodeCommit als Quellcode-Repository. Der Grund für diese Wahl ist, dass es mit AWS CodePipeline integriert ist. Wir möchten auch die Möglichkeit haben, unsere Infrastruktur zu testen. Dazu verwende ich normalerweise Feature Branches. Hier zeigt sich die erste Herausforderung. Wir brauchen nur 1 Repository und eine Pipeline für die Bereitstellung unserer Infrastruktur. Aber wir brauchen auch eine Pipeline, die unseren Feature Branch bereitstellt. In CloudFormation können Sie dies mithilfe von Bedingungen tun.

Parameters:
  FeatureGitBranch:
    Type: String
    Default: ""
  ProjectName:
    Type: String
    Default: ""   
Conditions:
  IsMainBranchPipeline: !Equals [!Ref FeatureGitBranch, ""]
  IsFeatureBranchPipeline: !Not [Condition: IsMainBranchPipeline]

Durch die Angabe eines FeatureGitBranch-Parameters können wir nun einige Auswahlmöglichkeiten treffen. Zum Beispiel können wir das Repository nur in der Produktionspipeline erstellen.

Resources:
  PipelineRepo:
    Condition: IsMainBranchPipeline
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryName: !Ref ProjectName
      RepositoryDescription: <repository-description>

Die Anforderungen an die Pipeline

Die Pipeline verwendet eine Reihe von Ressourcen. Sie können diese Ressourcen in Ihren Pipelines gemeinsam nutzen. Sie befinden sich also in einer separaten Vorlage und ich setze diese Ressourcen einmal pro Region ein, die ich verwende.

Zunächst benötigen Sie einen S3-Bucket, um die in jeder Phase erstellten Artefakte zu speichern.

ArtifactsBucket:
  Type: AWS::S3::Bucket
  DeletionPolicy: Retain
  UpdateReplacePolicy: Retain
  Properties:
    BucketName: !Sub codepipeline-artifacts-${AWS::AccountId}-${AWS::Region}
    VersioningConfiguration:
      Status: Enabled
    BucketEncryption:
      ServerSideEncryptionConfiguration:
        - ServerSideEncryptionByDefault:
            SSEAlgorithm: AES256

Ich verwende einen vorhersehbaren Bucket-Namen, damit ich ihn in meiner Pipeline verwenden kann. Da Bucket-Namen einen global eindeutigen Namen haben müssen, füge ich auch die Konto-ID und die Region hinzu.

Sie benötigen außerdem eine IAM-Rolle. Sie werden diese Rolle in Ihrer Pipeline verwenden, um Ihre CloudFormation-Vorlage bereitzustellen.

CloudFormationServiceRole:
 Type: AWS::IAM::Role
 Properties:
   RoleName: !Sub cloudformation-execution-role-${AWS::Region}
   AssumeRolePolicyDocument:
     Version: "2012-10-17"
     Statement:
       - Action: sts:AssumeRole
         Effect: Allow
         Principal: { Service: cloudformation.amazonaws.com }
   ManagedPolicyArns:
     - arn:aws:iam::aws:policy/AdministratorAccess

Auch hier verwende ich einen vorhersehbaren Namen und gebe die Region an. Da Rollennamen in Ihrem Konto eindeutig sind, können Sie dies in jeder Region einsetzen. Der Einfachheit halber habe ich die verwaltete Richtlinie AdministratorAccess verwendet. Vielleicht möchten Sie dies für Ihren eigenen Bereich einschränken.

Die Pipeline

Die Pipeline selbst benötigt ebenfalls eine Rolle. Diese Rolle kann die CloudFormation-Rolle übergeben und die im vorherigen Schritt erstellten Buckets verwenden.

CodePipelineExecutionRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Action: "sts:AssumeRole"
          Effect: Allow
          Principal:
            Service:
              - codepipeline.amazonaws.com
    Policies:
      - PolicyName: CodePipelineAccess
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action: "iam:PassRole"
              Resource: !Sub cloudformation-execution-role-${AWS::Region}
      - PolicyName: CodePipelineCodeAndS3Bucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Action:
                - s3:GetBucketAcl
                - s3:GetBucketLocation
              Effect: Allow
              Resource:
                - !Sub arn:${AWS::Partition}:s3:::codepipeline-artifacts-${AWS::AccountId}-eu-west-1
                - !Sub arn:${AWS::Partition}:s3:::codepipeline-artifacts-${AWS::AccountId}-eu-central-1
            - Action:
                - "s3:GetObject"
                - "s3:GetObjectVersion"
                - "s3:PutObject"
              Effect: Allow
              Resource:
                - !Sub arn:${AWS::Partition}:s3:::codepipeline-artifacts-${AWS::AccountId}-eu-west-1/*
                - !Sub arn:${AWS::Partition}:s3:::codepipeline-artifacts-${AWS::AccountId}-eu-central-1/*
      - PolicyName: CodeCommitAccess
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Action:
                - codecommit:GitPull
                - codecommit:GetBranch
                - codecommit:GetCommit
                - codecommit:UploadArchive
                - codecommit:GetUploadArchiveStatus
              Effect: Allow
              Resource:
                - !Sub arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${ProjectName}
                - !Sub arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${ProjectName}/*
      - PolicyName: CodePipelineCodeBuildAndCloudformationAccess
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - "codebuild:StartBuild"
                - "codebuild:BatchGetBuilds"
              Resource:
                - !GetAtt CodeBuildProjectBuildAndPackage.Arn
            - Effect: Allow
              Action:
                - "cloudformation:DescribeStacks"
              Resource: !Sub "arn:${AWS::Partition}:cloudformation:eu-*:${AWS::AccountId}:stack/*"
            - Effect: Allow
              Action:
                - "cloudformation:CreateStack"
                - "cloudformation:DeleteStack"
                - "cloudformation:UpdateStack"
                - "cloudformation:CreateChangeSet"
                - "cloudformation:ExecuteChangeSet"
                - "cloudformation:DeleteChangeSet"
                - "cloudformation:DescribeChangeSet"
                - "cloudformation:SetStackPolicy"
                - "cloudformation:SetStackPolicy"
                - "cloudformation:ValidateTemplate"
              Resource:
                - !Sub "arn:${AWS::Partition}:cloudformation:eu-*:${AWS::AccountId}:stack/${ProjectName}-*/*"

Wie Sie in dem Schnipsel sehen können, darf die Rolle auch ein CodeBuild-Projekt starten. Und sie kann eine CloudFormation-Vorlage bereitstellen. Sie haben vielleicht bemerkt, dass ich in dieser Rolle 2 Regionen verwendet habe. Das liegt daran, dass ich in diesem speziellen Beispiel eine Pipeline habe, die 2 Regionen verwendet.

Da wir 2 Regionen verwenden, benötigen wir auch 2 Artefaktspeicher.

Pipeline:
  Type: AWS::CodePipeline::Pipeline
  Properties:
    ArtifactStores:
      - Region: eu-west-1
        ArtifactStore:
          Location: !Sub codepipeline-artifacts-${AWS::AccountId}-eu-west-1
          Type: S3
      - Region: eu-central-1
        ArtifactStore:
          Location: !Sub codepipeline-artifacts-${AWS::AccountId}-eu-central-1
          Type: S3
    RoleArn: !GetAtt CodePipelineExecutionRole.Arn
    RestartExecutionOnUpdate: true
    Stages:
      - Name: Source
        Actions:
          - Name: SourceCodeRepo
            ActionTypeId:
              Category: Source
              Owner: AWS
              Version: 1
              Provider: CodeCommit
            Configuration:
              PollForSourceChanges: False
              RepositoryName: !Ref ProjectName
              BranchName: !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, "main"]
            OutputArtifacts:
              - Name: SourceCodeAsZip
            RunOrder: 1

Abhängig von der IsFeatureBranchPipeline-Bedingung wählen wir den richtigen Zweig für diese Pipeline aus. Abhängig von Ihrem Projekt benötigen Sie möglicherweise einen Build-Schritt. Ich verwende CodeBuild, um Unit-Tests auszuführen und alle benötigten Ressourcen zu erstellen und zu verpacken.

      - Name: BuildAndPackage
        Actions:
          - Name: CodeBuild
            ActionTypeId:
              Category: Build
              Owner: AWS
              Provider: CodeBuild
              Version: "1"
            Configuration:
              ProjectName: !Ref CodeBuildProjectBuildAndPackage
            InputArtifacts:
              - Name: SourceCodeAsZip
            OutputArtifacts:
              - Name: BuildArtifactAsZip

Ich habe das CodeBuild-Projekt und das IAM-Rollen-Snippet für CodeBuild nicht aufgenommen. Dazu werde ich in Zukunft einen Blogbeitrag verfassen.

Kommen wir also zu dem Teil, der Spaß macht. Der nächste Schritt ist die eigentliche Bereitstellung der CloudFormation-Vorlage. Ich verwende 2 Regionen und möchte die Bereitstellung nur in diesen 2 Regionen für meine Produktionsumgebung vornehmen. Außerdem habe ich verschiedene Parameter für meine Produktionsumgebung. Auch hier verwende ich Bedingungen, um dieses Verhalten zu steuern.

          - !If
            - IsMainBranchPipeline
            - Name: Production
              Actions:
                - Name: Ireland-CreateChangeSet
                  RunOrder: 1
                  Region: eu-west-1
                  InputArtifacts:
                    - Name: BuildArtifactAsZip
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_REPLACE
                    RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-production
                    ChangeSetName: !Sub ${ProjectName}-production-ChangeSet
                    TemplatePath: BuildArtifactAsZip::packaged-template.yaml
                    Capabilities: CAPABILITY_NAMED_IAM
                    ParameterOverrides: |-
                      {
                        "EnvType": "production"
                      }
                - Name: Frankfurt-CreateChangeSet
                  RunOrder: 1
                  Region: eu-central-1
                  InputArtifacts:
                    - Name: BuildArtifactAsZip
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_REPLACE
                    RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-production
                    ChangeSetName: !Sub ${ProjectName}-production-ChangeSet
                    TemplatePath: BuildArtifactAsZip::packaged-template.yaml
                    Capabilities: CAPABILITY_NAMED_IAM
                    ParameterOverrides: |
                      {
                        "EnvType": "production"
                      }
                - Name: Ireland-ExecuteChangeSet
                  RunOrder: 2
                  Region: eu-west-1
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_EXECUTE
                    RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-production
                    ChangeSetName: !Sub ${ProjectName}-production-ChangeSet
                - Name: Frankfurt-ExecuteChangeSet
                  RunOrder: 2
                  Region: eu-central-1
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_EXECUTE
                    RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-production
                    ChangeSetName: !Sub ${ProjectName}-production-ChangeSet
            - !Ref AWS::NoValue

In der 1 Aktion erstelle ich einen Änderungssatz. In der zweiten Aktion führe ich ihn aus. Bitte beachten Sie den hier verwendeten RoleArn. Sie können auch eine Rolle aus einem anderen Konto angeben. So können Sie ein separates Konto für verschiedene Umgebungen verwenden. Sie könnten die Pipeline zum Beispiel in einem Bereitstellungskonto hosten. Und separate Konten für Entwicklung, Test, Abnahme und Produktion haben.

Der Feature-Zweig

Wir haben jetzt also eine funktionierende Pipeline für die Produktionsumgebung. Wie sieht es mit dem Feature-Zweig aus? Hierfür verwenden wir wieder die Bedingungen.

          - !If
            - IsFeatureBranchPipeline
            - Name: FeatureDevelopment
              Actions:
                - Name: Ireland-CreateChangeSet
                  RunOrder: 1
                  Region: eu-west-1
                  InputArtifacts:
                    - Name: BuildArtifactAsZip
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_REPLACE
                    RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-${FeatureName}
                    ChangeSetName: !Sub ${ProjectName}-feature-ChangeSet
                    TemplatePath: BuildArtifactAsZip::packaged-template.yaml
                    Capabilities: CAPABILITY_NAMED_IAM
                    ParameterOverrides: |
                      {
                        "EnvType": "development"
                      }
                - Name: Ireland-ExecuteChangeSet
                  RunOrder: 2
                  Region: eu-west-1
                  ActionTypeId:
                    Category: Deploy
                    Owner: AWS
                    Provider: CloudFormation
                    Version: "1"
                  Configuration:
                    ActionMode: CHANGE_SET_EXECUTE
                    RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cloudformation-execution-role
                    StackName: !Sub ${ProjectName}-${FeatureName}
                    ChangeSetName: !Sub ${ProjectName}-feature-ChangeSet
            - !Ref AWS::NoValue

Wie Sie sehen können, wird der Funktionszweig nur in der Region eu-west-1 bereitgestellt. Und er hat den Parameter EnvType auf development gesetzt.

Neue Übertragungen abholen

Wenn Sie Ihre Commits in das CodeCommit-Repository übertragen. Sie können eine Ereignisregel verwenden, um eine neue Pipeline-Ausführung auszulösen. Dazu benötigen wir eine IAM-Rolle und die Regel selbst.

CloudWatchEventRole:
   Type: AWS::IAM::Role
   Properties:
     AssumeRolePolicyDocument:
       Version: '2012-10-17'
       Statement:
       - Effect: Allow
         Principal: { Service: events.amazonaws.com }
         Action: sts:AssumeRole
     Policies:
       - PolicyName: root
         PolicyDocument:
           Version: '2012-10-17'
           Statement:
             - Action: codepipeline:StartPipelineExecution
               Resource: !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
               Effect: Allow

CloudWatchEventRule:
  Type: AWS::Events::Rule
  Properties:
    Description: Check CodeCommit Repo Changes
    EventPattern:
      detail-type:
        - "CodeCommit Repository State Change"
      source:
        - aws.codecommit
      resources:
        - !Sub arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${ProjectName}
      detail:
        event:
          anything-but:
            - referenceDeleted
        referenceType:
          - branch
        referenceName:
          - !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, "main"]
    Targets:
      - Id: codepipeline
        Arn: !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
        RoleArn: !Sub ${CloudWatchEventRole.Arn}

Wir lösen bei jedem Ereignis aus, außer wenn der Zweig entfernt wird.

Fazit

Sie können die Vorlage für die Pipeline in Ihrem CodeCommit-Repository speichern. Wenn Sie einen Feature-Zweig erstellen, können Sie diese Vorlage unter Angabe des Zweignamens bereitstellen. Die Pipeline kann dann die CloudFormation-Vorlage des Projekts bereitstellen. Und mit jeder Übertragung, die Sie durchführen, wird Ihre Funktionsumgebung aktualisiert.

Mit dieser Einrichtung haben Sie alles in einem einzigen Repository. (Mit Ausnahme des gemeinsamen S3-Buckets und der IAM-Rolle.) Da sich alles in einem einzigen Repository befindet, ist es einfacher zu pflegen.

Verfasst von

Joris Conijn

Joris is the AWS Practise CTO of the Xebia Cloud service line and has been working with the AWS cloud since 2009 and focussing on building event-driven architectures. While working with the cloud from (almost) the start, he has seen most of the services being launched. Joris strongly believes in automation and infrastructure as code and is open to learning new things and experimenting with them because that is the way to learn and grow.

Contact

Let’s discuss how we can support your journey.