Mastering Spring Boot: Building a Dynamic Secret Santa Generator Web Application using Azure DevOps

Mastering Spring Boot: Building a Dynamic Secret Santa Generator Web Application using Azure DevOps

Senta Generate

The Secret Santa Generator is a web application built using Spring Boot technologies, Thymeleaf views, JPA, H2 Database, and more. It features a Spring Model, View, and Controller (MVC) architecture along with Service and Repository layers. This project is designed to facilitate the popular Christmas game "Secret Santa," where friends draw names to decide who they will give a present to.

Prerequisites

Before diving into this project, here are some skills and tools you should be familiar with:

  • [x] Clone repository for terraform code
    Note: Replace resource names and variables as per your requirement in terraform code

    • Update terraform.tfvars.
  • [x] App Repo (SecretSanta-Generator)

  • [x] Azure Account: You’ll need an Azure account to create resources like virtual Machines, and AKS cluster, and manage pipelines.

  • [x] Terraform Knowledge: Familiarity with Terraform in provisioning, managing, and cleaning up infrastructure.

  • [x] Basic Kubernetes (AKS): A basic understanding of Kubernetes, especially Azure AKS, to deploy and manage containers.

  • [x] Docker Knowledge: Basic knowledge of Docker for containerizing applications.

  • [x] GitHub: Experience with GitHub for version control and managing repositories.

  • [x] Command-Line Tools: Basic comfort with using the command line for managing infrastructure and services.

  • [x] Basic CI/CD Knowledge: Some understanding of Continuous Integration and Deployment is recommended.

  • [x] Azure Container Registry (ACR): Set up ACR to store your Docker images.

  • [x] Linux VM: Docker must be installed on a Linux virtual machine to run containers.

Key Points

  • Technologies Used: Spring Boot, Thymeleaf, JPA, H2 Database

  • Architecture: Spring MVC, Service, and Repository layers

  • Functionality: Randomly generates Secret Santa matches

  • Learning Objectives: Spring development, database management, application architecture

Advantages of Using This Project

  • Educational Value: This project is an excellent resource for learning Spring development, database management, and industry-standard application architecture.

  • Practical Application: It provides a practical solution to the "Secret Santa problem," making it useful for real-world applications.

  • Comprehensive Technology Stack: The project covers a wide range of technologies, including Java Spring Core, HTML5, CSS, Thymeleaf, JPA, and H2 Database.

  • MVC Architecture: It demonstrates the use of MVC architecture, which is a widely adopted design pattern in web development.

  • In-Memory Database: The use of H2 in-memory database allows for easy setup and testing without the need for an external database.

Step-by-Step Description

  1. Project Setup

    • Clone the Repository: Clone the project repository from the source control.

    • Import into IDE: Import the project into your preferred Integrated Development Environment (IDE) such as IntelliJ IDEA or Eclipse.

    • Build the Project: Use Maven or Gradle to build the project and resolve dependencies.

  2. Application Configuration

    • Spring Boot Configuration: Configure Spring Boot application properties in application.properties or application.yml.

    • Database Configuration: Set up the H2 in-memory database configuration for development and testing purposes.

  3. Developing the Application

    • Model Layer: Define the data models using JPA annotations.

    • Repository Layer: Create repository interfaces for data access operations.

    • Service Layer: Implement business logic in service classes.

    • Controller Layer: Develop controllers to handle HTTP requests and responses.

  4. Thymeleaf Integration

    • View Templates: Create Thymeleaf templates for the user interface.

    • Data Binding: Bind data from the model to the view using Thymeleaf syntax.

  5. Implementing Secret Santa Logic

    • Random Pairing Algorithm: Implement the logic to randomly generate Secret Santa matches.

    • Directed Graph Solution: Ensure the solution handles the complexities of the "Secret Santa problem" by creating a directed graph.

  6. Testing and Debugging

    • Unit Tests: Write unit tests for the service and repository layers.

    • Integration Tests: Develop integration tests to ensure the application components work together as expected.

    • Debugging: Use the IDE's debugging tools to troubleshoot and fix any issues.

  7. Deployment

    • Package the Application: Package the application as a JAR or WAR file.

    • Deploy to Server: Deploy the packaged application to a web server or cloud platform.

Setting Up the Infrastructure

I have created a Terraform code to set up the entire infrastructure, including the installation of required applications, tools, and the AKS cluster automatically created.

NoteAKS cluster creation will take approx. 10 to 15 minutes.

  • ⇒ Virtual machines will be created named as "devopsdemovm"

  • ⇒ Docker Install

  • ⇒ Azure Cli Install

  • ⇒ KubeCtl Install

  • ⇒ AKS Cluster Setup

Virtual Machine creation

First, we'll create the necessary virtual machines using terraform code.

Below is a terraform Code:

Once you clone repo and run the terraform command.

$ ls -l
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
dar--l          26/12/24   7:16 PM                pipeline
dar--l          23/12/24   3:38 PM                scripts
-a---l          25/12/24   2:31 PM            600 .gitignore
-a---l          26/12/24   9:29 PM           6571 VM_ACR.tf
-a---l          26/12/24   9:29 PM            892 main.tf
-a---l          26/12/24   9:29 PM            567 output.tf
-a---l          26/12/24   9:29 PM            269 provider.tf
-a---l          26/12/24   9:30 PM            223 terraform.tfvars
-a---l          26/12/24   9:30 PM            615 variable.tf

You need to run the following terraform command.

Now, run the following command.

terraform init
terraform fmt
terraform validate
terraform plan
terraform apply 
# Optional <terraform apply --auto-approve>

After running the Terraform command, we will check the following to ensure everything is set up correctly with Terraform.

Inspect the Cloud-Init logs:

Once connected to VM then you can check the status of the user_data script by inspecting the log files

# Primary log file for cloud-init
sudo tail -f /var/log/cloud-init-output.log
                    or 
sudo cat /var/log/cloud-init-output.log | more
  • If the user_data script runs successfully, you will see output logs and any errors encountered during execution.

  • If there’s an error, this log will provide clues about what failed.

Verify the Installation

  • [x] Docker version
ubuntu@ip-172-31-95-197:~$ docker --version
Docker version 24.0.7, build 24.0.7-0ubuntu4.1


docker ps -a
ubuntu@ip-172-31-94-25:~$ docker ps
  • [x] kubectl version
ubuntu@ip-172-31-89-97:~$ kubectl version
Client Version: v1.31.1
Kustomize Version: v5.4.2
  • [x] Azure cli version
azureuser@devopsdemovm:~$ az version
{
  "azure-cli": "2.67.0",
  "azure-cli-core": "2.67.0",
  "azure-cli-telemetry": "1.1.0",
  "extensions": {}
}

Step-by-Step Process:

Step-01: Create project in Azure DevOps

Step-02: Clone the Repo in Azure DevOps

Step-03: To Configure self-hosted Linux agents in Azure DevOps

  • Need to configure Self-hosted Linux agents/integrate to azure DevOps

  • run the following command as part of provisioning the server, we have already installed the agent.

azureuser@devopsdemovm:~/myagent$ ls -l
total 144072
drwxrwxr-x 26 azureuser azureuser     20480 Nov 13 10:54 bin
-rwxrwxr-x  1 azureuser azureuser      3173 Nov 13 10:45 config.sh
-rwxrwxr-x  1 azureuser azureuser       726 Nov 13 10:45 env.sh
drwxrwxr-x  7 azureuser azureuser      4096 Nov 13 10:46 externals
-rw-rw-r--  1 azureuser azureuser      9465 Nov 13 10:45 license.html
-rw-rw-r--  1 azureuser azureuser      3170 Nov 13 10:45 reauth.sh
-rw-rw-r--  1 azureuser azureuser      2753 Nov 13 10:45 run-docker.sh
-rwxrwxr-x  1 azureuser azureuser      2014 Nov 13 10:45 run.sh
-rw-r--r--  1 root      root      147471638 Nov 13 12:22 vsts-agent-linux-x64-4.248.0.tar.gz
  • Configure the agent
~/myagent$ ./config.sh

Type 'Y'

#Server URL
Azure Pipelines: https://dev.azure.com/{your-organization}
https://dev.azure.com/mrbalraj
  • Give any name for agent
devops-demo_vm
  • We have to Optionally run the agent interactively. If you didn't run as a service above:
~/myagent$ ./run.sh &

Now, Agent is online ;-)

Additional settings needs to be done as below

image-25

image-26

image-27

image-28

image-29

Step-04: Setup AKS Cluster

  • Note: Key concept overview of pipeline.

    image-9

Step-05: Install SonarQube Extension

  • Now, we will integrate SonarQube into the same pipeline. We need to search for it in the marketplace and select SonarQube.

  • Install the SonarQube Extension. Now, we will integrate SonarQube into the same pipeline. We need to search for it in the marketplace and select SonarQube as shown below.

Step-06: Setup SonarQube.

  • Note the agent's public IP address and try to access it on port 9000.

  • publicIPaddressofVM:9000

  • Generate the SonarQubeToken

Step-07: Configure the Service Connection for "Azure Resource Manager"

  • Steps to configure connection for Azure Resource Manager:

  • Configure the Service Connection:

    • Select the project and project setting:

      image-8

Will create three connection as below

    1. SonarQube
    1. Docker hub
    1. AKS Cluster
  • Steps to configure connection for SonarQube:

  • Steps to configure connection for DockerHub:

  • Steps to configure connection for Kubernetes:

image-13

IIt will prompt you for login credentials, and you should use the same credentials you used for the UI portal login.

image-14

image-15

image-16

image-17

image-18

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
# master   
- none

pool:
  name: devops-demo_vm
  demands: agent.name -equals agent-1

stages:
- stage: CompileJob
  displayName: 'Compile Stage'
  jobs:
  - job: CompileJob
    displayName: 'Compile Job'
    steps:
    - script: mvn compile
      displayName: 'Compile Step'

- stage: Test
  displayName: 'Test Stage'
  jobs:
  - job: TestJob
    displayName: 'Test Job'
    steps:
    - script: mvn test
      displayName: 'Test Step'

# Add Trivy FS scan image.
- stage: Trivy_FS_Scan
  displayName: 'Trivy-FS-Stage'
  jobs:
  - job: TrivyFSJob
    displayName: 'TrivyFSJob'
    steps:
    - script: trivy fs --format table -o trivy-fs-report.html .
      displayName: 'TrivyFS-Scan_Step'
  • Add Stages for SonarQube

  • taking help from the helper as below to complete the stage for sonarqube

    image-19

    image-20

    image-21

    image-22

- stage: SonarQube_Scan
  displayName: 'SonarQube-Stage'
  jobs:
  - job: SonarQubeSJob
    displayName: 'SonarQubeJob'
    steps:
    - task: SonarQubePrepare@7
      inputs:
        SonarQube: 'sonar-conn'
        scannerMode: 'cli'
        configMode: 'manual'
        cliProjectKey: 'secretsanta'
        cliProjectName: 'secretsanta'
        cliSources: '.'
        extraProperties: 'sonar.java.binaries=.'
    - task: SonarQubeAnalyze@7
      inputs:
        jdkversion: 'JAVA_HOME'
  • add build package stage
- stage: Build
  displayName: 'Build-Stage'
  jobs:
  - job: BuildJob
    displayName: 'BuildJob'
    steps:
    - script: mvn package
      displayName: 'Build_package_Step'

Run the pipeline and status of pipeline as below-

image-23

  • Add Docker build and push image

    image-30

    image-31

- stage: Docker
  displayName: 'Docker-Stage'
  jobs:
  - job: DockerJob
    displayName: 'Docker Job'
    steps:
    - script: mvn package
      displayName: 'Build_package_Step'
    - task: Docker@2
      inputs:
        containerRegistry: 'docker-conn'
        repository: 'balrajsi/secretsanta'
        command: 'buildAndPush'
        Dockerfile: '**/Dockerfile'
        tags: 'latest'
  • Trivy Image scan
- stage: Trivy_Image_Scan
  displayName: 'Trivy-Image-Stage'
  jobs:
  - job: TrivyImageJob
    displayName: 'TrivyImageJob'
    steps:
    - script: trivy image --format table -o trivy-image-report.html balrajsi/secretsanta:latest
      displayName: 'TrivyImage-Scan_Step'

Pipeline status

image-32

  • update the image name in manifest file.

  • add K8s Stage in pipeline.

- stage: K8_Deploy
  displayName: 'K8_Deploy_Stage'
  jobs:
  - job: K8s_Deploy_Job
    displayName: 'K8s_Deploy_Job'
    steps:
    - task: KubectlInstaller@0
      inputs:
        kubectlVersion: 'latest'
    - task: Kubernetes@1
      inputs:
        connectionType: 'Kubernetes Service Connection'
        kubernetesServiceEndpoint: 'k8s-conn'
        namespace: 'default'
        command: 'apply'
        useConfigurationFile: true
        configuration: 'deployment-service.yaml'

Run the pipeline and got below message

image-45

image-46

Once i approved it and pipeline works fine.

image-47

image-50

Project Status in SonarQube:

image-33

image-63

Image View in Docker Hub

image-34

View status in Azure UI:

image-51

image-52

image-53

image-54

On Agent VM

sudo snap install kubectl --classic

az login

image-56

from UI | K8s

image-57

  • First, we will create a folder in the repository called 'scripts' and update the .sh file as shown below. We will create a shell script to get an updated image tag in case a new image is being created..

  • Don't forget to update the container registroty name in the script file.

Now, try to get all resouces and you will noticed there is an error related to "ImagePullBackoff".

kubectl get all

I am getting below error message.

image-58

Solution: As we are using private registory and we need to use 'imagepullsecrets'

Go to azure registory and get the password which will be used in below command

image-60

  • command to create ACRImagePullSecret
kubectl create secret docker-registry <secret-name> \
    --namespace <namespace> \
    --docker-server=<container-registry-name>.azurecr.io \
    --docker-username=<service-principal-ID> \
    --docker-password=<service-principal-password>

Explanation of the Command:

kubectl create secret docker-registry:

- This creates a new Kubernetes secret of type docker-registry.
<secret-name>:

- The name of the secret being created. For example, acr-credentials.
--namespace <namespace>:

- Specifies the namespace in which the secret will be created. If omitted, it defaults to the default namespace.
Replace <namespace> with the desired namespace name.
--docker-server=<container-registry-name>.azurecr.io:

- The URL of your container registry. For Azure Container Registry (ACR), the format is <container-registry-name>.azurecr.io.
Replace <container-registry-name> with your ACR name.
--docker-username=<service-principal-ID>:

- The username to authenticate with the container registry. For Azure, this is typically a service principal's application (client) ID.
--docker-password=<service-principal-password>:

- The password (or secret) associated with the service principal used for authentication.

To get a token, click on container registory

image-79

kubectl create secret docker-registry acr-credentials \
    --namespace default \
    --docker-server=aconregee7b05ba.azurecr.io \
    --docker-username=aconregee7b05ba \
    --docker-password=<token>

image-61

  • Command to delete secret
kubectl delete secret acr-credential --namespace default

Also, update the manifest file as below.

image-64

  • To check the deployment
kubectl get deploy vote -o yaml
  • Verify services and try to access the application
kubectl get svc
kubectl get node -o wide
kubectl describe svc argocd-server -n argocd
  • Now, we will open one more port in VMSS

    image-66

    image-58


azureuser@devopsdemovm:~$ kubectl get all

NAME                                    READY   STATUS    RESTARTS   AGE
pod/santa-deployment-786c6cb64d-6jrf6   1/1     Running   0          8m50s
pod/santa-deployment-786c6cb64d-sgtgp   1/1     Running   0          8m50s

NAME                 TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP      10.0.0.1       <none>        443/TCP          155m
service/santa-ssvc   LoadBalancer   10.0.191.143   <pending>     8080:32144/TCP   8m51s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/santa-deployment   2/2     2            2           8m51s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/santa-deployment-786c6cb64d   2         2         2       8m51s

 kubectl get nodes -o wide
NAME                             STATUS   ROLES    AGE    VERSION   INTERNAL-IP   EXTERNAL-IP     OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
aks-system-36575698-vmss000000   Ready    <none>   155m   v1.31.2   10.224.0.4    52.191.142.89   Ubuntu 22.04.5 LTS   5.15.0-1075-azure   containerd://1.7.23-1

from Agent VM:

image-55

Congratulations :-) the application is working and accessible.

image-59

image-60

image-61

image-62

Step-05: Clean up the images and container registroy using the pipeline.

  • First create Service Connection in Azure Devops.

  • Once you create a connection, make sure to note down the connection ID, as it will be used in the pipeline.

  • On the agent machine, ensure you are logged in with Azure, and the connection is active. If not, log in using the following steps.

      az login --use-device-code
    

Environment Cleanup:

  • As we are using Terraform, we will use the following command to delete

  • Delete all deployment/Service first

    kubectl delete deployment.apps/santa-deployment kubectl delete service/santa-ssvc

Now, time to delete the AKS Cluster and Virtual machine.

run the terraform command.

Terraform destroy --auto-approve

Conclusion

The Secret Santa Generator web application is a comprehensive project that showcases various aspects of Spring development, database management, and web application architecture. It provides a practical solution to a common problem while offering valuable learning opportunities for developers.

Ref Link: