Layer-2-Konstrukte - AWS Präskriptive Leitlinien

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.

Layer-2-Konstrukte

Das AWS CDK Open-Source-Repository wurde hauptsächlich in der TypeScriptProgrammiersprache geschrieben und besteht aus zahlreichen Paketen und Modulen. Die Hauptpaketbibliothek, genanntaws-cdk-lib, ist grob in ein Paket pro AWS Dienst aufgeteilt, obwohl dies nicht immer der Fall ist. Wie bereits erwähnt, werden die L1-Konstrukte während des Build-Prozesses automatisch generiert. Was ist also der ganze Code, den Sie sehen, wenn Sie in das Projektarchiv schauen? Das sind L2-Konstrukte, die Abstraktionen von L1-Konstrukten sind.

Die Pakete enthalten auch eine Sammlung von TypeScript Typen, Aufzählungen und Schnittstellen sowie Hilfsklassen, die mehr Funktionalität hinzufügen, aber diese Elemente dienen alle L2-Konstrukten. Alle L2-Konstrukte rufen bei der Instanziierung ihre entsprechenden L1-Konstrukte in ihren Konstruktoren auf, und auf das resultierende L1-Konstrukt, das erstellt wird, kann von Schicht 2 aus wie folgt zugegriffen werden:

const role = new Bucket(this, "amzn-s3-demo-bucket", {/*...BucketProps*/}); const cfnBucket = role.node.defaultChild;

Das L2-Konstrukt verwendet die Standardeigenschaften, praktischen Methoden und andere syntaktische Merkmale und wendet sie auf das L1-Konstrukt an. Dadurch entfällt ein Großteil der Wiederholungen und der Ausführlichkeit, die für die direkte Bereitstellung von Ressourcen erforderlich sind. CloudFormation

Alle L2-Konstrukte bauen ihre entsprechenden L1-Konstrukte unter der Haube auf. L2-Konstrukte erweitern L1-Konstrukte jedoch nicht wirklich. Sowohl L1- als auch L2-Konstrukte erben eine spezielle Klasse namens Construct. In Version 1 der Construct Klasse war sie in AWS CDK das Entwicklungskit integriert, aber in Version 2 ist sie ein separates eigenständiges Paket. Auf diese Weise können andere Pakete wie das Cloud Development Kit for Terraform (CDKTF) es als Abhängigkeit enthalten. Jede Klasse, die die Klasse erbt, ist ein L1-, L2- oder L3-Konstrukt. Construct L2-Konstrukte erweitern diese Klasse direkt, wohingegen L1-Konstrukte eine CfnResource aufgerufene Klasse erweitern, wie in der folgenden Tabelle dargestellt.

L1-Vererbungsbaum

L2-Vererbungsbaum

L1-Konstrukt

→ Klasse CfnResource

→ abstrakte Klasse CfnRefElement

→→ abstrakte Klasse CfnElement

→→→ Klasse Construct

L2-Konstrukt

→ Klassenkonstrukt

Wenn sowohl L1- als auch L2-Konstrukte die Construct Klasse erben, warum erweitern L2-Konstrukte dann nicht einfach L1? Nun, die Klassen zwischen der Construct Klasse und Ebene 1 fixieren das L1-Konstrukt als Spiegelbild der Ressource. CloudFormation Sie enthalten abstrakte Methoden (Methoden, die nachgelagerte Klassen enthalten müssen)_toCloudFormation, was das Konstrukt zwingt, CloudFormation Syntax direkt auszugeben. L2-Konstrukte überspringen diese Klassen und erweitern die Construct Klasse direkt. Dies gibt ihnen die Flexibilität, einen Großteil des für L1-Konstrukte benötigten Codes zu abstrahieren, indem sie sie separat innerhalb ihrer Konstruktoren erstellen.

Im vorherigen Abschnitt wurde ein S3-Bucket aus einer CloudFormation Vorlage und derselbe S3-Bucket side-by-side verglichen, der als L1-Konstrukt gerendert wurde. Dieser Vergleich ergab, dass die Eigenschaften und die Syntax nahezu identisch sind und das L1-Konstrukt im Vergleich zum Konstrukt nur drei oder vier Zeilen einspart. CloudFormation Vergleichen wir nun das L1-Konstrukt mit dem L2-Konstrukt für denselben S3-Bucket:

L1-Konstrukt für S3-Bucket

L2-Konstrukt für S3-Bucket

new CfnBucket(this, "amzns3demobucket", { bucketName: "amzn-s3-demo-bucket", bucketEncryption: { serverSideEncryptionConfiguration: [ { serverSideEncryptionByDefault: { sseAlgorithm: "AES256" } } ] }, metricsConfigurations: [ { id: "myConfig" } ], ownershipControls: { rules: [ { objectOwnership: "BucketOwnerPreferred" } ] }, publicAccessBlockConfiguration: { blockPublicAcls: true, blockPublicPolicy: true, ignorePublicAcls: true, restrictPublicBuckets: true }, versioningConfiguration: { status: "Enabled" } });
new Bucket(this, "amzns3demobucket", { bucketName: "amzn-s3-demo-bucket", encryption: BucketEncryption.S3_MANAGED, metrics: [ { id: "myConfig" }, ], objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, versioned: true });

Wie Sie sehen können, ist das L2-Konstrukt weniger als halb so groß wie das L1-Konstrukt. L2-Konstrukte verwenden zahlreiche Techniken, um diese Konsolidierung zu erreichen. Einige dieser Techniken gelten für ein einzelnes L2-Konstrukt, andere können jedoch für mehrere Konstrukte wiederverwendet werden, sodass sie aus Gründen der Wiederverwendbarkeit in ihre eigene Klasse aufgeteilt werden. L2-Konstrukte konsolidieren die CloudFormation Syntax auf verschiedene Weise, wie in den folgenden Abschnitten beschrieben.

Standardeigenschaften

Die einfachste Methode, den Code für die Bereitstellung einer Ressource zu konsolidieren, besteht darin, die gängigsten Eigenschaftseinstellungen in Standardwerte umzuwandeln. Der AWS CDK hat Zugriff auf leistungsstarke Programmiersprachen und CloudFormation hat keinen. Daher sind diese Standardwerte oft bedingt. Manchmal können mehrere CloudFormation Konfigurationszeilen aus dem AWS CDK Code entfernt werden, da diese Einstellungen aus den Werten anderer Eigenschaften abgeleitet werden können, die an das Konstrukt übergeben werden.

Strukturen, Typen und Schnittstellen

Obwohl der in mehreren Programmiersprachen verfügbar AWS CDK ist, ist er nativ geschrieben TypeScript, sodass das Typsystem dieser Sprache verwendet wird, um die Typen zu definieren, aus denen L2-Konstrukte bestehen. Ein tiefer Einblick in dieses Typsystem würde den Rahmen dieses Handbuchs sprengen. Einzelheiten finden Sie in der TypeScriptDokumentation. Zusammenfassend TypeScript type beschreibt a, welche Art von Daten eine bestimmte Variable enthält. Dies können Basisdaten wie a string oder komplexere Daten wie ein object sein. A TypeScript interface ist eine andere Art, den TypeScript Objekttyp auszudrücken, und a struct ist ein anderer Name für eine Schnittstelle.

TypeScript verwendet den Begriff Struktur nicht, aber wenn Sie in der AWS CDK API-Referenz nachschauen, werden Sie feststellen, dass eine Struktur eigentlich nur eine weitere TypeScript Schnittstelle innerhalb des Codes ist. In der API-Referenz werden auch bestimmte Schnittstellen als Schnittstellen bezeichnet. Wenn Strukturen und Schnittstellen dasselbe sind, warum unterscheidet die AWS CDK Dokumentation dann zwischen ihnen?

Was als Strukturen AWS CDK bezeichnet wird, sind Schnittstellen, die jedes Objekt repräsentieren, das von einem L2-Konstrukt verwendet wird. Dazu gehören die Objekttypen für die Eigenschaftsargumente, die während der Instanziierung an das L2-Konstrukt übergeben werden, z. B. BucketProps für das S3-Bucket-Konstrukt und TableProps für das DynamoDB-Tabellenkonstrukt, sowie andere TypeScript Schnittstellen, die innerhalb von verwendet werden. AWS CDKKurz gesagt, wenn es sich um eine TypeScript Schnittstelle innerhalb von handelt AWS CDK und dem Namen kein Buchstabe vorangestellt wirdI, wird sie als Struktur bezeichnet. AWS CDK

Umgekehrt AWS CDK verwendet er den Begriff Interface, um die Basiselemente darzustellen, sodass ein einfaches Objekt als richtige Repräsentation eines bestimmten Konstrukts oder einer bestimmten Hilfsklasse betrachtet werden müsste. Das heißt, eine Schnittstelle beschreibt, was die öffentlichen Eigenschaften eines L2-Konstrukts sein müssen. Alle AWS CDK Schnittstellennamen sind die Namen vorhandener Konstrukte oder Hilfsklassen, denen der Buchstabe vorangestellt ist. I Alle L2-Konstrukte erweitern die Construct Klasse, implementieren aber auch ihre entsprechende Schnittstelle. Das L2-Konstrukt Bucket implementiert also die Schnittstelle. IBucket

Statische Methoden

Jede Instanz eines L2-Konstrukts ist auch eine Instanz der entsprechenden Schnittstelle, aber das Gegenteil ist nicht der Fall. Dies ist wichtig, wenn Sie eine Struktur durchsehen, um zu sehen, welche Datentypen erforderlich sind. Wenn für eine Struktur eine Eigenschaft aufgerufen wirdbucket, die den Datentyp erfordertIBucket, können Sie entweder ein Objekt übergeben, das die in der IBucket Schnittstelle aufgelisteten Eigenschaften enthält, oder eine Instanz eines Bucket L2-Objekts. Beides würde funktionieren. Wenn diese bucket Eigenschaft jedoch ein L2 erfordertBucket, könnten Sie nur eine Bucket Instanz in diesem Feld übergeben.

Diese Unterscheidung wird sehr wichtig, wenn Sie bereits vorhandene Ressourcen in Ihren Stack importieren. Sie können ein L2-Konstrukt für jede Ressource erstellen, die Ihrem Stack eigen ist. Wenn Sie jedoch auf eine Ressource verweisen müssen, die außerhalb des Stacks erstellt wurde, müssen Sie die Schnittstelle dieses L2-Konstrukts verwenden. Das liegt daran, dass beim Erstellen eines L2-Konstrukts eine neue Ressource erstellt wird, falls noch keine in diesem Stapel vorhanden ist. Verweise auf bestehende Ressourcen müssen einfache Objekte sein, die der Schnittstelle dieses L2-Konstrukts entsprechen.

Um dies in der Praxis zu vereinfachen, sind den meisten L2-Konstrukten eine Reihe von statischen Methoden zugeordnet, die die Schnittstelle des L2-Konstrukts zurückgeben. Diese statischen Methoden beginnen normalerweise mit dem Wort. from Die ersten beiden Argumente, die an diese Methoden übergeben werden, sind dieselben scope und die id Argumente, die für ein Standard-L2-Konstrukt erforderlich sind. Das dritte Argument ist jedoch nicht, props sondern eine kleine Teilmenge von Eigenschaften (oder manchmal nur eine Eigenschaft), die eine Schnittstelle definiert. Aus diesem Grund sind bei der Übergabe eines L2-Konstrukts in den meisten Fällen nur die Elemente der Schnittstelle erforderlich. Auf diese Weise können Sie nach Möglichkeit auch importierte Ressourcen verwenden.

// Example of referencing an external S3 bucket const preExistingBucket = Bucket.fromBucketName(this, "external-bucket", "name-of-bucket-that-already-exists");

Sie sollten sich jedoch nicht stark auf Schnittstellen verlassen. Sie sollten Ressourcen importieren und Schnittstellen nur dann direkt verwenden, wenn dies unbedingt erforderlich ist, da Schnittstellen nicht viele der Eigenschaften — wie Hilfsmethoden — bieten, die ein L2-Konstrukt so mächtig machen.

Hilfsmethoden

Ein L2-Konstrukt ist eher eine programmatische Klasse als ein einfaches Objekt, sodass es Klassenmethoden verfügbar machen kann, mit denen Sie Ihre Ressourcenkonfiguration nach der Instanziierung bearbeiten können. Ein gutes Beispiel dafür ist das L2-Rollenkonstrukt AWS Identity and Access Management (IAM). Die folgenden Ausschnitte zeigen zwei Möglichkeiten, dieselbe IAM-Rolle mithilfe des L2-Konstrukts zu erstellen. Role

Ohne eine Hilfsmethode:

const role = new Role(this, "my-iam-role", { assumedBy: new FederatedPrincipal('my-identity-provider.com'), managedPolicies: [ ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess") ], inlinePolicies: { lambdaPolicy: new PolicyDocument({ statements: [ new PolicyStatement({ effect: Effect.ALLOW, actions: [ 'lambda:UpdateFunctionCode' ], resources: [ 'arn:aws:lambda:us-east-1:123456789012:function:my-function' ] }) ] }) } });

Mit einer Hilfsmethode:

const role = new Role(this, "my-iam-role", { assumedBy: new FederatedPrincipal('my-identity-provider.com') }); role.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")); role.attachInlinePolicy(new Policy(this, "lambda-policy", { policyName: "lambdaPolicy", statements: [ new PolicyStatement({ effect: Effect.ALLOW, actions: [ 'lambda:UpdateFunctionCode' ], resources: [ 'arn:aws:lambda:us-east-1:123456789012:function:my-function' ] }) ] }));

Die Möglichkeit, Instanzmethoden zu verwenden, um die Ressourcenkonfiguration nach der Instanziierung zu manipulieren, gibt L2-Konstrukten viel zusätzliche Flexibilität gegenüber der vorherigen Schicht. L1-Konstrukte erben auch einige Ressourcenmethoden (z. B.addPropertyOverride), aber erst auf Ebene zwei erhalten Sie Methoden, die speziell für diese Ressource und ihre Eigenschaften entwickelt wurden.

Aufzählungen

CloudFormation Bei der Syntax müssen Sie häufig viele Details angeben, um eine Ressource ordnungsgemäß bereitzustellen. Die meisten Anwendungsfälle werden jedoch häufig nur durch eine Handvoll Konfigurationen abgedeckt. Die Darstellung dieser Konfigurationen mithilfe einer Reihe von Aufzählungswerten kann den benötigten Codeaufwand erheblich reduzieren.

Im S3-Bucket-L2-Codebeispiel von weiter oben in diesem Abschnitt müssen Sie beispielsweise die bucketEncryption Eigenschaft der CloudFormation Vorlage verwenden, um alle Details anzugeben, einschließlich des Namens des zu verwendenden Verschlüsselungsalgorithmus. Stattdessen AWS CDK stellt das BucketEncryption Enum bereit, das die fünf gängigsten Formen der Bucket-Verschlüsselung verwendet und es Ihnen ermöglicht, jede mit einzelnen Variablennamen auszudrücken.

Was ist mit den Randfällen, die nicht von den Aufzählungen abgedeckt werden? Eines der Ziele eines L2-Konstrukts besteht darin, die Bereitstellung einer Layer-1-Ressource zu vereinfachen, sodass bestimmte Randfälle, die weniger häufig verwendet werden, in Schicht 2 möglicherweise nicht unterstützt werden. Um diese Randfälle zu unterstützen, AWS CDK können Sie die zugrunde liegenden CloudFormation Ressourceneigenschaften mithilfe der addPropertyOverrideMethode direkt bearbeiten. Weitere Informationen zu Eigenschaftsüberschreibungen finden Sie im Abschnitt Bewährte Methoden in diesem Handbuch und im Abschnitt Abstraktionen und Notstriche in der Dokumentation. AWS CDK

Hilfsklassen

Manchmal kann eine Aufzählung nicht die programmatische Logik erfüllen, die zur Konfiguration einer Ressource für einen bestimmten Anwendungsfall erforderlich ist. In diesen Situationen bietet der AWS CDK oft stattdessen eine Hilfsklasse an. Eine Aufzählung ist ein einfaches Objekt, das eine Reihe von Schlüssel-Wert-Paaren bietet, wohingegen eine Hilfsklasse alle Funktionen einer Klasse bietet. TypeScript Eine Hilfsklasse kann sich immer noch wie eine Aufzählung verhalten, indem sie statische Eigenschaften verfügbar macht, aber die Werte dieser Eigenschaften könnten dann intern mit bedingter Logik im Hilfsklassenkonstruktor oder in einer Hilfsmethode festgelegt werden.

Die BucketEncryption Enumeration kann also zwar die Menge an Code reduzieren, die benötigt wird, um einen Verschlüsselungsalgorithmus für einen S3-Bucket einzurichten, aber dieselbe Strategie würde nicht für die Festlegung von Zeitdauern funktionieren, da einfach zu viele mögliche Werte zur Auswahl stehen. Das Erstellen einer Aufzählung für jeden Wert wäre weitaus aufwändiger als es wert ist. Aus diesem Grund wird eine Hilfsklasse für die standardmäßigen S3 Object Lock-Konfigurationseinstellungen eines S3-Buckets verwendet, wie sie durch die ObjectLockRetentionKlasse dargestellt werden. ObjectLockRetentionenthält zwei statische Methoden: eine für die Aufbewahrung von Vorschriften und die andere für die Aufbewahrung der Unternehmensführung. Beide Methoden verwenden eine Instanz der Duration-Hilfsklasse als Argument, um die Zeitspanne auszudrücken, für die die Sperre konfiguriert werden soll.

Ein anderes Beispiel ist die AWS Lambda Hilfsklasse Runtime. Auf den ersten Blick könnte es so aussehen, als könnten die mit dieser Klasse verknüpften statischen Eigenschaften durch eine Aufzählung behandelt werden. Unter der Haube stellt jedoch jeder Eigenschaftswert eine Instanz der Runtime Klasse selbst dar, sodass die im Konstruktor der Klasse ausgeführte Logik nicht innerhalb einer Aufzählung erreicht werden konnte.