0% found this document useful (0 votes)
5 views

Explain_using_ tools

Uploaded by

Milorad Spasic
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Explain_using_ tools

Uploaded by

Milorad Spasic
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

I will explain what tools I used, which are Terraform and Pulumi, I did not use CDK, although I

know that it is an aws product that is intended exclusively for creating infrastructure on aws. My
use of Terraform was to create virtual machines on an ESXi cluster, and Pulumi to create on a
Kubernetes cluster. I will give a brief description of the use of Terraform and Pulumi in order to
show the knowledge of these tools and how they are used, the code examples are abstract and
not related to my projects.

At the end, I gave an example of a technical problem I had and how it was solved, describing in
detail the cause of the problem and its solution.

Terraform is a popular Infrastructure as Code (IaC) tool that enables developers and engineers
to define, manage, and deploy infrastructure using a declarative configuration language. It is
used to automate the process of creating and maintaining infrastructure in the cloud, on-
premise environments, or hybrid setups.

1. Preparation and planning of infrastructure

• Defining the infrastructure: We start by writing Terraform configuration files (.tf


files), which contain the resources needed for the application, such as servers, databases,
networks, load balancers, etc.

• Example:

provider "aws" {
region = "us-east-1"
}

resource "aws_instance" "example" {


ami = "ami-12345678"
instance_type = "t2.micro"
}

• Project initialization: The terraform init command is run, which installs the required
providers (eg AWS, Azure, GCP).

2. Planning of changes

• Overview of changes: Through the terraform plan, we get insight into the changes that
Terraform will make to the infrastructure, thus ensuring that nothing will be changed
unintentionally.

• Example:

Plan: 1 to add, 0 to change, 0 to destroy.

3. Application of infrastructure
• After the review, we run the terraform apply command, which deploys the resources in
the defined provider (eg AWS).

• Terraform automatically takes care of the order of resources. For example, it will not
create an EC2 instance before a VPC exists.

4. Management and maintenance

• State monitoring: Terraform uses the terraform.tfstate file to monitor the state of the
infrastructure. If the infrastructure is changed manually, it can cause inconsistency, so it is
better to always use Terraform.

• Resource update: Changes to .tf files are reflected using terraform apply.

• Destroying resources: When resources are no longer needed, use terraform destroy to
remove them.

Why did I use Terraform?

1. Automation: Terraform eliminates the need for manual infrastructure management,


saving time and reducing the chance of errors.

2. Declarative language: Instead of writing a series of steps to achieve something, we


describe the end state and Terraform takes care of the details.

3. Repeatability and scalability: The same configuration can be used in different


environments (eg development, test, production) by simply changing variables.

4. Cross-provider compatibility: Terraform can manage resources from different


providers simultaneously (eg AWS + Kubernetes + Azure).

5. Version Control: Terraform configurations can be versioned via Git, which allows
tracking of change history.

Pulumi is a tool forInfrastructure as Code (IaC), which allows defining and managing
the infrastructure using standard programming languages such as Python, TypeScript,
Go, C#and others. This is the main difference from Terraform, which uses a tool-specific
declarative language. Pulumi offers the flexibility and power of programming languages,
which allows for more complex logic and easier integration with the rest of the code.

I used Pulumi with Python.


1. Project initialization

• Project creation: The first step is to startpulumi new, where we choose the language
and project type (eg AWS, Azure, Kubernetes). This creates the initial files and configuration.

• Example for Python:


pulumi new aws-python

• This generates__main__.pyfile, where we define resources.

2. Writing infrastructure code

• Defining resources: Instead of a declarative language, the infrastructure is defined


using code. For example, creating an AWS EC2 instance in Python:

importpulumi
importpulumi_awsasaws

# Creating an EC2 instance


instance = aws.ec2.Instance(
"exampleInstance",
instance_type="t2.micro",
ami="ami-12345678"
)
pulumi.export("instance_ip", instance.public_ip)

• Use of logic: Since we use programming languages, we can easily use loops, conditionals
and functions.

forandinrange (3):
aws.ec2.Instance(f"exampleInstance-{and}",
instance_type="t2.micro",
ami="ami-12345678")

3. Infrastructure implementation

• After defining the code, the command is usedpulumi cf:


• Shows the changes that will be applied (similar to Terraform'splan).
• After confirmation, it implements the infrastructure.

4. Infrastructure management

• Status monitoring: Pulumi monitors infrastructure health in the cloud or locally


through Pulumi.<stack>.yaml files.

• Updating resources: Code changes are reflected using pulumi cf.


• Deleting resources: Seated pulumi destroy to remove resources.
Why did I use Pulumi?

1. Programming languages: Enables the use of known languages with all their libraries
and tools.

• For example, you can write infrastructure tests using Pytest or unittest.

2. Integration: Easily integrates with existing applications and CI/CD tools.


3. Complex logic: Pulumi allows the implementation of advanced rules and conditions
that would require additional modules or scripts in Terraform.
4. Multiple providers: Like Terraform, it supports different providers (AWS, Azure, GCP,
Kubernetes, etc.) in one code.
5. State management: Pulumi can store state locally or in its cloud service, while
Terraform uses a local file or backend.

A personal example of using Pulumi


On a hybrid infrastructure management project, I used Pulumi to:

1. Automation of Kubernetes cluster creation: I used Python to automate the creation of


EKS clusters and deployment applications.

importpulumi_kubernetesask8s

app_labels = {app:"nginx"}
deployment = k8s.apps.v1.Deployment(
"nginx-deployment",
spec={
"selector": {"matchLabels": app_labels},
"replicas":2,
"template": {
"metadata": {"labels": app_labels},
"spec": {
"containers": [{"name":"nginx","image":"nginx:1.14"}]
},
},
},
)

2. Dynamic allocation of resources: I implemented scaling of the number of instances


based on the input parameters.

3. CI/CD integration: Pulumi was part of the pipeline to automatically update the
infrastructure on eachmergeto the main branch.

Advantages over Terraform

• Greater flexibility: Programming languages enable advanced logics.


• Possibility of testing: Infrastructure code can be tested like any other code.
• Easier learning curve: If you already know Python or TypeScript, Pulumi is a natural
choice.

When using Pulumi in a project, I focused on infrastructure automation and integration


with CI/CD processes to ensure continuous infrastructure delivery and maintenance.
Here is a detailed description of the steps:

The script

I designed the infrastructure for serverless application using AWS resources (eg
Lambda, API Gateway, S3) and integrated Pulumi into the CI/CD pipeline to automate
everything from creation to infrastructure updates.

1. Structure of the project


The structure of the project was as follows:

project/

├── infra/ # Pulls files for infrastructure
│ ├── __main__.py # Main script with infrastructure code
│ ├── Pulumi.yaml # Pulumi configuration
│ ├── Pulumi.dev.yaml # Parameters for the development environment
│ └── Pulumi.prod.yaml # Parameters for the production environment

├── lambda/ # Code for Lambda functions
│ └── handler.py

└── .github/ # CI/CD configuration
└── workflows/
└── pulumi.yml # GitHub Actions pipeline

2. Creating infrastructure with Pulumi


U__main__.py, I defined the resources:

Creating an S3 bucket for static content

importpulumi
importpulumi_awsasaws

# S3 bucket for static content


bucket = aws.s3.Bucket(
"static-content-bucket",
website={
"index_document":"index.html",
},
)

pulumi.export("bucket_name", bucket.bucket)
pulumi.export("bucket_url", bucket.website_endpoint)
Creation of Lambda function and API Gateway

# Lambda function
lambda_role = aws.iam.Role(
"lambda-execution-role",
assume_role_policy="""{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"}
}
]
}""",
)

function = aws.lambda_.Function(
"my-lambda-function",
runtime="python3.9",
role=lambda_role.arn,
handler="handler.main",
code=pulumi.AssetArchive({
".": pulumi.FileArchive("./lambda"),
}),
)

# API Gateway connected to the Lambda function


api = aws.apigatewayv2.Api(
"api-gateway",
protocol_type="HTTP",
target=function.arn,
)

pulumi.export("api_url", api.api_endpoint)

Defining different environments (dev/prod)

I changed the parameters in the files Pulumi.dev.yaml and Pulumi.prod.yaml. For example:

configuration:
aws:region: us-east-1

3. Automation with CI/CD

For CI/CD I used GitHub Actions and created pulumi.yml in .github/workflows/directory.

GitHub Actions pipeline configuration

name: Pulumi CI/CD Pipeline

heh:
push:
branches:
- main
- dev

jobs:
deploy:
runs-on: ubuntu-latest

steps:
# 1. Checkout code
- name: Checkout code
uses: actions/checkout@v3

# 2. Pulumi installation and dependency


- name: Install Pulumi
runes: |
curl -fsSL https://get.pulumi.com | sh
export PATH=$PATH:~/.pulumi/bin

- name: Install Python dependencies


runes: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 3. Authentication for Pulumi and AWS


- name: Authenticate Pulumi
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
runes: pulumi login

- name: Configure AWS Credentials


uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

# 4. Running the Pulumi command


- name: Preview changes
runes: pulumi preview --stack dev

- name: Deploy infrastructure


runes: pulumi cf --stack dev --yes

Explanation of steps:

1. Checkout code: Pipeline fetches code from the corresponding branch (main or dev).
2. Pulumi installation and Python libraries: Setting up the environment to work with
Pulumi.
3. Authentication:

• Pulumi benefits access token which is stored in GitHub Secrets


(PULUMI_ACCESS_TOKEN).
• AWS credentials are configured using aws-actions/configure-aws-credentials.

4. Deploy infrastructure:
• pulumi previewverifies changes before implementation.
• pulumi cfimplements the infrastructure for the defined stack(devOrprod).

4. How everything works in practice

1. Local development:

• I wrote and tested the Pulumi code locally using the commands:

pulumi preview --stack dev


pulumi up --stack dev

• I sat down Pulumi.dev.yaml to configure the development environment.

2. GitHub Actions pipeline:


• Each one push in dev the branch was driven by implementation in development
environments.
• Merge into main the branch is automatically started by the deployment in production
using Pulumi.prod.yaml.

3. Automatic validation:
• pulumi preview ensured that subtle errors were identified before implementation.

• If the deployment fails, the team is notified via GitHub Actions logs.
4. Parameterization for environments:

• Through the Pulumi configuration files (Pulumi.dev.yamlandPulumi.prod.yaml), and


easily separated resources and settings specific to development and production.

Results and benefits

• Faster deliveries: CI/CD enabled every infrastructure change to be implemented


automatically.
• Security and change tracking: Pulumi provided a detailed view of all infrastructure
changes prior to implementation.
• Easy scalability: New resources are easily added through code and automatically
included in the pipeline.
• Reusability: Constructors in Pulumi code made it possible to reuse resource definitions
across projects.

Technical problem from the domain of databases: Deadlock in transactions


Problem:

On the inventory management project, we worked with PostgreSQL database and


implemented functionality that updates inventory in real time. Each transaction involved the
following steps:

1. Checking the current quantity in stock.


2. Updating the quantity in the database.

In the case of a large number of parallel requests, I ran into a problem deadlock. This happened
when two or more processes were trying to update the same rows in the inventory table, but
there were locks (locks) caused a mutual blockade. This resulted in an error:

ERROR: deadlock detected


DETAIL: Process1234waitsforShareLock on transaction5678; blocked by
process5678.

Cause of the problem:

The problem was in the design of the transactions. Transactions were taking overRow-Level
Lockson different lines in different order, which caused interdependencies between processes.
Specifically:

• Process 1 locks queue A and waits for queue B.


• Process 2 locks queue B and waits for queue A.

This scenario led to deadlocks when requests happened in parallel.

Solution:

1. Analysis of the locking order


Analyzing the query, I identified that the rows are locked in different order depending on the
business logic. This caused inconsistent behavior.
2. Implementation of deterministic locking order

I changed the logic so that all processes lock rows in the same order, regardless of the input
parameters. For example:

SELECT*FROMstock
WHEREproduct_idIN(product_a, product_b)
ORDER BYproduct_idFOR UPDATE;

This change ensures that all processes lock the row with the smallest one firstproduct_id, and
only then the others.
3. Introduction of retry interval (Retry)
Deadlock is inevitable in certain situations where parallelism exceeds the resources of the
database. I implemented the retry mechanism in the application code:

importpsycopg2
fromwith thatimportsleep

defexecute_transaction():
forattemptinrange (3):
try:
withconnection.cursor()ascursor:
cursor.execute("BEGIN;")
# Inventory update query
cursor.execute("""
UPDATE stock
SET quantity = quantity - 1
WHERE product_id = %s AND quantity > 0;
""", (product_id,))
cursor.execute("COMMIT;")
break
exceptpsycopg2.errors.DeadlockDetected:
ifattempt <2:
sleep(0.5) # Waits before retrying
else:
raise

4. Setting the transaction isolation level


For this functionality, I set the transaction isolation level toREAD
COMMITTEDinsteadREPEATABLE READ, because the application did not require strictly
consistent data throughout the transaction.

5. Performance monitoring and analysis

I introduced logging of all transactions and deadlock situations using


PostgreSQLpg_stat_activityand activated the automatic recording of deadlock information in
the log file:

SETlog_lock_waits =HE;
SETdeadlock_timeout ='1s';

Why am I sure the problem won't happen again?

1. Consistent locking order: I defined a rule that all processes lock rows in the same
order. This eliminates the cause of the deadlock.
2. Retry mechanism: Even in case of unexpected situations, the system automatically
repeats the transaction up to three times before reporting an error.

3. Monitoring and alarms: I set up monitoring at the database and application level, so
that any new deadlock is reported immediately. This enables proactive problem solving.
4. Optimization of the isolation level: By changing the isolation level of transactions, the
number of situations where competitive locking occurs has been reduced.

5. Testing under load: I simulated high levels of competition using tools such
aspgbenchand custom load scripts. The deadlock did not reoccur.

Results:

• The system became stable, even with a large number of parallel requests.
• Database performance has improved, as the number of locks has been reduced to a
minimum.
• There are no reported deadlocks more than six months after the implementation of the
solution.

You might also like