MasterCloudApps-Projects / shopping-purchases

Master cloud apps TFM purchases microservice

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Master cloud apps TFM - Purchases microservice

Table of contents

Description

  1. A purchases API Rest that allows as user:
    • Create a new shopping cart.
    • Get shopping cart info.
    • Delete shopping cart.
    • Complete shopping cart.
    • Set products in shopping cart.
    • Delete product from shopping cart.

Requirements

The next requirements are necessary to work with this project:

Technologies

Dependencies

Development dependencies

  • Spring Boot Devtools: additional set of tools that can make the application development experience a little more pleasant.
  • Spring Boot 2.6.2 Test dependencies: Testing provided libraries.
    • JUnit 5: The de-facto standard for unit testing Java applications.
    • Spring Test & Spring Boot Test: Utilities and integration test support for Spring Boot applications.
    • AssertJ: A fluent assertion library.
    • Hamcrest: A library of matcher objects (also known as constraints or predicates).
    • Mockito: A Java mocking framework.
    • JSONassert: An assertion library for JSON.
    • JsonPath: XPath for JSON.
  • Testcontainers: Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
  • JUnit Platform Suite Engine: The JUnit Platform supports the declarative definition and execution of suites of tests from any test engine using the JUnit Platform.
  • Githook-maven-plugin: Maven plugin to configure and install local git hooks.
  • Jib Maven Plugin: Jib is a Maven plugin for building Docker and OCI images for your Java applications.
  • Maven Release Plugin:This plugin is used to release a project with Maven, saving a lot of repetitive, manual work.

Project structure

Project is composed by the next modules:

  • .github/workflows: contains workflows for github actions
  • apis: folder with api definitions
    • rest: openapi definition with REST endpoints.
  • checkstyle: contains project style for IDE plugin.
  • docker: contains docker files
    • docker-compose.yml: allows to launch the app and its necessary resources as a docker image (MySQL database, Kafka, Zookeeper and purchases).
    • docker-compose-dev.yml: allows to launch the necessary resources to run the app in local (MySQL database, and users API).
    • dockerize.sh: script that build an app docker local image and to run it as a docker container.
  • helm/charts: helm chart is defined inside.
  • k8s: k8s manifests and scripts to apply all of them or remove them.
  • postman: postman collection and environments configuration.
  • src: source code.
    • main:
      • java: java code.
        • es.codeurjc.mca.tfm.purchases: parent package.
          • application: package containing application layer.
          • domain: package containing domain layer.
          • infrastructure: package containing infrastructure layer.
          • PurchasesApplication.java: contains main Purchases class.
      • resources: application resources.
        • application.yml: application properties for configuration.
        • keystore.jks: repository of security certificates.
    • test: test folder.
      • java: java code.
        • es.codeurjc.mca.tfm.purchases: parent package.
          • integration: contains integration tests.
            • application.controllers: application controller integration tests.
            • infrastructure: infrastructure (kafka) integration tests.
          • testcontainers: contains base class with testcontainers config that launch docker-compose-test file.
          • unit: contains unit tests.
      • resources: application test resources.
        • application-test.yml: application properties for testing configuration.
        • docker-compose-test.yml: docker compose file for testing purposes without volumes.
  • LICENSE: Apache 2 license file.
  • pom.xml: file that contains information about the project and configuration details used by Maven to build the project.
  • README.md: this file.

Configuration

Project configuration is in src/main/resources/application.yml file.

Properties description

  • security.jwt.token.secret-key: JWT token secret key.

  • server.ssl.key-store-password: Server key store

  • server.ssl.key-store: Server key store path.

  • server.port: Port where the app will run. Default value is 8446.

  • kafka.bootstrapAddress: Kafka hosts.

  • kafka.groupId: Kafka group. Default value is purchases-group

  • kafka.topics.createShoppingCart: create shopping carts topic. Default value is create-shopping-carts.

  • kafka.topics.deleteShoppingCart: delete shopping carts topic. Default value is delete-shopping-carts.

  • kafka.topics.completeShoppingCart: complete shopping carts topic. Default value is complete-shopping-carts.

  • kafka.topics.createOrder: create order topic. Default value is create-orders.

  • kafka.topics.validateItems: validate items topic. Default value is validate-items.

  • kafka.topics.updateItems: update shopping cart items topic. Default value is update-items.

  • kafka.topics.updateOrder: update order topic. Default value is update-orders.

  • kafka.topics.restoreStock: restore items stock topic. Default value is restore-stock.

  • kafka.topics.validateBalance: validate user balance topic. Default value is validate-balance.

  • kafka.topics.changeState: change order state topic. Default value is change-orders-state.

  • spring.datasource.url: Database url.

  • spring.datasource.username: Database username. Read value from RDS_USERNAME environment value, if not exists, then default value is root.

  • spring.datasource.password: Database password. Read value from RDS_PASSWORD environment value, if not exists, then default value is pass.

  • spring.datasource.hikari.initialization-fail-timeout: Time to wait for initial database connection in milliseconds. Default value is 60000.

Helm chart configurable values

The next variables are defined to use helm chart in helm/charts/values.yaml:

    • namespace: K8s namespace. By default tfm-dev-amartinm82.
  • mysql.create: Indicates if is necessary to deploy a MySQL container. By default false. If this variable is false then the mysql.image.* , mysql.replicas, mysql.resources.* variables won't have effect.
  • mysql.image.repository: database image name. By default mysql.
  • mysql.image.tag: image tag. By default 8.0.22.
  • mysql.host: database url. By default localhost.
  • mysql.user: database username. By default root.
  • mysql.password: database password. By default password.
  • mysql.database: database name. By default users.
  • mysql.port: database port. By default 3306.
  • mysql.replicas: database replicas. By default 1.
  • mysql.resources.requests.memory: database instance requested memory. By default 256Mi.
  • mysql.resources.requests.cpu: database instance requested cpu. By default 250m.
  • mysql.resources.limits.memory: database instance limit memory. By default 512Mi.
  • mysql.resources.limits.cpu: database instance requested cpu. By default 500m.
  • zookeeper.image.repository: zookeeper image name. By default k8s.gcr.io/kubernetes-zookeeper.
  • zookeeper.image.tag: zookeeper image tag. By default 1.0-3.4.10.
  • zookeeper.ports.server: zookeeper server port. By default 2888.
  • zookeeper.ports.le: zookeeper leader election port. By default 3888.
  • zookeeper.ports.client: zookeeper client port. By default 2181.
  • zookeeper.replicas: zookeeper replicas. By default 1.
  • zookeeper.resources.requests.memory: zookeeper instance requested memory. By default 256Mi.
  • zookeeper.resources.requests.cpu: zookeeper instance requested cpu. By default 250m.
  • zookeeper.resources.limits.memory: zookeeper instance limit memory. By default 512Mi.
  • zookeeper.resources.limits.cpu: zookeeper instance requested cpu. By default 500m.
  • zookeeper.runAsUser: user which run zookeeper in container. By default 1000.
  • zookeeper.fsGroup: file system group which run zookeeper in container. By default 1000.
  • kafka.replicas: kafka replicas. By default 1.
  • kafka.port: kafka port. By default 9092.
  • kafka.image.repository: kafka image name. By default gcr.io/google_containers/kubernetes-kafka.
  • kafka.image.tag: kafka image tag. By default 1.0-10.2.1.
  • kafka.resources.requests.memory: kafka instance requested memory. By default 512Mi.
  • kafka.resources.requests.cpu: kafka instance requested cpu. By default 500m.
  • kafka.resources.limits.memory: kafka instance limit memory. By default 1Gi.
  • kafka.resources.limits.cpu: kafka instance requested cpu. By default 1000m.
  • kafka.runAsUser: user which run kafka in container. By default 1000.
  • kafka.fsGroup: file system group which run kafka in container. By default 1000.
  • securityContext.runAsUser: user which run the app in container. By default 1001.
  • replicaCount: number of replicas for the app. By default 1.
  • image.repository: app image name. By default amartinm82/tfm-purchases.
  • image.tag: app image tag. By default latest.
  • service.type: app service type. By default ClusterIP.
  • service.port: app port. By default 8446.
  • resources.requests.memory: app instance requested memory. By default 512Mi.
  • resources.requests.cpu: app instance requested cpu. By default 500m.
  • resources.limits.memory: app instance limit memory. By default 1Gi.
  • resources.limits.cpu: app instance requested cpu. By default 1000m.

Usage

Installation

To install the project execute

mvn clean install

Run tests

mvn test

Run Unit Tests

mvn test -Punit

Run Integration Tests

mvn test -Pit

Run application

Locally

To run application locally:

  1. Up necessary services:
    docker-compose -f docker/docker-compose-dev.yml up
    
    Note: to stop services when they are not necessary run:
    docker-compose -f docker/docker-compose-dev.yml down
    
  2. Execute the app:
    mvn spring-boot:run
    

As docker container

To run application in a docker container execute:

cd docker
./dockerize.sh

To stop application in container when not necessary then run:

cd docker
docker-compose down

NOTE: If the containers are not accessible via localhost, it will be necessary to use ${DOCKER_HOST_IP} instead of localhost. To do this, give a value to the variable:

export DOCKER_HOST_IP=127.0.0.1

For Mac:

sudo ifconfig lo0 alias 10.200.10.1/24  # (where 10.200.10.1 is some unused IP address)
export DOCKER_HOST_IP=10.200.10.1

Checking application is running

In both cases, locally and As docker container you can use openapi definition or [Postman collection](./postman/Purchases API.postman_collection.json) to test running application.

  • Openapi: open openapi-v1.yml content in swagger editor and select localhost server and execute endpoints you want.
  • Postman: select TFM-purchases-local-env environment variable. Execute postman collection:
    • Manually: Set values you want in the endpoint body and run it.
    • Automatically: Set values to userToken, userId, productId and secondProductId variables, and execute Postman Collection Runner.

Contributing

To contribute to this project have in mind:

  1. It was developed using TBD, so only main branch exists, and is necessary that every code pushed to remote repository is ready to be deployed in production environment.
  2. In order to ensure the right style and code conventions, and that code to commit and push is ok, this project use pre-commit and pre-push git hooks. This is implemented using githook-maven-plugin.
    • pre-commit: This hook run maven-checkstyle-plugin and unit tests, and if fails, changes can't be committed.
    • pre-push: This hook run integrations tests, and if fails, commits can't be pushed.
  3. The API First approach was used, so please, if is necessary to modify API, in first place you must modify and validate openapi definition, and later, perform the code changes.
  4. Every code you modify or add must have a test that check the right behaviour of it (As a future task we'll add sonar to ensure there is a minimum coverage).

Deployment

This project has two available environments:

The mechanism used to deploy the application in any of the previous environment is via github actions, that are defined in workflows in folder .github/workflows. For this mechanism to work, it is necessary to add the following action secrets to the github repository:

  • DOCKERHUB_TOKEN: Token used to publish docker images in Dockerhub.
  • DOCKERHUB_USERNAME: username used to publish docker images in Dockerhub.
  • KUBECONFIG: kubeconfig of the k8s cluster where deploy the microservice.
  • MYSQL_HOST: MySQL host url.
  • MYSQL_PASSWORD: MySQL password.
  • MYSQL_USER: MySQL user.

PRE

When a push is done on remote branch (or a PR), github actions jobs defined in ci-cd.yml will be fired. All the jobs depends o the previous one, so if one of them fails, the project won't be deployed in the PRE environment:

  • checkstyle: Check style errors, and if there is any error fails.
  • tests: run unitary and integration tests in the branch, and if there is any error fails.
  • publish-image: Publish Docker image tfm-purchases with tag trunk in Dockerhub.
  • deploy: Deploy the previous generated image in PRE k8s cluster. For this, it uses the helm chart defined in helm/charts folder.

So, when we push in the main branch, because of the action execution, it results in if our code is right formatted, and works because it passes the tests, it is deployed and running on a k8s cluster of PRE environment.

PRO

Generate and deploy a new release

To deploy in PRO environment is necessary to generate a new release. To do that, execute:

mvn -Dusername=<git_user> release:prepare

It will tag the source code with the current version of pom.xml, push tag in remote repository, and bump project version (for detail see Maven Release Plugin phases)).

Due to the new tag is pushed, the workflow defined in release.yml is executed. It has several jobs:

  • check-tag: Verifies if pushed tag match with package version (to avoid manually tags creation).
  • publish-package: Depends on previous job. Publish mvn package version in github packages repository.
  • publish-release: Depends on previous job. Publish the release in github.
  • publish-image: Depends on previous job. Generate docker image of app, tagging it with latest and {pushed_tag} (i.e: if we generated the tag 1.2.0. it tags the new image with 1.2.0), and publishing them in Dockerhub.
  • deploy: Depends on previous job. It deploys application in PRO k8s cluster using {pushed_tag} image. For this, it uses the helm chart defined in helm/charts folder.

Deploy existing release

To deploy an existing release you can execute in github manual workflow defined in manual-release-deploy.yml. Select main branch (the only one that exists), and introduce the release to deploy in the input. The release will be deployed in PRO environment.

Checking application is deployed

Like in Usage > Run application > Checking application is running you can check if the application is successfully deployed using Openapi definition or Postman collection.

Developers

This project was developed by:

👤 Álvaro Martín - 📨 amartinm82@gmail.com

Appendix

Mac M1 issues

  • Error deploying k8s manifests in minikube:
"no matching manifest for linux/arm64/v8 in the manifest list entries"

About

Master cloud apps TFM purchases microservice

License:Apache License 2.0


Languages

Language:Java 97.6%Language:Smarty 1.5%Language:Shell 1.0%