View a markdown version of this page

Referenz zum Integrationsmodell - AWS CodePipeline

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Referenz zum Integrationsmodell

Es gibt mehrere vorgefertigte Integrationen für Dienste von Drittanbietern, mit denen bestehende Kundentools in den Pipeline-Release-Prozess integriert werden können. Partner oder Drittanbieter verwenden ein Integrationsmodell, um Aktionstypen zur Verwendung in zu implementieren. CodePipeline

Verwenden Sie diese Referenz, wenn Sie Aktionstypen planen oder mit ihnen arbeiten, die mit einem unterstützten Integrationsmodell in verwaltet werden CodePipeline.

Um Ihren Drittanbieter-Aktionstyp als Partnerintegration mit zu zertifizieren CodePipeline, verweisen Sie auf das AWS Partnernetzwerk (APN). Diese Informationen sind eine Ergänzung zur Referenz. AWS CLI

Wie funktionieren Aktionstypen von Drittanbietern mit dem Integrator

Sie können Aktionstypen von Drittanbietern zu Kunden-Pipelines hinzufügen, um Aufgaben im Zusammenhang mit Kundenressourcen abzuschließen. Der Integrator verwaltet Jobanfragen und führt die Aktion mit aus. CodePipeline Das folgende Diagramm zeigt einen Aktionstyp eines Drittanbieters, der für Kunden zur Verwendung in ihrer Pipeline erstellt wurde. Nachdem der Kunde die Aktion konfiguriert hat, wird die Aktion ausgeführt und es werden Jobanfragen erstellt, die von der Action Engine des Integrators bearbeitet werden.

Das Bild zeigt, wie Aktionstypen und Artefakte von Drittanbietern von der Action Engine des Integrators verarbeitet werden

Das Diagramm zeigt die folgenden Schritte:

  1. Die Aktionsdefinition wird registriert und in verfügbar gemacht CodePipeline. Die Drittanbieter-Aktion ist für Kunden des Drittanbieters verfügbar.

  2. Der Kunde des Anbieters wählt und konfiguriert die Aktion in CodePipeline.

  3. Die Aktion wird ausgeführt und die Jobs werden in die Warteschlange gestellt. CodePipeline Wenn der Job fertig ist CodePipeline, wird eine Job-Anfrage gesendet.

  4. Der Integrator (der Job-Worker für Polling-APIs von Drittanbietern oder die Lambda-Funktion) nimmt die Jobanfrage entgegen, gibt eine Bestätigung zurück und bearbeitet die Artefakte für die Aktionen.

  5. Der Integrator gibt eine success/failure Ausgabe mit einem Auftragsergebnis und einem Fortsetzungstoken zurück (der Job-Worker verwendet success/failure APIs oder die Lambda-Funktion sendet die success/failure Ausgabe).

Hinweise zu den Schritten, mit denen Sie einen Aktionstyp anfordern, anzeigen und aktualisieren können, finden Sie unter. Mit Aktionstypen arbeiten

Konzepte

In diesem Abschnitt werden die folgenden Begriffe für Aktionstypen von Drittanbietern verwendet:

Aktionstyp

Ein wiederholbarer Prozess, der in Pipelines wiederverwendet werden kann, die dieselben Continuous Delivery-Workloads ausführen. Aktionstypen werden durch einOwner, Category und gekennzeichnet. Provider Version Beispiel:

{ "Category": "Deploy", "Owner": "AWS", "Provider": "CodeDeploy", "Version": "1" },

Alle Aktionen desselben Typs haben dieselbe Implementierung.

Action

Eine einzelne Instanz eines Aktionstyps, einer der diskreten Prozesse, die innerhalb einer Phase einer Pipeline ablaufen. Dazu gehören in der Regel die Benutzerwerte, die für die Pipeline spezifisch sind, in der diese Aktion ausgeführt wird.

Definition der Aktion

Das Schema für einen Aktionstyp, das die Eigenschaften definiert, die für die Konfiguration der Aktion und der input/output Artefakte erforderlich sind.

Aktionsausführung

Eine Sammlung von Aufträgen, die ausgeführt wurden, um festzustellen, ob die Aktion in der Pipeline des Kunden erfolgreich war oder nicht.

Engine zur Ausführung von Aktionen

Eine Eigenschaft der Aktionsausführungskonfiguration, die den Integrationstyp definiert, der von einem Aktionstyp verwendet wird. Gültige Werte sind JobWorker und Lambda.

Integration

Beschreibt eine Software, die von einem Integrator zur Implementierung eines Aktionstyps ausgeführt wird. CodePipeline unterstützt zwei Integrationstypen, die den beiden unterstützten Action Engines JobWorker und Lambda entsprechen.

Integrator

Die Person, der die Implementierung eines Aktionstyps gehört.

Aufgabe

Ein Stück Arbeit mit Pipeline und Kundenkontext zur Ausführung einer Integration. Eine Aktionsausführung besteht aus einem oder mehreren Aufträgen.

Beruf: Arbeiter

Der Dienst, der die Kundeneingaben verarbeitet und einen Job ausführt.

Unterstützte Integrationsmodelle

CodePipeline hat zwei Integrationsmodelle:

  • Lambda-Integrationsmodell: Dieses Integrationsmodell ist die bevorzugte Methode, um mit Aktionstypen zu arbeiten. CodePipeline Das Lambda-Integrationsmodell verwendet eine Lambda-Funktion, um Jobanfragen zu verarbeiten, wenn Ihre Aktion ausgeführt wird.

  • Jobworker-Integrationsmodell: Das Job Worker-Integrationsmodell ist das zuvor verwendete Modell für Integrationen von Drittanbietern. Das Jobworker-Integrationsmodell verwendet einen Job Worker, der so konfiguriert ist, dass er die CodePipeline APIs kontaktiert, um Jobanfragen zu verarbeiten, wenn Ihre Aktion ausgeführt wird.

Zum Vergleich werden in der folgenden Tabelle die Funktionen der beiden Modelle beschrieben:

Lambda-Integrationsmodell Integrationsmodell für Berufstätige
Beschreibung Der Integrator schreibt die Integration als Lambda-Funktion, die immer dann aufgerufen wird, CodePipeline wenn ein Job für die Aktion verfügbar ist. Die Lambda-Funktion fragt nicht nach verfügbaren Jobs ab, sondern wartet stattdessen, bis die nächste Jobanfrage eingegangen ist. Der Integrator schreibt die Integration als Jobworker, der ständig nach verfügbaren Jobs in den Pipelines des Kunden fragt. Der Jobworker führt dann den Job aus und sendet das Auftragsergebnis mithilfe von APIs an CodePipeline ihn zurück. CodePipeline
Infrastruktur AWS Lambda Stellen Sie Job Worker-Code in der Infrastruktur des Integrators bereit, z. B. in Amazon EC2-Instances.
Aufwand für die Entwicklung Die Integration enthält nur die Geschäftslogik. Die Integration muss nicht nur die Geschäftslogik enthalten, sondern auch mit CodePipeline APIs interagieren.
Aufwand der Operation Geringerer operativer Aufwand, da die Infrastruktur nur aus AWS Ressourcen besteht. Höherer operativer Aufwand, da der Mitarbeiter seine eigenständige Hardware benötigt.
Max. Job-Laufzeit Wenn die Integration länger als 15 Minuten aktiv ausgeführt werden muss, kann dieses Modell nicht verwendet werden. Diese Aktion richtet sich an Integratoren, die einen Prozess starten (z. B. einen Build auf dem Code-Artefakt des Kunden initiieren) und nach dessen Abschluss ein Ergebnis zurückgeben müssen. Wir empfehlen nicht, dass der Integrator weiter darauf wartet, dass der Build abgeschlossen ist. Geben Sie stattdessen eine Fortsetzung zurück. CodePipelineerstellt in weiteren 30 Sekunden einen neuen Job, wenn eine Fortsetzung vom Code des Integrators eingeht, um den Job zu überprüfen, bis er abgeschlossen ist. Jobs (hours/days) mit sehr langer Laufzeit können mit diesem Modell aufrechterhalten werden.

Lambda-Integrationsmodell

Das unterstützte Lambda-Integrationsmodell umfasst die Erstellung der Lambda-Funktion und die Definition der Ausgabe für den Aktionstyp des Drittanbieters.

Aktualisieren Sie Ihre Lambda-Funktion, um die Eingabe von zu verarbeiten CodePipeline

Sie können eine neue Lambda-Funktion erstellen. Sie können Ihrer Lambda-Funktion Geschäftslogik hinzufügen, die immer dann ausgeführt wird, wenn in Ihrer Pipeline ein Job für Ihren Aktionstyp verfügbar ist. Angesichts des Kontextes des Kunden und der Pipeline möchten Sie beispielsweise möglicherweise mit einer Erweiterung Ihres Service für den Kunden beginnen.

Verwenden Sie die folgenden Parameter, um Ihre Lambda-Funktion so zu aktualisieren, dass sie die Eingabe von CodePipeline verarbeitet.

Format:

  • jobId:

    • Die eindeutige, vom System generierte ID des Jobs.

    • Typ: Zeichenfolge

    • Muster: [0-9a-f] {8} - [0-9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12}

  • accountId:

    • Die ID des AWS Kundenkontos, das bei der Ausführung des Auftrags verwendet werden soll.

    • Typ: Zeichenfolge

    • Muster: [0-9] {12}

  • data:

    • Andere Informationen zu einem Job, die eine Integration verwendet, um den Job abzuschließen.

    • Enthält eine Karte mit den folgenden Elementen:

      • actionConfiguration:

        • Die Konfigurationsdaten für die Aktion. Die Felder für die Aktionskonfiguration sind eine Zuordnung von Schlüssel-Wert-Paaren, die Ihr Kunde zur Eingabe von Werten benötigt. Die Schlüssel werden durch die Schlüsselparameter in der Aktionstyp-Definitionsdatei bestimmt, wenn Sie Ihre Aktion einrichten. In diesem Beispiel werden die Werte vom Benutzer der Aktion bestimmt, der Informationen in den Password Feldern Username und angibt.

        • Typ: Zuordnung von Zeichenfolge zu Zeichenfolge, optional vorhanden

          Beispiel:

          "configuration": { "Username": "MyUser", "Password": "MyPassword" },
      • encryptionKey:

        • Stellt Informationen über den Schlüssel dar, der zum Verschlüsseln von Daten im Artefaktspeicher verwendet wird, z. B. einen AWS KMS Schlüssel.

        • Inhalt: Typ des DatentypsencryptionKey, optional vorhanden

      • inputArtifacts:

        • Liste mit Informationen über ein Artefakt, an dem gearbeitet werden soll, z. B. ein Test- oder Build-Artefakt.

        • Inhalt: Liste des DatentypsArtifact, optional vorhanden

      • outputArtifacts:

        • Liste von Informationen über die Ausgabe einer Aktion.

        • Inhalt: Liste des DatentypsArtifact, optional vorhanden

      • actionCredentials:

        • Stellt ein Objekt mit AWS Sitzungsanmeldeinformationen dar. Diese Anmeldeinformationen sind temporäre Anmeldeinformationen, die von ausgestellt werden AWS STS. Sie können verwendet werden, um auf Eingabe- und Ausgabeartefakte im S3-Bucket zuzugreifen, in dem Artefakte für die Pipeline gespeichert werden CodePipeline.

          Diese Anmeldeinformationen verfügen außerdem über dieselben Berechtigungen wie die angegebene Vorlage für Richtlinienerklärungen in der Definitionsdatei für den Aktionstyp.

        • Inhalt: Typ des DatentypsAWSSessionCredentials, optional vorhanden

      • actionExecutionId:

        • Die externe ID der Ausführung der Aktion.

        • Typ: Zeichenfolge

      • continuationToken:

        • Ein vom System generiertes Token, z. B. eine Bereitstellungs-ID, das von einem Job benötigt wird, um den Job asynchron fortzusetzen.

        • Typ: Zeichenfolge, optional vorhanden

Datentypen:

  • encryptionKey:

    • id:

      • Die ID, die verwendet wurde, um den Schlüssel zu identifizieren. Für einen AWS KMS Schlüssel können Sie die Schlüssel-ID, den Schlüssel-ARN oder den Alias-ARN verwenden.

      • Typ: Zeichenfolge

    • type:

      • Der Typ des Verschlüsselungsschlüssels, z. B. ein AWS KMS Schlüssel.

      • Typ: Zeichenfolge

      • Zulässige Werte: KMS

  • Artifact:

    • name:

      • Der Name des Artefakts.

      • Typ: Zeichenfolge, optional vorhanden

    • revision:

      • Die Revisions-ID des Artefakts. Je nach Art des Objekts kann dies eine Commit-ID (GitHub) oder eine Revisions-ID (Amazon S3) sein.

      • Typ: Zeichenfolge, optional vorhanden

    • location:

      • Die Position eines Artefakts.

      • Inhalt: Typ des DatentypsArtifactLocation, optional vorhanden

  • ArtifactLocation:

    • type:

      • Die Art des Artefakts an der Position.

      • Typ: Zeichenfolge, optional vorhanden

      • Zulässige Werte: S3

    • s3Location:

      • Der Speicherort des S3-Buckets, der eine Revision enthält.

      • Inhalt: Typ des DatentypsS3Location, optional vorhanden

  • S3Location:

    • bucketName:

      • Der Name des S3-Buckets.

      • Typ: Zeichenfolge

    • objectKey:

      • Der Schlüssel des Objekts im S3-Bucket, der das Objekt im Bucket eindeutig identifiziert.

      • Typ: Zeichenfolge

  • AWSSessionCredentials:

    • accessKeyId:

      • Der Zugriffsschlüssel für die Sitzung.

      • Typ: Zeichenfolge

    • secretAccessKey:

      • Der geheime Zugriffsschlüssel für die Sitzung.

      • Typ: Zeichenfolge

    • sessionToken:

      • Das Token für die Sitzung.

      • Typ: Zeichenfolge

Beispiel:

{ "jobId": "01234567-abcd-abcd-abcd-012345678910", "accountId": "012345678910", "data": { "actionConfiguration": { "key1": "value1", "key2": "value2" }, "encryptionKey": { "id": "123-abc", "type": "KMS" }, "inputArtifacts": [ { "name": "input-art-name", "location": { "type": "S3", "s3Location": { "bucketName": "inputBucket", "objectKey": "inputKey" } } } ], "outputArtifacts": [ { "name": "output-art-name", "location": { "type": "S3", "s3Location": { "bucketName": "outputBucket", "objectKey": "outputKey" } } } ], "actionExecutionId": "actionExecutionId", "actionCredentials": { "accessKeyId": "access-id", "secretAccessKey": "secret-id", "sessionToken": "session-id" }, "continuationToken": "continueId-xxyyzz" } }

Geben Sie die Ergebnisse Ihrer Lambda-Funktion zurück an CodePipeline

Die Jobworker-Ressource des Integrators muss bei Erfolg, Misserfolg oder Fortsetzung eine gültige Nutzlast zurückgeben.

Format:

  • result: Das Ergebnis des Jobs.

    • Erforderlich

    • Gültige Werte (Groß- und Kleinschreibung wird nicht beachtet):

      • Success: Zeigt an, dass ein Job erfolgreich und abgeschlossen ist.

      • Continue: Zeigt an, dass ein Job erfolgreich war und fortgesetzt werden muss, z. B. wenn der Job Worker für dieselbe Aktionsausführung erneut aufgerufen wird.

      • Fail: Zeigt an, dass ein Job fehlgeschlagen ist und abgeschlossen ist.

  • failureType: Ein Fehlertyp, der einem fehlgeschlagenen Job zugeordnet werden soll.

    Die failureType Kategorie für Partneraktionen beschreibt die Art des Fehlers, der bei der Ausführung des Jobs aufgetreten ist. Integratoren legen den Typ zusammen mit der Fehlermeldung fest, wenn das Ergebnis eines Auftragsfehlers an CodePipeline zurückgegeben wird.

    • Optional. Erforderlich, wenn das Fail Ergebnis

    • Muss Null sein, result wenn Success oder Continue

    • Zulässige Werte:

      • ConfigurationError

      • JobFailed

      • PermissionsError

      • RevisionOutOfSync

      • RevisionUnavailable

      • SystemUnavailable

  • continuation: Fortsetzungsstatus, der an den nächsten Job innerhalb der aktuellen Aktionsausführung übergeben werden soll.

    • Optional. Erforderlich, wenn das Ergebnis istContinue.

    • Muss Null sein, wenn Success oder result istFail.

    • Eigenschaften:

      • State: Ein Hash des Zustands, der übergeben werden soll.

  • status: Status der Aktionsausführung.

    • Optional.

    • Eigenschaften:

      • ExternalExecutionId: Eine optionale externe Ausführungs-ID oder Commit-ID, die dem Job zugeordnet werden soll.

      • Summary: Eine optionale Zusammenfassung dessen, was passiert ist. In Fehlerszenarien wird dies die Fehlermeldung, die dem Benutzer angezeigt wird.

  • outputVariables: Eine Reihe von key/value Paaren, die an die nächste Aktionsausführung übergeben werden.

    • Optional.

    • Muss Null sein, wenn Continue oder result istFail.

Beispiel:

{ "result": "success", "failureType": null, "continuation": null, "status": { "externalExecutionId": "my-commit-id-123", "summary": "everything is dandy" }, "outputVariables": { "FirstOne": "Nice", "SecondOne": "Nicest", ... } }

Verwenden Sie Fortsetzungstoken, um auf Ergebnisse eines asynchronen Prozesses zu warten

Das continuation Token ist Teil der Nutzlast und des Ergebnisses Ihrer Lambda-Funktion. Es ist eine Möglichkeit, den Jobstatus an den Job zu übergeben CodePipeline und darauf hinzuweisen, dass der Job fortgesetzt werden muss. Wenn beispielsweise ein Integrator einen Build für den Kunden auf seiner Ressource gestartet hat, wartet er nicht darauf, dass der Build abgeschlossen ist, sondern weist darauf hin, CodePipeline dass kein Endergebnis vorliegt, indem er das result as zurückgibt continue und die eindeutige ID des Builds an das CodePipeline continuation as-Token zurückgibt.

Anmerkung

Lambda-Funktionen können nur bis zu 15 Minuten ausgeführt werden. Wenn der Job länger laufen muss, können Sie Fortsetzungstoken verwenden.

Das CodePipeline Team ruft den Integrator nach 30 Sekunden mit demselben continuation Token in seiner Nutzlast auf, damit es überprüfen kann, ob der Vorgang abgeschlossen ist. Wenn der Build abgeschlossen ist, gibt der Integrator das success/fail Endergebnis zurück, andernfalls fährt er fort.

Stellen Sie CodePipeline die Berechtigungen bereit, um die Lambda-Funktion des Integrators zur Laufzeit aufzurufen

Sie fügen Ihrer Integrator-Lambda-Funktion Berechtigungen hinzu, um dem CodePipeline Dienst die Berechtigungen zu geben, ihn mithilfe des Dienstprinzips aufzurufen:. CodePipeline codepipeline.amazonaws.com Sie können Berechtigungen mithilfe der Befehlszeile CloudFormation oder über die Befehlszeile hinzufügen. Ein Beispiel finden Sie unter Mit Aktionstypen arbeiten.

Integrationsmodell für Berufstätige

Nachdem Sie Ihren allgemeinen Arbeitsablauf entworfen haben, können Sie Ihren Job Worker erstellen. Obwohl die Besonderheiten der Drittanbieter-Aktion bestimmen, was für den Job-Worker benötigt wird, bieten die meisten Auftragsarbeiter für Drittanbieter-Aktionen die folgenden Funktionen:

  • Abfrage nach Aufträgen von CodePipeline Using. PollForThirdPartyJobs

  • Bestätigen von Aufträgen und Zurückgeben der Ergebnisse zur CodePipeline Verwendung von AcknowledgeThirdPartyJobPutThirdPartyJobSuccessResult, und. PutThirdPartyJobFailureResult

  • Artefakte werden abgerufen, and/or indem Artefakte für die Pipeline in den Amazon S3-Bucket eingegeben werden. Um Artefakte aus dem Amazon S3-Bucket herunterzuladen, müssen Sie einen Amazon S3-Client erstellen, der Signature Version 4-Signing (Sig V4) verwendet. Sig V4 ist erforderlich für AWS KMS.

    Um Artefakte in den Amazon S3-Bucket hochzuladen, müssen Sie auch die Amazon PutObject S3-Anfrage so konfigurieren, dass sie die Verschlüsselung über AWS Key Management Service (AWS KMS) verwendet. AWS KMS verwendet AWS KMS keys. Um zu wissen, ob der Von AWS verwalteter Schlüssel oder ein vom Kunden verwalteter Schlüssel zum Hochladen von Artefakten verwendet werden soll, muss sich Ihr Mitarbeiter die Auftragsdaten ansehen und die Eigenschaft des Verschlüsselungsschlüssels überprüfen. Wenn die Eigenschaft festgelegt ist, sollten Sie bei der Konfiguration diese vom Kunden verwaltete Schlüssel-ID verwenden AWS KMS. Wenn die Schlüsseleigenschaft Null ist, verwenden Sie die Von AWS verwalteter Schlüssel. CodePipeline verwendet den, Von AWS verwalteter Schlüssel sofern nicht anders konfiguriert.

    Ein Beispiel, das zeigt, wie die AWS KMS Parameter in Java oder.NET erstellt werden, finden Sie unter Specifying the AWS Key Management Service in Amazon S3 Using the AWS SDKs. Weitere Informationen zum Amazon S3-Bucket für finden Sie CodePipeline unterCodePipeline Konzepte.

Wählen und Konfigurieren einer Strategie für die Berechtigungsverwaltung Ihres Auftragsworkers

Um einen Job Worker für Ihre Drittanbieter-Aktion in zu entwickeln CodePipeline, benötigen Sie eine Strategie für die Integration von Benutzer- und Rechteverwaltung.

Die einfachste Strategie besteht darin, die Infrastruktur, die Sie für Ihren Job Worker benötigen, hinzuzufügen, indem Sie Amazon EC2-Instances mit einer Instance-Rolle AWS Identity and Access Management (IAM) erstellen, mit der Sie die Ressourcen, die Sie für Ihre Integration benötigen, problemlos skalieren können. Sie können die integrierte Integration mit verwenden AWS , um die Interaktion zwischen Ihrem Mitarbeiter und zu vereinfachen. CodePipeline

Erfahren Sie mehr über Amazon EC2 und finden Sie heraus, ob es die richtige Wahl für Ihre Integration ist. Informationen finden Sie unter Amazon EC2 — Virtual Server Hosting. Informationen zum Einrichten einer Amazon EC2-Instance finden Sie unter Erste Schritte mit Amazon EC2 Linux-Instances.

Eine weitere Strategie, die Sie in Betracht ziehen sollten, ist die Verwendung von Identity Federation mit IAM, um Ihr vorhandenes System und Ihre Ressourcen für Identitätsanbieter zu integrieren. Diese Strategie ist nützlich, wenn Sie bereits über einen Anbieter für Unternehmensidentitäten verfügen oder bereits so konfiguriert sind, dass Benutzer unterstützt werden, die Web-Identitätsanbieter verwenden. Mit Identity Federation können Sie sicheren Zugriff auf AWS Ressourcen gewähren CodePipeline, auch ohne IAM-Benutzer erstellen oder verwalten zu müssen. Sie können Funktionen und Richtlinien für die Sicherheitsanforderungen bezüglich Passwörtern und die Rotation von Anmeldeinformationen nutzen. Sie können Beispielanwendungen als Vorlage für Ihre selbsterstellten Anwendungen verwenden. Weitere Informationen finden Sie unter Manage Federation.

Um Zugriff zu gewähren, fügen Sie Ihren Benutzern, Gruppen oder Rollen Berechtigungen hinzu:

Im Folgenden finden Sie ein Beispiel für eine Richtlinie, die Sie zur Verwendung mit Ihrem externen Job-Mitarbeiter erstellen könnten. Diese Richtlinie dient lediglich als Beispiel und wird unverändert bereitgestellt.

JSON
{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "codepipeline:PollForThirdPartyJobs", "codepipeline:AcknowledgeThirdPartyJob", "codepipeline:GetThirdPartyJobDetails", "codepipeline:PutThirdPartyJobSuccessResult", "codepipeline:PutThirdPartyJobFailureResult" ], "Resource": [ "arn:aws:codepipeline:us-east-2::actionType:ThirdParty/Build/Provider/1/" ] } ] }