Wdrożenie bezserwerowej aplikacji z AWS CDK i Amazon Q Developer

Wdrożenie bezserwerowej aplikacji z AWS CDK i Amazon Q Developer

📅 Ostatnia aktualizacja: 3 maja 2024

🕒 Czas czytania: 12 minut


Wprowadzenie

Rozwój aplikacji w chmurze przeszedł długą drogę od ręcznego konfigurowania serwerów do nowoczesnych, bezserwerowych (serverless) architektur. AWS Cloud Development Kit (CDK) zrewolucjonizował sposób definiowania infrastruktury jako kodu (IaC), a najnowszy dodatek od AWS - Amazon Q Developer - wprowadza sztuczną inteligencję do procesów wytwarzania oprogramowania.

W tym artykule przeprowadzimy Cię przez proces wdrażania nowoczesnej aplikacji bezserwerowej z wykorzystaniem AWS CDK i Amazon Q Developer. Poznasz nie tylko podstawy architektury serverless, ale także praktyczne zastosowanie narzędzi opartych na AI do przyspieszenia cyklu rozwoju.

Czym jest architektura bezserwerowa (serverless)?

Architektura bezserwerowa to podejście do tworzenia i uruchamiania aplikacji, które eliminuje potrzebę zarządzania tradycyjnymi serwerami. Wbrew nazwie, serwery nadal istnieją - po prostu są one w pełni zarządzane przez dostawcę chmury.

Kluczowe cechy aplikacji bezserwerowych:

  1. Automatyczne skalowanie - aplikacja automatycznie dostosowuje zasoby do bieżącego obciążenia
  2. Pay-per-use - płacisz tylko za faktyczne wykorzystanie zasobów, a nie za ich bezczynne działanie
  3. Brak zarządzania serwerami - dostawca chmury zajmuje się wszystkimi aspektami zarządzania infrastrukturą
  4. Wysoka dostępność - wbudowana odporność na awarie
  5. Krótki czas wprowadzania zmian - szybsze wdrażanie nowych funkcjonalności

Główne komponenty architektury serverless w AWS:

  • AWS Lambda - usługa obliczeniowa uruchamiająca kod w odpowiedzi na zdarzenia
  • Amazon API Gateway - zarządzana usługa do tworzenia i utrzymywania API
  • DynamoDB - baza danych NoSQL
  • Amazon S3 - przechowywanie obiektów
  • Amazon EventBridge - usługa magistrali zdarzeń dla aplikacji
  • AWS Step Functions - usługa orkiestracji funkcji Lambda

AWS CDK - Infrastructure as Code na wyższym poziomie

AWS Cloud Development Kit (CDK) to framework open-source do definiowania infrastruktury w chmurze przy użyciu języków programowania, które znasz i lubisz. W przeciwieństwie do AWS CloudFormation, który używa plików YAML lub JSON, CDK pozwala definiować infrastrukturę w TypeScript, Python, Java, C# i Go.

Zalety AWS CDK:

  • Wykorzystanie znanego języka programowania - pełna moc języków programowania (zmienne, pętle, warunki)
  • Abstrakcje wysokiego poziomu - wbudowane konstrukty przyspieszające tworzenie typowych wzorców architektonicznych
  • Reużywalność kodu - możliwość tworzenia własnych konstruktów i bibliotek
  • Weryfikacja typów - wcześne wykrywanie błędów dzięki systemom typów
  • Integracja z IDE - podpowiedzi, refaktoryzacja i debugowanie
  • Automatyczna generacja CloudFormation - CDK przekształca kod w szablony CloudFormation

Podstawowe pojęcia AWS CDK:

  • App - najwyższy poziom konstruktu CDK reprezentujący całą aplikację
  • Stack - zbiór zasobów AWS, które są wdrażane jako jednostka
  • Construct - element budujący aplikacji CDK (np. funkcja Lambda, tabela DynamoDB)
  • Synthesize - proces generowania szablonu CloudFormation z kodu CDK
  • Deploy - wdrożenie wygenerowanego szablonu CloudFormation w AWS

Amazon Q Developer - AI na pomoc programistom

Amazon Q Developer (dawniej Amazon CodeWhisperer) to asystent programistyczny oparty na sztucznej inteligencji, zaprojektowany specjalnie do tworzenia aplikacji w chmurze AWS. Narzędzie to znacząco przyspiesza pracę deweloperów poprzez:

  • Generowanie kodu - tworzenie fragmentów kodu na podstawie komentarzy lub istniejącego kodu
  • Sugestie kodu w czasie rzeczywistym - propozycje uzupełniania kodu podczas pisania
  • Wykrywanie błędów bezpieczeństwa - identyfikacja potencjalnych luk i zagrożeń
  • Wyjaśnianie kodu - automatyczne dokumentowanie i wyjaśnianie złożonych fragmentów kodu
  • Rekomendacje dotyczące usług AWS - sugestie optymalnych usług AWS do konkretnych przypadków użycia

Amazon Q Developer integruje się z popularnymi środowiskami programistycznymi, takimi jak VS Code, IntelliJ IDEA, PyCharm i AWS Cloud9, oferując bezpośredni dostęp do jego możliwości podczas codziennej pracy.

Przygotowanie środowiska do pracy z AWS CDK i Amazon Q

Zanim zaczniemy tworzyć i wdrażać aplikację bezserwerową, musimy przygotować środowisko deweloperskie. Poniżej znajdziesz niezbędne kroki:

1. Instalacja niezbędnych narzędzi

# Instalacja Node.js (wymagane dla AWS CDK)
sudo apt update
sudo apt install nodejs npm

# Instalacja AWS CDK
npm install -g aws-cdk

# Weryfikacja instalacji
cdk --version

2. Konfiguracja AWS CLI

# Instalacja AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Konfiguracja poświadczeń AWS
aws configure

3. Instalacja Amazon Q Developer

Aby korzystać z Amazon Q Developer, musisz:

  1. Mieć aktywne konto AWS
  2. Zainstalować wtyczkę Amazon Q Developer dla Twojego IDE
    • Dla VS Code: wyszukaj "Amazon Q" w marketplace rozszerzeń
    • Dla IntelliJ: wyszukaj "Amazon Q" w marketplace pluginów

Po instalacji potrzebne będzie uwierzytelnienie wtyczki przy użyciu Twoich poświadczeń AWS.

Tworzenie projektu bezserwerowego z AWS CDK

Teraz, gdy nasze środowisko jest gotowe, przystąpimy do tworzenia projektu bezserwerowego przy użyciu AWS CDK. Nasz przykładowy projekt będzie prostym API do zarządzania listą zadań (todo list).

1. Inicjalizacja projektu CDK

# Utworzenie nowego katalogu projektu
mkdir todo-serverless-app
cd todo-serverless-app

# Inicjalizacja projektu CDK w TypeScript
cdk init app --language typescript

To polecenie tworzy szkielet projektu CDK z następującą strukturą:

todo-serverless-app/
├── bin/
│   └── todo-serverless-app.ts
├── lib/
│   └── todo-serverless-app-stack.ts
├── node_modules/
├── package.json
├── cdk.json
└── tsconfig.json

2. Definiowanie zasobów bezserwerowych

Otwórz plik lib/todo-serverless-app-stack.ts i zmodyfikuj go, aby zdefiniować wymagane zasoby:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as path from 'path';

export class TodoServerlessAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Tworzenie tabeli DynamoDB dla zadań
    const todoTable = new dynamodb.Table(this, 'TodoTable', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // Tylko dla środowiska dev/test
    });

    // Tworzenie funkcji Lambda do obsługi API
    const todoHandler = new lambda.Function(this, 'TodoHandler', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
      environment: {
        TODO_TABLE: todoTable.tableName,
      },
    });

    // Przyznanie uprawnień do tabeli DynamoDB dla funkcji Lambda
    todoTable.grantReadWriteData(todoHandler);

    // Utworzenie API Gateway
    const api = new apigateway.RestApi(this, 'TodoApi', {
      restApiName: 'Todo Service',
      description: 'This service manages todo items.',
    });

    // Dodanie zasobu /todos
    const todos = api.root.addResource('todos');

    // Dodanie metod HTTP
    todos.addMethod('GET', new apigateway.LambdaIntegration(todoHandler));
    todos.addMethod('POST', new apigateway.LambdaIntegration(todoHandler));

    // Dodanie zasobu /todos/{id}
    const singleTodo = todos.addResource('{id}');
    singleTodo.addMethod('GET', new apigateway.LambdaIntegration(todoHandler));
    singleTodo.addMethod('PUT', new apigateway.LambdaIntegration(todoHandler));
    singleTodo.addMethod('DELETE', new apigateway.LambdaIntegration(todoHandler));

    // Wyświetlenie URL API po wdrożeniu
    new cdk.CfnOutput(this, 'ApiUrl', { value: api.url });
  }
}

3. Tworzenie kodu Lambda z pomocą Amazon Q Developer

Teraz musimy utworzyć kod funkcji Lambda, która będzie obsługiwać nasze API. Tutaj skorzystamy z pomocy Amazon Q Developer.

Najpierw utwórz katalog dla funkcji Lambda:

mkdir -p lambda
touch lambda/index.js

Następnie otwórz plik lambda/index.js w swoim IDE z zainstalowanym Amazon Q Developer. Zacznij od napisania komentarza, który opisuje, co chcesz osiągnąć:

// Create a serverless Lambda function to manage todo items using DynamoDB.
// The function should handle CRUD operations: create, read, update, delete.
// It should work with API Gateway and process different HTTP methods.

Po wprowadzeniu tego komentarza, Amazon Q Developer powinien zasugerować kod funkcji Lambda. Możesz zaakceptować sugestię lub poprosić o alternatywę. Typowy wynik mógłby wyglądać tak:

// Create a serverless Lambda function to manage todo items using DynamoDB.
// The function should handle CRUD operations: create, read, update, delete.
// It should work with API Gateway and process different HTTP methods.

const AWS = require('aws-sdk');
const { v4: uuidv4 } = require('uuid');
const dynamoDB = new AWS.DynamoDB.DocumentClient();
const TABLE_NAME = process.env.TODO_TABLE;

exports.handler = async (event) => {
  try {
    const { httpMethod, resource, pathParameters, body } = event;

    // GET /todos - List all todo items
    if (httpMethod === 'GET' && resource === '/todos') {
      const result = await dynamoDB.scan({
        TableName: TABLE_NAME
      }).promise();

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(result.Items)
      };
    }

    // GET /todos/{id} - Get a specific todo item
    if (httpMethod === 'GET' && resource === '/todos/{id}') {
      const id = pathParameters.id;
      const result = await dynamoDB.get({
        TableName: TABLE_NAME,
        Key: { id }
      }).promise();

      if (!result.Item) {
        return {
          statusCode: 404,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ message: 'Todo not found' })
        };
      }

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(result.Item)
      };
    }

    // POST /todos - Create a new todo item
    if (httpMethod === 'POST' && resource === '/todos') {
      const todoItem = JSON.parse(body);
      const id = uuidv4();
      const timestamp = new Date().toISOString();

      const newTodo = {
        id,
        timestamp,
        completed: false,
        ...todoItem
      };

      await dynamoDB.put({
        TableName: TABLE_NAME,
        Item: newTodo
      }).promise();

      return {
        statusCode: 201,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newTodo)
      };
    }

    // PUT /todos/{id} - Update a todo item
    if (httpMethod === 'PUT' && resource === '/todos/{id}') {
      const id = pathParameters.id;
      const todoItem = JSON.parse(body);

      // Check if item exists
      const existingItem = await dynamoDB.get({
        TableName: TABLE_NAME,
        Key: { id }
      }).promise();

      if (!existingItem.Item) {
        return {
          statusCode: 404,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ message: 'Todo not found' })
        };
      }

      // Update the item
      const timestamp = new Date().toISOString();
      const updatedTodo = {
        id,
        timestamp,
        ...todoItem
      };

      await dynamoDB.put({
        TableName: TABLE_NAME,
        Item: updatedTodo
      }).promise();

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updatedTodo)
      };
    }

    // DELETE /todos/{id} - Delete a todo item
    if (httpMethod === 'DELETE' && resource === '/todos/{id}') {
      const id = pathParameters.id;

      await dynamoDB.delete({
        TableName: TABLE_NAME,
        Key: { id }
      }).promise();

      return {
        statusCode: 204,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: 'Todo deleted successfully' })
      };
    }

    // If no matching operation found
    return {
      statusCode: 400,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: 'Unsupported operation' })
    };
  } catch (error) {
    console.error('Error:', error);
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: 'Internal server error', error: error.message })
    };
  }
};

Zainstalujmy teraz zależności potrzebne dla naszej funkcji Lambda:

cd lambda
npm init -y
npm install aws-sdk uuid
cd ..

4. Wdrażanie aplikacji

Po zdefiniowaniu zasobów i logiki naszej aplikacji, możemy ją wdrożyć:

# Synteza szablonu CloudFormation
cdk synth

# Inicjalizacja środowiska AWS CDK (tylko przy pierwszym użyciu CDK w danym regionie)
cdk bootstrap

# Wdrożenie aplikacji
cdk deploy

Po pomyślnym wdrożeniu, CDK wyświetli URL naszego API, który możemy używać do testowania.

Testowanie aplikacji bezserwerowej

Teraz, gdy nasza aplikacja jest wdrożona, możemy ją przetestować przy użyciu narzędzi takich jak curl, Postman lub AWS Console.

Przykładowe żądania REST API

Tworzenie nowego zadania:

curl -X POST \
  https://your-api-id.execute-api.region.amazonaws.com/prod/todos \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Ukończyć artykuł o AWS CDK",
    "description": "Napisać kompleksowy artykuł o wdrażaniu aplikacji serverless"
  }'

Pobieranie wszystkich zadań:

curl -X GET \
  https://your-api-id.execute-api.region.amazonaws.com/prod/todos

Aktualizacja zadania:

curl -X PUT \
  https://your-api-id.execute-api.region.amazonaws.com/prod/todos/task-id-from-previous-response \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Ukończyć artykuł o AWS CDK",
    "description": "Napisać kompleksowy artykuł o wdrażaniu aplikacji serverless",
    "completed": true
  }'

Usunięcie zadania:

curl -X DELETE \
  https://your-api-id.execute-api.region.amazonaws.com/prod/todos/task-id-from-previous-response

Zaawansowane funkcje Amazon Q Developer

Podczas pracy nad aplikacją bezserwerową, Amazon Q Developer może pomóc na wiele sposobów, wykraczających poza proste generowanie kodu.

1. Zapytania w języku naturalnym

Możesz zadawać Amazon Q pytania dotyczące usług AWS i otrzymywać konkretne odpowiedzi z przykładami kodu.

Przykład: "Jak dodać autoryzację do API Gateway z wykorzystaniem Amazon Cognito?"

2. Transformacja kodu

Amazon Q może pomóc w przekształcaniu kodu, na przykład z CDK v1 do CDK v2, lub z jednego języka programowania na inny.

Przykład: "Przekształć ten kod CloudFormation na CDK w TypeScript"

3. Rozbudowa funkcjonalności

Możesz poprosić Amazon Q o dodanie nowych funkcji do istniejącego kodu.

Przykład: "Dodaj paginację do skanowania DynamoDB w tej funkcji Lambda"

4. Wykrywanie problemów bezpieczeństwa

Amazon Q automatycznie skanuje Twój kod pod kątem potencjalnych problemów bezpieczeństwa, takich jak hardcoded credentials, zbyt szerokie uprawnienia IAM czy niezabezpieczone punkty końcowe API.

5. Debugging

Możesz poprosić Amazon Q o pomoc w debugowaniu problemu, podając kod i komunikat o błędzie.

Przykład: "Dlaczego ten kod Lambda zwraca błąd 'Cannot read property 'Item' of undefined'?"

Najlepsze praktyki dla architektury bezserwerowej

Aby maksymalnie wykorzystać potencjał architektury bezserwerowej i uniknąć typowych pułapek, warto przestrzegać następujących najlepszych praktyk:

1. Projektowanie funkcji Lambda

  • Pojedyncza odpowiedzialność - każda funkcja Lambda powinna mieć jedno, konkretne zadanie
  • Mały rozmiar i szybkie wykonanie - optymalizuj kod pod kątem szybkości startu i wykonania
  • Zarządzanie zależnościami - dołączaj tylko niezbędne zależności, aby zminimalizować rozmiar pakietu
  • Obsługa błędów - implementuj odpowiednią obsługę błędów i ponawianie operacji

2. Zarządzanie danymi

  • Wykorzystanie cachingu - używaj ElastiCache lub DAX dla częstych operacji odczytu
  • Optymalizacja dostępu do bazy danych - projektuj model danych pod konkretne wzorce dostępu
  • Stateless design - funkcje Lambda powinny być bezstanowe, przechowuj stan w serwisach takich jak DynamoDB

3. Bezpieczeństwo

  • Zasada najmniejszych uprawnień - przyznawaj funkcjom Lambda tylko niezbędne uprawnienia
  • Zmienne środowiskowe - przechowuj wrażliwe dane w AWS Secrets Manager lub SSM Parameter Store
  • Walidacja danych wejściowych - zawsze weryfikuj dane otrzymywane w API

4. Monitorowanie i logowanie

  • Szczegółowe logi - używaj kontekstowych logów dla łatwiejszego debugowania
  • Wykorzystanie AWS X-Ray - implementuj śledzenie dystrybucyjne
  • Alerty - konfiguruj powiadomienia o anomaliach i błędach

5. CI/CD dla aplikacji bezserwerowych

  • Automatyzacja wdrożeń - używaj pipeline'ów CI/CD do wdrażania zmian
  • Środowiska testowe - automatycznie twórz i niszcz środowiska testowe
  • Testowanie funkcji Lambda - pisz testy jednostkowe i integracyjne dla funkcji

Podsumowanie

W tym artykule poznaliśmy proces wdrażania nowoczesnej aplikacji bezserwerowej przy użyciu AWS CDK i Amazon Q Developer. Architektura bezserwerowa oferuje wiele korzyści: automatyczne skalowanie, model pay-per-use i brak konieczności zarządzania serwerami. AWS CDK upraszcza definiowanie infrastruktury jako kodu poprzez użycie języków programowania zamiast szablonów deklaratywnych. Amazon Q Developer, jako asystent AI, znacząco przyspiesza proces rozwoju, pomagając w generowaniu kodu, debugowaniu i implementacji najlepszych praktyk.

Wykorzystując razem te narzędzia, możesz tworzyć skalowalne, niezawodne i efektywne kosztowo aplikacje chmurowe z bezprecedensową prędkością i łatwością. Wraz z rozwojem technologii AI i automatyzacji, takie podejście do tworzenia oprogramowania staje się nowym standardem w branży.

Często zadawane pytania

Ile kosztuje korzystanie z AWS CDK?

Sam AWS CDK jest darmowy. Płacisz tylko za zasoby AWS, które tworzysz za pomocą CDK (np. funkcje Lambda, tabele DynamoDB, API Gateway).

Czy Amazon Q Developer jest dostępny bezpłatnie?

Amazon Q Developer oferuje zarówno plan bezpłatny (z pewnymi ograniczeniami), jak i plan płatny z dodatkowymi funkcjami. W planie bezpłatnym możesz korzystać z podstawowych funkcji generowania kodu i sugestii, ale zaawansowane funkcje, takie jak kompleksowe skanowanie bezpieczeństwa, są dostępne w planie płatnym.

Czy mogę używać AWS CDK z innymi językami niż TypeScript?

Tak, AWS CDK obsługuje wiele języków programowania, w tym Python, Java, C# i Go, oprócz TypeScript.

Jakie są ograniczenia architektury bezserwerowej?

Główne ograniczenia obejmują:

  • Zimny start (cold start) - opóźnienie przy pierwszym wywołaniu funkcji
  • Ograniczenia czasowe wykonania (np. maksymalny czas trwania funkcji Lambda to 15 minut)
  • Ograniczenia rozmiaru wdrożenia
  • Trudności w debugowaniu i monitorowaniu

Czy mogę migrować istniejącą aplikację do architektury bezserwerowej?

Tak, ale często wymaga to przeprojektowania aplikacji pod kątem architektury mikrousług i podejścia event-driven. Nie wszystkie aplikacje są dobrymi kandydatami do migracji na architekturę bezserwerową.


Jeśli potrzebujesz wsparcia w projektowaniu, wdrażaniu lub optymalizacji aplikacji bezserwerowych, skontaktuj się z nami. W IQHost specjalizujemy się w nowoczesnych architekturach chmurowych i możemy pomóc Ci wykorzystać pełny potencjał technologii chmury AWS.

Skontaktuj się z nami i dowiedz się, jak możemy pomóc Twojej organizacji w transformacji cyfrowej.

Czy ten artykuł był pomocny?

Wróć do listy wpisów

Twoja strona WordPress działa wolno?

Sprawdź nasz hosting WordPress z ultraszybkimi dyskami NVMe i konfiguracją serwera zoptymalizowaną pod kątem wydajności. Doświadcz różnicy już dziś!

Sprawdź ofertę hostingu
30-dniowa gwarancja zwrotu pieniędzy