Gebruikmaken van een serverloze Pact Broker met PostgreSQL op AWS ECS fargate
Introductie
Maak kennis met een serverloze Pact Broker met PostgreSQL op AWS ECS Fargate
Introductie
Een partner vroeg me onlangs om te laten zien hoe contracttesten, ook bekend als Pact, werkt voor een van onze klanten. Hoewel ik Pact in de praktijk niet had gebruikt, was ik door mijn uitgebreide ervaring met integratietests en servicevirtualisatie gretig om dit te ontdekken. Mijn doel was om een serverloze Pact Broker op AWS ECS (Elastic Container Service) op te zetten voor zowel de Pact Broker als de PostgreSQL-database. In deze handleiding wordt beschreven hoe u een Pact Broker en PostgreSQL op ECS kunt opzetten met behulp van de AWS Cloud Development Kit (CDK) in Python, waarbij de nadruk ligt op kostenefficiëntie en schaalbaarheid.
Vereisten
- AWS-account met de juiste toegang
- AWS CLI en AWS CDK geïnstalleerd
- Docker geïnstalleerd voor lokaal beheer van containerimages
- Basiskennis van Docker, AWS ECS en netwerken
Overzicht van de architectuur
De oplossing bestaat uit:
- Amazon ECS: host zowel de Pact Broker als PostgreSQL in containers.
- Amazon S3: slaat Pact-bestanden op voor versiebeheer en delen.
- Toekomstige AWS Lambda-integratie: automatiseert de verificatieprocessen van het pact.
- Amazon CloudWatch: biedt logboekregistratie en monitoring.
Kostenoverwegingen
- Kies voor ECS Fargate Spot Instances voor kostenbesparingen in niet-productieomgevingen.
- Controleer regelmatig het ECS-taakgebruik en pas zo nodig de taakgrootte aan om overbevoorrading te voorkomen.
- Gebruik het levenscyclusbeleid van S3 om de opslagkosten te minimaliseren.
- Ontdek de AWS Free Tier voor in aanmerking komende services om de initiële kosten te verlagen.
Implementatiestappen
- ECS-cluster en -netwerken
Stel een VPC- en een ECS-cluster in om een netwerkomgeving te bieden voor de gecontaineriseerde services:
t2. PostgreSQL-database in containers
Implementeer PostgreSQL als een container binnen ECS. Definieer een Dockerfile voor PostgreSQL of gebruik een bestaande afbeelding van Docker Hub. Zorg voor permanente opslag via ECS-volumebeheer
- Inzet van Pact Broker
Containeriseer de Pact Broker en implementeer deze op ECS. Zorg ervoor dat het is geconfigureerd om te communiceren met de PostgreSQL-container:
Na implementatie Controleren en implementeren van pacten
Verifieer eerst een pact en stuur het vervolgens door naar de makelaar. Na verificatie zou je setup er ongeveer zo uit moeten zien:
import { expect } from 'chai';
import path from 'path';
import { Pact, Matchers } from '@pact-foundation/pact';
import { getMeBSN, getMeBSNs } from './index.mjs';
const { like } = Matchers;
describe('The BSN API', () => {
let url = 'localhost';
const port = 8992;
const provider = new Pact({
port: port,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
consumer: 'RWS-consumer',
provider: 'BRP-provider',
// logLevel: 'trace', // assuming you want to set log level to 'trace'
});
const EXPECTED_BODY = [
{
bsn: 123456789,
},
{
bsn: 987654321,
},
];
// Setup the provider
before(async () => {
await provider.setup();
});
// Write Pact when all tests done
after(async () => {
await provider.finalize();
});
// verify with Pact, and reset expectations
afterEach(async () => {
await provider.verify();
});
describe('get /bsns', () => {
before(async () => {
const interaction = {
state: 'i have a list of BSN',
uponReceiving: 'a request for all BSNs',
withRequest: {
method: 'GET',
path: '/bsns',
headers: {
Accept: [
'application/problem+json',
'application/json',
'text/plain',
'*/*',
],
},
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: [
{ bsn: 123456789 },
{ bsn: 987654321 }
],
},
};
await provider.addInteraction(interaction);
});
it('returns the correct response', async () => {
const urlAndPort = {
url: url,
port: port,
};
const response = await getMeBSNs(urlAndPort);
console.log(response)
expect(response).to.eql(EXPECTED_BODY);
});
});
});
Na de implementatie is het pact zichtbaar in de pact-broker, opgeslagen in aws postgress ecs.
Om dat aan te tonen wanneer je een provider aanmaakt en om te zien of het niet lukt bij verifiëren of niet, heb ik twee API’s gemaakt in api gateway en lambda en de structuur van de tweede api een beetje gewijzigd.
De code voor het verifiëren van het pact als provider is deze
import axios from 'axios';
import fs from 'fs/promises'; // Use fs.promises for async/await support
import { Verifier } from '@pact-foundation/pact';
const pactFileUrl = 'http://pactst-pactb-oesxbucvqxww-103295103.eu-west-2.elb.amazonaws.com/pacts/provider/BRP-provider/consumer/RWS-consumer/latest';
const localFilePath = './local-pact-file.json'; // Path where you want to save the pact file
// Basic Authentication credentials
const username = 'admin';
const password = 'password';
const auth = Buffer.from(`${username}:${password}`).toString('base64');
async function downloadPactFile() {
try {
const response = await axios.get(pactFileUrl, {
headers: {
'Authorization': `Basic ${auth}`
},
responseType: 'json' // Assuming the response is JSON
});
// Save the file locally
await fs.writeFile(localFilePath, JSON.stringify(response.data));
console.log(`Pact file downloaded and saved to ${localFilePath}`);
} catch (error) {
console.error('Failed to download the pact file:', error.message);
}
}
async function verifyPacts() {
// Path to the local pact file
const localPactPath = './local-pact-file.json';
const opts = {
provider: 'BRP-provider',
providerBaseUrl: 'https://sqsgrhcuji.execute-api.eu-west-2.amazonaws.com/prod',
pactUrls: [localPactPath], // Use the local file path
logLevel: 'DEBUG',
};
try {
await new Verifier(opts).verifyProvider();
console.log('Pact verification complete!');
} catch (error) {
console.error('Pact verification failed:', error.message);
process.exit(1); // Exit
}
}
async function run() {
await downloadPactFile();
await verifyPacts();
}
run();
Wanneer u mijn pijplijntest uitvoert, zult u zien dat de derde test mislukt
Het resultaat
Als ik mijn pijplijntests uitvoer, blijkt dat de derde test mislukt is vanwege een verbroken pact. De logboeken geven duidelijk het probleem aan: een wijziging van bsn naar bsnnew. Dit demonstreert de MVP van het maken van een serverloze demo door het opzetten van dummy-API’s in Lambda.
Toekomstige verbeteringen
- S3 voor Pact-bestanden: Configureer een S3-bucket voor opslag en beheer van pact-bestanden.
- Lambda voor pactverificatie: plan om AWS Lambda te gebruiken voor geautomatiseerde pactverificatie die wordt geactiveerd door S3-uploads.
Conclusie
De implementatie van de Pact Broker en PostgreSQL op AWS ECS biedt een schaalbare, efficiënte en kosteneffectieve oplossing voor contracttesten in een microservices-omgeving. Toekomstige verbeteringen, waaronder AWS Lambda-integratie, beloven het contracttestproces verder te automatiseren en te stroomlijnen.
Ga voor meer gedetailleerde informatie en om toegang te krijgen tot de repositories voor dit project naar:
- https://gitlab.com/learnautomatedtesting/pactexample (aanbieder van API-voorbeelden)
- https://gitlab.com/learnautomatedtesting/servicevirtualizationandpact/ (Voorbeeld opensource Serverless stack AWS CDK Python v2) Deze opzet toont een praktische implementatie van Pact in AWS, waarbij de voordelen van serverloze architectuur voor contracttesten worden benadrukt.