Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions kubernetes/k3d-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: study-app-cluster
servers: 1
agents: 1
options:
k3s:
extraArgs:
- arg: --disable=traefik
nodeFilters:
- server:*
26 changes: 26 additions & 0 deletions kubernetes/manifests/base/backend/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: study-app
spec:
replicas: 1
selector:
matchLabels:
component: backend
template:
metadata:
labels:
component: backend
spec:
containers:
- name: backend
image: backend:latest
ports:
- containerPort: 22112
resources:
limits:
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
6 changes: 6 additions & 0 deletions kubernetes/manifests/base/backend/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml
12 changes: 12 additions & 0 deletions kubernetes/manifests/base/backend/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: study-app
spec:
selector:
component: backend
ports:
- port: 22112
type: LoadBalancer

30 changes: 30 additions & 0 deletions kubernetes/manifests/base/frontend/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: study-app
spec:
replicas: 1
selector:
matchLabels:
component: frontend
template:
metadata:
labels:
component: frontend
spec:
containers:
- name: frontend
image: frontend:latest
ports:
- containerPort: 22111
env:
- name: API_URL
value: "http://backend:22112"
resources:
limits:
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"

6 changes: 6 additions & 0 deletions kubernetes/manifests/base/frontend/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml
12 changes: 12 additions & 0 deletions kubernetes/manifests/base/frontend/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: study-app
spec:
selector:
component: frontend
ports:
- port: 22111
type: LoadBalancer

6 changes: 6 additions & 0 deletions kubernetes/manifests/base/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- backend
- frontend
5 changes: 5 additions & 0 deletions kubernetes/manifests/dev/backend/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base/backend
20 changes: 20 additions & 0 deletions kubernetes/manifests/dev/frontend/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base/frontend

# Patch for the frontend deployment
patches:
- target:
kind: Deployment
name: frontend
namespace: study-app
patch: |-
- op: replace
path: /spec/template/spec/containers/0/env
value:
- name: DEBUG
value: "true"
- name: API_URL
value: "http://dev-backend:22112"
16 changes: 16 additions & 0 deletions kubernetes/manifests/dev/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- namespace.yaml
- backend
- frontend

namespace: study-app
namePrefix: dev-

images:
- name: backend
newTag: dev
- name: frontend
newTag: dev
4 changes: 4 additions & 0 deletions kubernetes/manifests/dev/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: study-app
142 changes: 142 additions & 0 deletions kubernetes/setup_cluster_local
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/bin/bash
set -e

# Colors for better output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE_DIR="$(dirname "$SCRIPT_DIR")"
CLUSTER_NAME="study-app-cluster"

echo -e "${GREEN}DevOps Study App - Kubernetes Deployment Helper${NC}"
echo -e "${YELLOW}This script will set up a k3d cluster and deploy the study app.${NC}"
echo ""

# Check for required tools
check_dependency() {
if ! command -v "$1" &>/dev/null; then
echo -e "${RED}Error: $1 is not installed. Please install it before proceeding.${NC}"
exit 1
fi
}

echo "Checking dependencies..."
check_dependency k3d
check_dependency kubectl
check_dependency docker
echo -e "${GREEN}All dependencies are installed.${NC}"
echo ""

# Check if cluster exists
if k3d cluster list | grep -q "$CLUSTER_NAME"; then
echo -e "${YELLOW}Cluster $CLUSTER_NAME already exists.${NC}"
read -p "Do you want to delete and recreate it? (y/n): " -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Deleting existing cluster..."
k3d cluster delete "$CLUSTER_NAME"
else
echo "Using existing cluster."
fi
fi

# Create cluster if it doesn't exist
if ! k3d cluster list | grep -q "$CLUSTER_NAME"; then
echo "Creating k3d cluster using config file..."
k3d cluster create --config "$SCRIPT_DIR/k3d-config.yaml"
echo -e "${GREEN}Cluster created successfully!${NC}"
fi

# Configure kubectl to use the cluster
echo "Configuring kubectl to use the cluster..."
kubectl config use-context k3d-"$CLUSTER_NAME"

# Build Docker images
echo "Building Docker images..."
echo "Building backend image..."
docker build -t backend:dev -f "$BASE_DIR/src/backend/Dockerfile" "$BASE_DIR/src/backend"

echo "Building frontend image..."
docker build -t frontend:dev -f "$BASE_DIR/src/frontend/Dockerfile" "$BASE_DIR/src/frontend"

# Import images into k3d
echo "Importing images into k3d..."
k3d image import backend:dev -c "$CLUSTER_NAME"
k3d image import frontend:dev -c "$CLUSTER_NAME"

# Deploy the application using kustomize
echo "Deploying application using kustomize..."
kubectl apply -k "$SCRIPT_DIR/manifests/dev"

# Wait for pods to be ready
echo "Waiting for pods to be ready..."
kubectl wait --for=condition=Ready pods --all -n study-app --timeout=120s

# Get service info
echo -e "${GREEN}Application deployed successfully!${NC}"
echo "Getting service information..."
kubectl get services -n study-app

# Function to wait for LoadBalancer IP assignment and get URL
get_service_url() {
local service_name=$1
local max_attempts=30
local attempt=1

echo -e "Waiting for $service_name external IP..."

while [ $attempt -le $max_attempts ]; do
local ip
local port

ip=$(kubectl get svc "$service_name" -n study-app -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
port=$(kubectl get svc "$service_name" -n study-app -o=jsonpath='{.spec.ports[0].port}' 2>/dev/null)

if [ -n "$ip" ] && [ -n "$port" ]; then
echo "http://$ip:$port"
return 0
fi

echo -n "."
sleep 2
((attempt++))
done

echo ""
echo -e "${RED}Could not get external IP for $service_name after $max_attempts attempts${NC}"
return 1
}

# Get frontend and backend service URLs
FRONTEND_URL=$(get_service_url "dev-frontend")
BACKEND_URL=$(get_service_url "dev-backend")

echo -e "\n${GREEN}Access your application via LoadBalancer external IPs:${NC}"
if [ -n "$FRONTEND_URL" ] && [ -n "$BACKEND_URL" ]; then
echo -e "Frontend: ${YELLOW}$FRONTEND_URL${NC}"
echo -e "Backend API: ${YELLOW}$BACKEND_URL${NC}"
echo -e "Backend health check: ${YELLOW}$BACKEND_URL/health${NC}"
else
echo -e "\n${RED}Could not determine service URLs. Please check the service status:${NC}"
echo -e "${YELLOW}kubectl get svc -n study-app${NC}"
fi

# Extract service ports for port-forwarding instructions
FRONTEND_PORT=$(kubectl get svc dev-frontend -n study-app -o=jsonpath='{.spec.ports[0].port}' 2>/dev/null)
BACKEND_PORT=$(kubectl get svc dev-backend -n study-app -o=jsonpath='{.spec.ports[0].port}' 2>/dev/null)

echo -e "\n${GREEN}Alternative access via port-forwarding (for local development):${NC}"
echo -e "To access via port-forwarding, run these commands in separate terminals:"
echo -e "${YELLOW}kubectl port-forward svc/dev-frontend -n study-app $FRONTEND_PORT:$FRONTEND_PORT${NC}"
echo -e "${YELLOW}kubectl port-forward svc/dev-backend -n study-app $BACKEND_PORT:$BACKEND_PORT${NC}"
echo -e "Then access the application at:"
echo -e "Frontend: ${YELLOW}http://localhost:$FRONTEND_PORT${NC}"
echo -e "Backend API: ${YELLOW}http://localhost:$BACKEND_PORT${NC}"
echo -e "Backend health check: ${YELLOW}http://localhost:$BACKEND_PORT/health${NC}"

echo -e "\nTo delete the cluster when finished:"
echo -e "${YELLOW}k3d cluster delete $CLUSTER_NAME${NC}"

6 changes: 6 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[tools]
k3d = "latest"
kubectl = "latest"
pre-commit = "latest"
python = "3.13"
ruff = "latest"
Expand All @@ -13,5 +15,9 @@ experimental = true
APP_REPO = 'devops'
GITOPS_REPO = 'devops-gitops'

[tasks.k8s-setup-local]
description = "Set up a basic Kubernetes cluster for development that builds the local images and applies them"
run = "bash ./kubernetes/setup_cluster_local"

[hooks]
enter = "bash ./scripts/setup_project"