Skip to content
Open
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,20 @@ kubectl delete namespace tarun-spring-app
```
This ensures the namespace and all resources within it are deleted.

## Deploying with Terraform

The `terraform` directory provides the same Kubernetes resources using Terraform.
The configuration is split across multiple `.tf` files for readability and Terraform automatically loads all of them.
Run the following commands to apply them:

```bash
cd terraform
terraform init
terraform apply
```

Ensure your kubeconfig is accessible (by default `~/.kube/config`).

## Future Enhancements

Below are some potential enhancements and next steps for this project:
Expand Down
22 changes: 22 additions & 0 deletions terraform/configmap.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
resource "kubernetes_config_map" "spring_app_config" {
metadata {
name = "spring-app-config"
namespace = kubernetes_namespace.spring.metadata[0].name
}

data = {
"application.properties" = <<EOT
spring.application.name=spring-app
spring.datasource.url=jdbc:h2:mem:todo-db
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=$${DB_USERNAME:defaultUser}
spring.datasource.password=$${DB_PASSWORD:defaultPass}
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.web-allow-others=true
management.endpoints.web.exposure.include=prometheus
management.endpoint.health.show-details=always
EOT
}
}
82 changes: 82 additions & 0 deletions terraform/deployment.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
resource "kubernetes_deployment" "spring_app" {
metadata {
name = "spring-app"
namespace = kubernetes_namespace.spring.metadata[0].name
labels = {
app = "spring-app"
}
annotations = {
"prometheus.io/scrape" = "true"
"prometheus.io/port" = "8080"
"prometheus.io/path" = "/actuator/prometheus"
}
}

spec {
replicas = 2

selector {
match_labels = {
app = "spring-app"
}
}

template {
metadata {
labels = {
app = "spring-app"
}
}

spec {
container {
name = "spring-app"
image = "tarundhiman/spring-app:v3"

image_pull_policy = "IfNotPresent"

port {
container_port = 8080
}

volume_mount {
name = "config-volume"
mount_path = "/config/application.properties"
sub_path = "application.properties"
}

env {
name = "DB_USERNAME"
value_from {
secret_key_ref {
name = kubernetes_secret.spring_app_secret.metadata[0].name
key = "username"
}
}
}

env {
name = "DB_PASSWORD"
value_from {
secret_key_ref {
name = kubernetes_secret.spring_app_secret.metadata[0].name
key = "password"
}
}
}

args = ["--spring.config.location=file:/config/application.properties"]
}

volume {
name = "config-volume"
config_map {
name = kubernetes_config_map.spring_app_config.metadata[0].name
}
}

restart_policy = "Always"
}
}
}
}
40 changes: 40 additions & 0 deletions terraform/ingress.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
resource "kubernetes_ingress_v1" "spring_app_ingress" {
metadata {
name = "spring-app-ingress"
namespace = kubernetes_namespace.spring.metadata[0].name
}

spec {
ingress_class_name = "nginx"

rule {
host = "spring-app.example.com"
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = kubernetes_service.spring_app_service.metadata[0].name
port {
number = 80
}
}
}
}
path {
path = "/prometheus"
path_type = "Prefix"
backend {
service {
name = kubernetes_service.prometheus_service.metadata[0].name
port {
number = 90
}
}
}
}
}
}
}
}
5 changes: 5 additions & 0 deletions terraform/namespace.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource "kubernetes_namespace" "spring" {
metadata {
name = "tarun-spring-app"
}
}
137 changes: 137 additions & 0 deletions terraform/prometheus.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
resource "kubernetes_service_account" "prometheus" {
metadata {
name = "prometheus"
namespace = kubernetes_namespace.spring.metadata[0].name
}
}

resource "kubernetes_cluster_role" "prometheus" {
metadata {
name = "prometheus-clusterrole"
}

rule {
api_groups = [""]
resources = ["pods", "endpoints", "services"]
verbs = ["get", "list", "watch"]
}
}

resource "kubernetes_cluster_role_binding" "prometheus" {
metadata {
name = "prometheus-clusterrolebinding"
}

subject {
kind = "ServiceAccount"
name = kubernetes_service_account.prometheus.metadata[0].name
namespace = kubernetes_namespace.spring.metadata[0].name
}

role_ref {
kind = "ClusterRole"
name = kubernetes_cluster_role.prometheus.metadata[0].name
api_group = "rbac.authorization.k8s.io"
}
}

resource "kubernetes_config_map" "prometheus_config" {
metadata {
name = "prometheus-config"
namespace = kubernetes_namespace.spring.metadata[0].name
}

data = {
"prometheus.yml" = <<EOT
global:
scrape_interval: 15s

scrape_configs:
- job_name: 'spring-app'
metrics_path: /actuator/prometheus
scheme: http
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: spring-app
EOT
}
}

resource "kubernetes_deployment" "prometheus" {
metadata {
name = "prometheus-deployment"
namespace = kubernetes_namespace.spring.metadata[0].name
labels = {
app = "prometheus"
}
}

spec {
replicas = 1

selector {
match_labels = {
app = "prometheus"
}
}

template {
metadata {
labels = {
app = "prometheus"
}
}

spec {
service_account_name = kubernetes_service_account.prometheus.metadata[0].name
container {
name = "prometheus"
image = "prom/prometheus:v2.22.0"
args = [
"--config.file=/etc/prometheus/prometheus.yml",
"--web.route-prefix=/prometheus",
"--web.external-url=http://spring-app.example.com/prometheus"
]
port {
container_port = 9090
}
volume_mount {
name = "prometheus-config-volume"
mount_path = "/etc/prometheus"
}
}

volume {
name = "prometheus-config-volume"
config_map {
name = kubernetes_config_map.prometheus_config.metadata[0].name
}
}
}
}
}
}

resource "kubernetes_service" "prometheus_service" {
metadata {
name = "prometheus-service"
namespace = kubernetes_namespace.spring.metadata[0].name
}

spec {
selector = {
app = "prometheus"
}

port {
name = "http"
port = 90
target_port = 9090
}

type = "ClusterIP"
}
}
12 changes: 12 additions & 0 deletions terraform/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.29"
}
}
}

provider "kubernetes" {
config_path = var.kubeconfig
}
11 changes: 11 additions & 0 deletions terraform/secret.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resource "kubernetes_secret" "spring_app_secret" {
metadata {
name = "spring-app-secret"
namespace = kubernetes_namespace.spring.metadata[0].name
}
data = {
username = base64decode("c2F0")
password = base64decode("cGFzc3dvcmQ=")
}
type = "kubernetes.io/basic-auth"
}
19 changes: 19 additions & 0 deletions terraform/service.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
resource "kubernetes_service" "spring_app_service" {
metadata {
name = "spring-app-service"
namespace = kubernetes_namespace.spring.metadata[0].name
}

spec {
selector = {
app = "spring-app"
}

port {
port = 80
target_port = 8080
}

type = "ClusterIP"
}
}
5 changes: 5 additions & 0 deletions terraform/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "kubeconfig" {
description = "Path to the kubeconfig file"
type = string
default = "~/.kube/config"
}