|
2 | 2 | - [Background](#background)
|
3 | 3 | - [Architecture](#architecture)
|
4 | 4 | - [Prerequisites](#prerequisites)
|
| 5 | +- [Run the application](#run-the-application) |
| 6 | +- [Test the endpoints](#test-the-endpoints) |
| 7 | +- [Keycloak](#keycloak) |
| 8 | +- [Observability](#Observability) |
5 | 9 |
|
6 | 10 |
|
7 | 11 | # Background
|
@@ -99,4 +103,261 @@ A foundational framework for building **Spring Boot**-based microservices, desig
|
99 | 103 | - **Interactions**: REST/HTTP, JDBC, MongoDB protocol.
|
100 | 104 | - **Scalability**: Kubernetes supports replicas; Docker Compose for local dev.
|
101 | 105 |
|
102 |
| -# Prerequisites |
| 106 | +# Prerequisites |
| 107 | + |
| 108 | +- **Java 17+** (Recommended for Spring Boot 3.x) |
| 109 | +- **Maven 3.8+** |
| 110 | +- **Docker & Docker Compose** (for local containerized deployment) |
| 111 | +- **Minikube & Tilt** (for Kubernetes-based deployment) |
| 112 | +- **Httpie / cURL** (for API testing) |
| 113 | +- **Postman / Bruno** |
| 114 | + |
| 115 | +# Run the application |
| 116 | + |
| 117 | +You can start the application using either **Docker (Docker Compose)** or **Kubernetes (Tilt)**. |
| 118 | + |
| 119 | +Ensure that your **Docker Engine** is running before proceeding. |
| 120 | + |
| 121 | +### Running with Docker or Individual Services on Host OS |
| 122 | + |
| 123 | +1. Start Persistent Services: |
| 124 | +```shell |
| 125 | + cd docker && docker compose -f docker-compose-infra.yml up --build |
| 126 | +``` |
| 127 | +This command initializes **PostgreSQL** and **MongoDB**. |
| 128 | + |
| 129 | +2. Launch the Observability Stack: |
| 130 | + ```shell |
| 131 | + cd docker && docker compose -f docker-compose-observability.yml up --build |
| 132 | +``` |
| 133 | +This set up **Grafana**, **Tempo**, **Loki**, **Fluent-bit**, **Prometheus** |
| 134 | +3. Start the Microservices |
| 135 | +```shell |
| 136 | + sh run.sh docker |
| 137 | +``` |
| 138 | +or |
| 139 | +```shell |
| 140 | + sh run.sh |
| 141 | +``` |
| 142 | +This will start all microservices on their respective ports |
| 143 | + |
| 144 | +### Running with Tilt in Kubernetes env `(Minikube)` |
| 145 | +1. Let's Start minikube |
| 146 | +```shell |
| 147 | + minikube start \ |
| 148 | + --profile=microservice-deployment \ |
| 149 | + --memory=4g \ |
| 150 | + --cpus=4 \ |
| 151 | + --disk-size=30g \ |
| 152 | + --kubernetes-version=v1.27 \ |
| 153 | + --driver=docker |
| 154 | +``` |
| 155 | +```html |
| 156 | +😄 [microservice-deployment] minikube v1.35.0 on Darwin 15.3.1 |
| 157 | + ▪ MINIKUBE_ACTIVE_DOCKERD=microservice-deployment |
| 158 | +👉 Using Kubernetes 1.27.16 since patch version was unspecified |
| 159 | +✨ Using the docker driver based on user configuration |
| 160 | +📌 Using Docker Desktop driver with root privileges |
| 161 | +👍 Starting "microservice-deployment" primary control-plane node in "microservice-deployment" cluster |
| 162 | +🚜 Pulling base image v0.0.46 ... |
| 163 | +🔥 Creating docker container (CPUs=4, Memory=4096MB) ... |
| 164 | +🐳 Preparing Kubernetes v1.27.16 on Docker 27.4.1 ... |
| 165 | + ▪ Generating certificates and keys ... |
| 166 | + ▪ Booting up control plane ... |
| 167 | + ▪ Configuring RBAC rules ... |
| 168 | +🔗 Configuring bridge CNI (Container Networking Interface) ... |
| 169 | +🔎 Verifying Kubernetes components... |
| 170 | + ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5 |
| 171 | +🌟 Enabled addons: storage-provisioner, default-storageclass |
| 172 | +🏄 Done! kubectl is now configured to use "microservice-deployment" cluster and "default" namespace by default |
| 173 | +``` |
| 174 | +2. Enable Ingress addon |
| 175 | +```shell |
| 176 | + minikube addons enable ingress --profile microservice-deployment |
| 177 | +``` |
| 178 | +```markdown |
| 179 | +💡 ingress is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub. |
| 180 | + You can view the list of minikube maintainers at: https://github.com/kubernetes/minikube/blob/master/OWNERS |
| 181 | +💡 After the addon is enabled, please run "minikube tunnel" and your ingress resources would be available at "127.0.0.1" |
| 182 | + ▪ Using image registry.k8s.io/ingress-nginx/controller:v1.11.3 |
| 183 | + ▪ Using image registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.4 |
| 184 | + ▪ Using image registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.4 |
| 185 | +🔎 Verifying ingress addon... |
| 186 | +🌟 The 'ingress' addon is enabled |
| 187 | +``` |
| 188 | +3. Run this to make sure minikube can read images from local registry |
| 189 | +```shell |
| 190 | + eval $(minikube -p microservice-deployment docker-env) |
| 191 | +``` |
| 192 | +4. Let's build the images |
| 193 | +```shell |
| 194 | + sh build-images.sh |
| 195 | +``` |
| 196 | +```html |
| 197 | +Building Docker images for Kubernetes using Minikube... |
| 198 | +Building course-composite-service... |
| 199 | +[+] Building 31.5s (14/14) FINISHED docker:default |
| 200 | + => [internal] load build definition from Dockerfile 0.0s |
| 201 | + => => transferring dockerfile: 871B 0.0s |
| 202 | +. |
| 203 | +. |
| 204 | +. |
| 205 | +. |
| 206 | +gateway-service built successfully! |
| 207 | +All images built successfully! |
| 208 | +``` |
| 209 | +5. List the images |
| 210 | +```shell |
| 211 | + docker images |
| 212 | +``` |
| 213 | +or |
| 214 | +```shell |
| 215 | + docker image ls |
| 216 | +``` |
| 217 | + |
| 218 | +```html |
| 219 | +REPOSITORY TAG IMAGE ID CREATED SIZE |
| 220 | +gateway-service latest 2e07a4894e3d 3 minutes ago 339MB |
| 221 | +review-service latest 857bf2e92e8d 3 minutes ago 336MB |
| 222 | +course-service latest ad9a018bd4a3 3 minutes ago 359MB |
| 223 | +course-composite-service latest 5e1868bd77bc 3 minutes ago 328MB |
| 224 | +registry.k8s.io/ingress-nginx/controller <none> ee44bc236803 5 months ago 293MB |
| 225 | +registry.k8s.io/ingress-nginx/kube-webhook-certgen <none> a62eeff05ba5 5 months ago 63.8MB |
| 226 | +registry.k8s.io/kube-apiserver v1.27.16 1113933272f1 7 months ago 123MB |
| 227 | +registry.k8s.io/kube-controller-manager v1.27.16 2db343b95a4c 7 months ago 115MB |
| 228 | +registry.k8s.io/kube-scheduler v1.27.16 91ad8454afdd 7 months ago 57.7MB |
| 229 | +registry.k8s.io/kube-proxy v1.27.16 ea1f910af975 7 months ago 79.9MB |
| 230 | +registry.k8s.io/etcd 3.5.12-0 3861cfcd7c04 13 months ago 149MB |
| 231 | +registry.k8s.io/coredns/coredns v1.10.1 ead0a4a53df8 2 years ago 53.6MB |
| 232 | +registry.k8s.io/pause 3.9 e6f181688397 2 years ago 744kB |
| 233 | +gcr.io/k8s-minikube/storage-provisioner v5 6e38f40d628d 3 years ago 31.5MB |
| 234 | +``` |
| 235 | + |
| 236 | +You can also get Table view |
| 237 | +```shell |
| 238 | + minikube image ls --format table --profile microservice-deployment |
| 239 | +``` |
| 240 | +```html |
| 241 | +|----------------------------------------------------|----------|---------------|--------| |
| 242 | +| Image | Tag | Image ID | Size | |
| 243 | +|----------------------------------------------------|----------|---------------|--------| |
| 244 | +| docker.io/library/review-service | latest | 857bf2e92e8d6 | 336MB | |
| 245 | +| docker.io/library/course-composite-service | latest | 5e1868bd77bc2 | 328MB | |
| 246 | +| registry.k8s.io/kube-controller-manager | v1.27.16 | 2db343b95a4c2 | 115MB | |
| 247 | +| registry.k8s.io/kube-scheduler | v1.27.16 | 91ad8454afddc | 57.7MB | |
| 248 | +| docker.io/library/gateway-service | latest | 2e07a4894e3d5 | 339MB | |
| 249 | +| docker.io/library/course-service | latest | ad9a018bd4a3c | 359MB | |
| 250 | +| registry.k8s.io/ingress-nginx/kube-webhook-certgen | <none> | a62eeff05ba51 | 63.8MB | |
| 251 | +| registry.k8s.io/kube-apiserver | v1.27.16 | 1113933272f1e | 123MB | |
| 252 | +| registry.k8s.io/kube-proxy | v1.27.16 | ea1f910af975c | 79.9MB | |
| 253 | +| gcr.io/k8s-minikube/storage-provisioner | v5 | 6e38f40d628db | 31.5MB | |
| 254 | +| registry.k8s.io/coredns/coredns | v1.10.1 | ead0a4a53df89 | 53.6MB | |
| 255 | +| registry.k8s.io/pause | 3.9 | e6f1816883972 | 744kB | |
| 256 | +| registry.k8s.io/ingress-nginx/controller | <none> | ee44bc2368033 | 293MB | |
| 257 | +| registry.k8s.io/etcd | 3.5.12-0 | 3861cfcd7c04c | 149MB | |
| 258 | +|----------------------------------------------------|----------|---------------|--------| |
| 259 | +``` |
| 260 | +6. Let's start the Microservices |
| 261 | +```shell |
| 262 | + Tilt up |
| 263 | +``` |
| 264 | +```html |
| 265 | +Tilt started on http://localhost:10350/ |
| 266 | +v0.33.22, built 2025-01-03 |
| 267 | + |
| 268 | +(space) to open the browser |
| 269 | +(s) to stream logs (--stream=true) |
| 270 | +(t) to open legacy terminal mode (--legacy=true) |
| 271 | +(ctrl-c) to exit |
| 272 | +``` |
| 273 | +```shell |
| 274 | + tilt get uiresources |
| 275 | +``` |
| 276 | +```html |
| 277 | +NAME CREATED AT |
| 278 | +course-composite-service 2025-03-11T10:37:08Z |
| 279 | +prometheus 2025-03-11T10:37:08Z |
| 280 | +fluent-bit 2025-03-11T10:37:08Z |
| 281 | +uncategorized 2025-03-11T10:37:08Z |
| 282 | +review-service 2025-03-11T10:37:08Z |
| 283 | +gateway-service 2025-03-11T10:37:08Z |
| 284 | +keycloak 2025-03-11T10:37:08Z |
| 285 | +review-mongodb 2025-03-11T10:37:08Z |
| 286 | +tempo 2025-03-11T10:37:08Z |
| 287 | +loki 2025-03-11T10:37:08Z |
| 288 | +course-service 2025-03-11T10:37:08Z |
| 289 | +grafana 2025-03-11T10:37:08Z |
| 290 | +course-postgres 2025-03-11T10:37:08Z |
| 291 | +(Tiltfile) 2025-03-11T10:37:08Z |
| 292 | +``` |
| 293 | +```shell |
| 294 | + kubectl get pods,svc,ingress |
| 295 | +``` |
| 296 | +```markdown |
| 297 | +NAME READY STATUS RESTARTS AGE |
| 298 | +pod/course-composite-service-7b57d566c4-6tz89 1/1 Running 0 85s |
| 299 | +pod/course-postgres-5d748fd4cc-v72rq 0/1 ContainerCreating 0 2m43s |
| 300 | +pod/course-service-76b45b858b-z6dwx 1/1 Running 0 83s |
| 301 | +pod/fluent-bit-7f54dc97f-4zfxl 0/1 ContainerCreating 0 2m43s |
| 302 | +pod/gateway-service-588c7cff7b-f4gfl 1/1 Running 0 14s |
| 303 | +pod/grafana-7d8cd9f95d-6qrcd 0/1 ContainerCreating 0 2m43s |
| 304 | +pod/keycloak-dd58c7c99-9gb6j 0/1 ContainerCreating 0 2m43s |
| 305 | +pod/loki-0 0/1 ContainerCreating 0 2m43s |
| 306 | +pod/prometheus-74c59fb86c-792vs 0/1 ContainerCreating 0 2m43s |
| 307 | +pod/review-mongodb-695dc8799-4lpfm 0/1 ContainerCreating 0 2m43s |
| 308 | +pod/review-service-9fc59c466-nkg9z 1/1 Running 0 84s |
| 309 | +pod/tempo-54cb98d67f-kqzhv 0/1 ContainerCreating 0 2m43s |
| 310 | + |
| 311 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 312 | +service/course-composite-service ClusterIP 10.105.126.22 <none> 80/TCP 86s |
| 313 | +service/course-postgres ClusterIP 10.97.180.213 <none> 5432/TCP 2m44s |
| 314 | +service/course-service ClusterIP 10.107.49.7 <none> 80/TCP 83s |
| 315 | +service/fluent-bit ClusterIP 10.102.247.251 <none> 24224/TCP 2m43s |
| 316 | +service/gateway-service ClusterIP 10.96.187.185 <none> 80/TCP 14s |
| 317 | +service/grafana ClusterIP 10.96.161.239 <none> 3000/TCP 2m43s |
| 318 | +service/keycloak ClusterIP 10.109.159.232 <none> 8080/TCP 2m44s |
| 319 | +service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4m36s |
| 320 | +service/loki ClusterIP 10.100.62.50 <none> 3100/TCP 2m43s |
| 321 | +service/prometheus ClusterIP 10.99.78.150 <none> 9090/TCP 2m43s |
| 322 | +service/review-mongodb ClusterIP 10.101.104.79 <none> 27017/TCP 2m44s |
| 323 | +service/review-service ClusterIP 10.101.51.125 <none> 80/TCP 84s |
| 324 | +service/tempo ClusterIP 10.106.248.234 <none> 4317/TCP,4318/TCP,3200/TCP 2m43s |
| 325 | + |
| 326 | +NAME CLASS HOSTS ADDRESS PORTS AGE |
| 327 | +ingress.networking.k8s.io/gateway-ingress nginx * 192.168.49.2 80 2m44s |
| 328 | +ingress.networking.k8s.io/grafana-ingress nginx grafana.local 192.168.49.2 80 2m44s |
| 329 | +ingress.networking.k8s.io/keycloak-ingress nginx keycloak.local 192.168.49.2 80 2m44s |
| 330 | +ingress.networking.k8s.io/prometheus-ingress nginx prometheus.local 192.168.49.2 80 2m44s |
| 331 | +``` |
| 332 | + |
| 333 | + |
| 334 | +# Test the endpoints |
| 335 | + |
| 336 | +Make sure to run minikube tunnel on Mac |
| 337 | + |
| 338 | +| **Components** | **Docker** | **Kubernetes on Mac** | Note | |
| 339 | +|---------------------|----------------------------------------|--------------------------------------|------------------------------------------------| |
| 340 | +| **Gateway** | http://localhost:9000 | http://127.0.0.1:80 | /course-aggregate/{courseid}/with-details | |
| 341 | +| **CourseComposite** | http://localhost:8080/course-aggregate | http://127.0.0.1:80/course-aggregate | | |
| 342 | +| **Course** | http://localhost:8080/courses | http://127.0.0.1:80/courses | | |
| 343 | +| **Review** | http://localhost:8080/reviews | http://127.0.0.1:80/reviews | | |
| 344 | +| **Grafana** | http://localhost:3000 | http://grafana.local | Add `127.0.0.1 grafana.local` in /etc/hosts | |
| 345 | +| **Loki** | http://loki:3100 | http://loki:3100 | | |
| 346 | +| **Tempo** | http://tempo:3200 | http://tempo:3200 | | |
| 347 | +| **Fluent-bit** | http://fluent-bit:24224 | http://fluent-bit:24224 | http on 4318 and grpc on 4317 | |
| 348 | +| **Prometheus** | http://localhost:9090 | http://prometheus.local | Add `127.0.0.1 prometheus.local` in /etc/hosts | |
| 349 | +| **Keycloak** | http://localhost:8081 | http://keycloak.local | Add `127.0.0.1 keycloak.local` in /etc/hosts | |
| 350 | + |
| 351 | +Also, please use **OpenAPI specs**, **bruno** or **postman** for API details. I will add Swagger/SpringDoc as when I get time!! |
| 352 | +# Keycloak |
| 353 | +### Head to Keycloak using above table ```http://localhost:8081/admin``` or ```http://keycloak.local/admin``` |
| 354 | +Create realm using `course-management-realm-realm.json` provided in the repo |
| 355 | +- Login to Keycloak → Go to http://localhost:8080/admin admin/admin |
| 356 | +- Create Realm → Click "Create Realm" in the top-left dropdown |
| 357 | +- Import Realm → Click "Import", select realm.json, and click "Create" |
| 358 | +- Verify → Check Clients, Users, Roles, and Mappers in the new realm |
| 359 | + |
| 360 | + |
| 361 | + |
| 362 | +# Observability |
| 363 | +In progress |
0 commit comments