Jak wykonać proces CI/CD dla funkcji Lambda przy pomocy AWS CodePipline.

Jak wykonać proces CI/CD dla funkcji Lambda przy pomocy AWS CodePipline.

Napisaliśmy aplikację serverless. Źródła trzymamy oczywiście w repozytorium kodu, najprawdopodobniej w GitHub. Chemy wdrożyć ją w chmurze AWS. Chcemy też, aby od razu po wrzuceniu zmian do repozytorium kodu, nowa wersja aplikacji, po przejściu przez testy, pojawiła się „na produkcji”. Potrzebujemy więc sławnego CI/CD. Jak wykonać proces CI/CD dla funkcji Lambda przy pomocy AWS CodePipline? W sumie jest to dość proste. Pokażę w jaki sposób to zrobić.

Aplikacja

Nasza aplikacja jest bardzo prosta. Składa się z jednej funkcji Lambda oraz endpointa w usłudze APIGateway. Całość zdefiniowana jest oczywiście za pomocą Serverless Application Model. Definicja wygląda następująco:

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
  Lambda:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: python3.7
      Role:
        Fn::GetAtt:
        - LambdaExecutionRole
        - Arn
      Events:
        GetEvent:
          Type: Api
          Properties:
            Path: /
            Method: get
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'ddlambdarole'
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [lambda.amazonaws.com]
          Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        -  arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Sama funkcja też jest bardzo prosta. Zwraca po prostu trochę tekstu do API:

import json

def handler(event, context):
    return {
        'statusCode': 200,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(
            {'message': 'Hello DevDiaries readers'}
        ),
    }

Dodatkowo zaimplementujemy jeszcze testy jednostkowe, które będą przeprowadzane w procesie budowania aplikacji. Test sprawdzi po prostu, czy w zwracanym ciągu znaków jest zwrot DevDiaries:

import unittest
import index

class TestHandlerCase(unittest.TestCase):

    def test_response(self):
        print("testing response.")
        result = index.handler(None, None)
        print(result)
        self.assertEqual(result['statusCode'], 200)
        self.assertEqual(result['headers']['Content-Type'], 'application/json')
        self.assertIn('DevDiaries', result['body'])


if __name__ == '__main__':
    unittest.main()

Cały kod jest oczywiście dostępny na GitHub i możecie sami spróbować wdrożyć cały proces CI/CD.

Mamy więc nasz kod, czas uruchomić AWS i wdrożyć naszą aplikację.

Wdrażamy proces CI/CD

Aby wygodnie połączyć GitHuba z AWS skorzystamy z usługi AWS CodePipeline. Zanim jednak z niej skorzystamy musimy się przygotować. Potrzebny nam będzie bucket S3 na artefakty oraz rola dla usługi CloudFormation, która pozwoli jej na działanie.

Rola dla CloudFormation

W usłudze IAM przechodzimy do zakładki Roles i klikamy Create role. Jako trusted entity wybieramy CloudFormation. Jako Permissions dodajemy politykę AWSLambdaExecute. Kilkamy Next, wpisujemy jakąś nazwę dla roli. Gdy rola jest gotowa, otwieramy ją i w zakładce Permissions klikamy Add inline policy. Przechodzimy do zakładki JSON i wklejamy poniższy dokument:

{
    "Statement": [
        {
            "Action": [
                "apigateway:*",
                "codedeploy:*",
                "lambda:*",
                "cloudformation:CreateChangeSet",
                "iam:GetRole",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:PutRolePolicy",
                "iam:AttachRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:DetachRolePolicy",
                "iam:PassRole",
                "s3:GetObjectVersion",
                "s3:GetBucketVersioning"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ],
    "Version": "2012-10-17"
}

Zapisujemy zmiany, tworzymy bucket S3 na artefakty (to chyba każdy potrafi 😉 ) i możemy przejść do usługi AWS CodePipeline.

Konfigurujemy proces CI/CD

Po jej otwarciu musimy stworzyć nowy pipeline. Klikamy Create pipeline i na początek wpisujemy nazwę dla naszego procesu.

Klikamy Next i wybieramy skąd mają być pobierane źródła aplikacji. W naszym przypadku będzie to GitHub.

Zostawiamy resztę opcji bez zmian i klikamy Connect to GitHub. Autoryzujemy AWS do podłączenia się do naszego konta. Trzeba to zrobić osobno dla każdego regionu AWS.

Następnie wybieramy repozytorium i branch, który ma być śledzony.

Kolejny krok to utworzenie projektu w usłudze CodeBuild. Tam będzie kompilowana i testowana nasza aplikacja.

Klikamy Create project I w zależności od potrzeb wybieramy odpowiednie ustawienia platformy dla naszego builda.

Wybieramy także nasz plik *buildspec* jako „instrukcję budowania pakietu.

Klikamy Continue to CodePipeline i rozpoczynamy proces konfiguracji deploymentu.

Nasza aplikacja będzie wdrożona za pomocą usługi CloudFormation, którą wybieramy spośród innych możliwości. Po ustawieniu pożądanego regionu jako akcję wybieramy Create or replace a changeset. Później to rozbudujemy.

Dalej kolejno definiujemy nazwy dla stacka oraz changeseta. Podajemy także gdzie znajduje się template dla naszej aplikacji. W naszym przypadku to BuildArtifact::outputtemplate.yaml.

Opcjonalnie, w zależności od potrzeb dodajemy Capabilities, czyli upoważniamy CloudFormation do tworzenia zasobów w usłudze IAM. Klikamy Next I Create pipeline.

Po chwili nasz pipeline pojawi się i zacznie pracę. Niestety musimy wykonać jeszcze dwie rzeczy, aby mógł przebiec pomyślnie.

Przede wszystkim musimy dodać uprawnienia dla usługi CodeBuild do zapisu plików w S3.

Przechodzimy do naszego projektu w CodeBuild i w zakładce Build details

odszukujemy rolę

klikamy w nią. Następnie dodajemy do niej politykę AmazonS3FullAccess. Teraz proces budowy aplikacji będzie miał uprawnienia do zapisu w naszym buckecie w usłudze S3. Sam bucket definiujemy w pliku buildspec.yaml jako zmienną:

- export S3_BUCKET=bucket_name

Wracamy do naszego pipeline i musimy dokończyć konfigurację procesu deploymentu. Do tej pory zdefiniowaliśmy proces jako tworzenie changeseta. Musimy dodać jeszcze proces, który ten changeset uruchomi i zniemi nasze środowisko w AWS. Przechodzimy do edycji Deploy

I dodajemy akcję. Klikamy Add action group I wypełniamy poszczególne pola jak poniżej. Używamy oczywiście odpowiednich nazw zarówno dla stacka jak i changeseta.

Zapisujemy zmiany i możemy wypróbować czy nasz proces CI/CD zadziała.

Po chwili (dłuższej lub krótszej) nasza aplikacja serverless będzie zainstalowana na usługach AWS. OD tej pory każda zmiana kodu w wybrany repozytorium i branchu będzie uruchamiała proces budowania i deploymentu naszej aplikacji.

Podsumowanie

Jak widać cała konfiguracja jest dość prosta. Warto z niej korzystać. Początkowy wkład pracy szybko zwróci się z nawiązką przy kolejnych zmianach w naszej aplikacji. Nic nie stoi na przeszkodzie, aby taki proces połączyć ze źródłami trzymanymi na przykład w BitBucket, a nawet w S3.

 

Comments are closed.