Kubernetes project - Microservices
Augustine Tetteh Ozor
Cloud DevOps Engineer | 2x AWS Certified | Cloud & Automation | AWS, Kubernetes, Docker, Terraform, Jenkins, and CI/CD Pipelines | Driving Scalable & Secure Infrastructure Solutions
EKS Cluster in AWS
Project Overview
This project focuses on creating and managing an Elastic Kubernetes Service (EKS) cluster in AWS, automating infrastructure setup, and configuring IAM roles and policies for secure and efficient cluster operations. It showcases the application of DevOps practices, Kubernetes orchestration, and cloud infrastructure management on AWS.
Project Objectives
Technologies and Tools
Launch EC2 Instance
Setup EKS Cluster
Setting Up AWS IAM User and Policies
Install CLIs
curl "<https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip>" -o "awscliv2.zip" sudo apt install unzip unzip awscliv2.zip sudo ./aws/install aws configure
2. Kubectl
curl -o kubectl <https://amazon-eks.s3.us-west-2.amazonaws.com/1.19.6/2021-01-05/bin/linux/amd64/kubectl> chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin kubectl version --short --client
3. eksctl
curl --silent --location "<https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$>(uname -s)_amd64.tar.gz" | tar xz -C /tmp sudo mv /tmp/eksctl /usr/local/bin eksctl version
AWS CLI Configuration
Step 1: Install AWS CLI
Step 2: Open Terminal/Command Prompt
Step 3: Run AWS Configure Command
In your terminal or command prompt, run the following command to configure AWS CLI:
aws configure
Step 4: Enter AWS Access Key ID and Secret Access Key
You'll be prompted to enter:
Example:
AWS Access Key ID [None]: YOUR_ACCESS_KEY_ID
AWS Secret Access Key [None]: YOUR_SECRET_ACCESS_KEY
Step 5: Choose Default Region
Next, AWS CLI will ask for a Default region name. For example, if you're working in US East (N. Virginia), you can type:
Default region name [None]: us-east-1
For other regions, refer to the AWS Region Table.
Step : 6 Verify Configuration
Run the following command to confirm that AWS CLI is configured properly:
aws sts get-caller-identity
Create EKS CLUSTER
CloudFormation will create the cluster when the first set of commands are run
eksctl create cluster --name=my-eks22 \\
--region=us-east-1 \\
--zones=us-east-1a,us-east-1b \\
--without-nodegroup
eksctl utils associate-iam-oidc-provider \\
--region us-east-1 \\
--cluster my-eks22 \\
--approve
eksctl create nodegroup --cluster=my-eks22 \\
--region=us-east-1 \\
--name=node2 \\
--node-type=t3.medium \\
--nodes=3 \\
--nodes-min=2 \\
--nodes-max=4 \\
--node-volume-size=20 \\
--ssh-access \\
--ssh-public-key=devopstack1 \\
--managed \\
--asg-access \\
--external-dns-access \\
--full-ecr-access \\
--appmesh-access \\
--alb-ingress-access
OIDC Provider Association: Associate an IAM OIDC provider with the EKS cluster.
The OIDC provider acts as a bridge between Kubernetes and AWS IAM, enabling service accounts in your EKS cluster to assume IAM roles. This allows pods running in the cluster to securely access AWS services (like S3, DynamoDB, etc.) using the least privilege principle.
eksctl utils associate-iam-oidc-provider --region us-east-1 --cluster my-eks22 --approve
Node Group Creation: Create a managed node group within the cluster.
eksctl create nodegroup --cluster=my-eks22 --region=us-east-1 --name=node2 --node-type=t3.medium --nodes=3 --nodes-min=2 --nodes-max=4 --node-volume-size=20 --ssh-access --ssh-public-key=devopstack1 --managed
Jenkins Installation and Configuration
Java Development Kit (JDK)
Jenkins is a Java-based application, so you need to install the Java Development Kit (JDK) before installing Jenkins.
sudo apt update
sudo apt install openjdk-17-jdk -y
Jenkins installation script :https://www.jenkins.io/doc/book/installing/linux/
领英推荐
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \\
<https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key>
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \\
<https://pkg.jenkins.io/debian-stable> binary/ | sudo tee \\
/etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins
sudo systemctl enable jenkins
sudo systemctl start jenkins
change the permission for installation script
sudo chmod +x [jenkins.sh](<https://jenkins.sh/>)
Copy the ip address of the ec2 install and use port 8080 to access jenkins
54.147.43.251:8080
To unlock Jenkins find the password at on your ec2 server: /var/lib/jenkins/secrets/initialAdminPassword
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Create Admin User
Docker Installation
sudo apt install docker.io
sudo chmod 666 /var/run/docker.sock
Install Jenkins Plugins
Configure Plugins That were installed
Connect to Git Repo and Create Pipeline
Create docker credential
Create a multi branch pipeline
Setup Webhook
Copy the jenkins url and the token for the webhook and use them as follows:
Continuous Deployment Stage
Kubernetes Role-Based Access Control (RBAC)
Create a namespace:
kubeclt create namespace webapps
Service Account Token Creation
apiVersion: v1
kind: Secret
type: [kubernetes.io/service-account-token](<https://kubernetes.io/service-account-token>)
metadata:
name: mysecretname
annotations:
[kubernetes.io/service-account.name:](<https://kubernetes.io/service-account.name:>) jenkins
Run the command to get the token
kubectl describe secret mysecretname -n webapps
Go to AWS EKS and copy the API Server Endpoint : https://127E9436BA00F4179627C6652364C965.gr7.us-east-1.eks.amazonaws.com
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: emailservice
spec:
selector:
matchLabels:
app: emailservice
template:
metadata:
labels:
app: emailservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
securityContext:
fsGroup: 1000
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
containers:
- name: server
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: adijaiswal/emailservice:latest
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: emailservice
spec:
type: ClusterIP
selector:
app: emailservice
ports:
- name: grpc
port: 5000
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkoutservice
spec:
selector:
matchLabels:
app: checkoutservice
template:
metadata:
labels:
app: checkoutservice
spec:
serviceAccountName: default
containers:
- name: server
image: adijaiswal/checkoutservice:latest
ports:
- containerPort: 5050
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
env:
- name: PORT
value: "5050"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: PAYMENT_SERVICE_ADDR
value: "paymentservice:50051"
- name: EMAIL_SERVICE_ADDR
value: "emailservice:5000"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: checkoutservice
spec:
type: ClusterIP
selector:
app: checkoutservice
ports:
- name: grpc
port: 5050
targetPort: 5050
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: recommendationservice
spec:
selector:
matchLabels:
app: recommendationservice
template:
metadata:
labels:
app: recommendationservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/recommendationservice:latest
ports:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: DISABLE_PROFILER
value: "1"
resources:
requests:
cpu: 100m
memory: 220Mi
limits:
cpu: 200m
memory: 450Mi
---
apiVersion: v1
kind: Service
metadata:
name: recommendationservice
spec:
type: ClusterIP
selector:
app: recommendationservice
ports:
- name: grpc
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
serviceAccountName: default
containers:
- name: server
image: adijaiswal/frontend:latest
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
- name: RECOMMENDATION_SERVICE_ADDR
value: "recommendationservice:8080"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: CHECKOUT_SERVICE_ADDR
value: "checkoutservice:5050"
- name: AD_SERVICE_ADDR
value: "adservice:9555"
# # ENV_PLATFORM: One of: local, gcp, aws, azure, onprem, alibaba
# # When not set, defaults to "local" unless running in GKE, otherwies auto-sets to gcp
# - name: ENV_PLATFORM
# value: "aws"
- name: ENABLE_PROFILER
value: "0"
# - name: CYMBAL_BRANDING
# value: "true"
# - name: FRONTEND_MESSAGE
# value: "Replace this with a message you want to display on all pages."
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: NodePort
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: frontend-external
spec:
type: LoadBalancer
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: paymentservice
spec:
selector:
matchLabels:
app: paymentservice
template:
metadata:
labels:
app: paymentservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/paymentservice:latest
ports:
- containerPort: 50051
env:
- name: PORT
value: "50051"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: paymentservice
spec:
type: ClusterIP
selector:
app: paymentservice
ports:
- name: grpc
port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: productcatalogservice
spec:
selector:
matchLabels:
app: productcatalogservice
template:
metadata:
labels:
app: productcatalogservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/productcatalogservice:latest
ports:
- containerPort: 3550
env:
- name: PORT
value: "3550"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: productcatalogservice
spec:
type: ClusterIP
selector:
app: productcatalogservice
ports:
- name: grpc
port: 3550
targetPort: 3550
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cartservice
spec:
selector:
matchLabels:
app: cartservice
template:
metadata:
labels:
app: cartservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/cartservice:latest
ports:
- containerPort: 7070
env:
- name: REDIS_ADDR
value: "redis-cart:6379"
resources:
requests:
cpu: 200m
memory: 64Mi
limits:
cpu: 300m
memory: 128Mi
readinessProbe:
initialDelaySeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
livenessProbe:
initialDelaySeconds: 15
periodSeconds: 10
exec:
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
---
apiVersion: v1
kind: Service
metadata:
name: cartservice
spec:
type: ClusterIP
selector:
app: cartservice
ports:
- name: grpc
port: 7070
targetPort: 7070
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: loadgenerator
spec:
selector:
matchLabels:
app: loadgenerator
replicas: 1
template:
metadata:
labels:
app: loadgenerator
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
restartPolicy: Always
containers:
- name: main
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: adijaiswal/loadgenerator:latest
env:
- name: FRONTEND_ADDR
value: "frontend:80"
- name: USERS
value: "10"
resources:
requests:
cpu: 300m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: currencyservice
spec:
selector:
matchLabels:
app: currencyservice
template:
metadata:
labels:
app: currencyservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/currencyservice:latest
ports:
- name: grpc
containerPort: 7000
env:
- name: PORT
value: "7000"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: currencyservice
spec:
type: ClusterIP
selector:
app: currencyservice
ports:
- name: grpc
port: 7000
targetPort: 7000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shippingservice
spec:
selector:
matchLabels:
app: shippingservice
template:
metadata:
labels:
app: shippingservice
spec:
serviceAccountName: default
containers:
- name: server
image: adijaiswal/shippingservice:latest
ports:
- containerPort: 50051
env:
- name: PORT
value: "50051"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: shippingservice
spec:
type: ClusterIP
selector:
app: shippingservice
ports:
- name: grpc
port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cart
spec:
selector:
matchLabels:
app: redis-cart
template:
metadata:
labels:
app: redis-cart
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: redis-cart
spec:
type: ClusterIP
selector:
app: redis-cart
ports:
- name: tcp-redis
port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adservice
spec:
selector:
matchLabels:
app: adservice
template:
metadata:
labels:
app: adservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: adijaiswal/adservice:latest
ports:
- containerPort: 9555
env:
- name: PORT
value: "9555"
resources:
requests:
cpu: 200m
memory: 180Mi
limits:
cpu: 300m
memory: 300Mi
readinessProbe:
initialDelaySeconds: 20
periodSeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:9555"]
livenessProbe:
initialDelaySeconds: 20
periodSeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:9555"]
---
apiVersion: v1
kind: Service
metadata:
name: adservice
spec:
type: ClusterIP
selector:
app: adservice
ports:
- name: grpc
port: 9555
targetPort: 9555
pipeline {
agent any
stages {
stage('Deploy to kubernetes') {
steps {
withKubeCredentials(kubectlCredentials: [[caCertificate: '', clusterName: ' my-eks22', contextName: '', credentialsId: 'kube-token', namespace: 'webapps', serverUrl: '<https://127E9436BA00F4179627C6652364C965.gr7.us-east-1.eks.amazonaws.com>']]) {
sh "kubectl apply -f deployment-service.yml"
sleep 60
}
}
}
stage('Verify Deployment') {
steps {
withKubeCredentials(kubectlCredentials: [[caCertificate: '', clusterName: ' my-eks22', contextName: '', credentialsId: 'kube-token', namespace: 'webapps', serverUrl: '<https://127E9436BA00F4179627C6652364C965.gr7.us-east-1.eks.amazonaws.com>']]) {
sh "kubectl get all -n webapps"
}
}
}
}
}
Clean Up the Deployment
eksctl delete cluster --name my-eks22 --region us-east-1
Mechanic, for havy duty track, Mafi and Cranes at Ghana Port and harbour Authority. ( Tema)
2 个月I agree!
AWS Certified Cloud Practitioner | Certified In Cybersecurity | Information Security (INFOSEC) | SOC Analyst | Security Analyst
2 个月Great I’m also working on a kubenetes project I will hit you up for some insights??
Open for New Opportunities : Senior IT Content Writer - Intern | 1* (CEH) | 1* CCNA Fundamentals | AWS Skill Builder Enthusiast
2 个月Good one ??Augustine Tetteh Ozor
DevOps | Linux | GitHub Actions | Maven | Tomcat | SAST | DAST | Jenkins | Docker | Kubernetes(EKS/Fargate) | Terraform | AWS | Azure | Python | Prometheus | Grafana | Node Exporter
2 个月Very helpful