From c42a36cd37eefa2b08076e0cccf146809855fee2 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Wed, 27 Mar 2024 16:29:09 +0700 Subject: [PATCH 1/6] BugFix - 5 crash container when deploying to k8s - https://github.com/hamony/reservation-service/issues/5 (#6) * Fixed Crash container when deploying to K8s https://github.com/hamony/reservation-service/issues/5 * Fixed typo reservation service * Fixed Crash container when deploying to K8s https://github.com/hamony/reservation-service/issues/5 Persistent object - Fixed Crash container when deploying to K8s --------- Co-authored-by: Khoa Nguyen --- ...rkflow.yaml => pull-request-workflow.yaml} | 0 .../reservationservice/domain/Guest.java | 2 + .../domain/Reservation.java | 8 +++- .../reservationservice/domain/Room.java | 45 +++++++++++++++++++ .../reservationservice/domain/RoomType.java | 5 +++ 5 files changed, 59 insertions(+), 1 deletion(-) rename .github/workflows/{merge-request-workflow.yaml => pull-request-workflow.yaml} (100%) create mode 100644 src/main/java/com/ubluetech/reservationservice/domain/RoomType.java diff --git a/.github/workflows/merge-request-workflow.yaml b/.github/workflows/pull-request-workflow.yaml similarity index 100% rename from .github/workflows/merge-request-workflow.yaml rename to .github/workflows/pull-request-workflow.yaml diff --git a/src/main/java/com/ubluetech/reservationservice/domain/Guest.java b/src/main/java/com/ubluetech/reservationservice/domain/Guest.java index d3dd1e0..316026c 100644 --- a/src/main/java/com/ubluetech/reservationservice/domain/Guest.java +++ b/src/main/java/com/ubluetech/reservationservice/domain/Guest.java @@ -1,8 +1,10 @@ package com.ubluetech.reservationservice.domain; import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import lombok.Getter; +@Embeddable @Getter class Guest { @Column(nullable = false) diff --git a/src/main/java/com/ubluetech/reservationservice/domain/Reservation.java b/src/main/java/com/ubluetech/reservationservice/domain/Reservation.java index e374e14..a684d53 100644 --- a/src/main/java/com/ubluetech/reservationservice/domain/Reservation.java +++ b/src/main/java/com/ubluetech/reservationservice/domain/Reservation.java @@ -1,6 +1,7 @@ package com.ubluetech.reservationservice.domain; import java.time.LocalDate; +import java.util.Set; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -19,7 +20,12 @@ public class Reservation { @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private Guest guest; - private Room room; + + @OneToMany(mappedBy = "reservation", + cascade = CascadeType.ALL, + orphanRemoval = true) + private Set rooms; + private LocalDate checkInDate; private LocalDate checkOutDate; } diff --git a/src/main/java/com/ubluetech/reservationservice/domain/Room.java b/src/main/java/com/ubluetech/reservationservice/domain/Room.java index 51a384e..03e2d4d 100644 --- a/src/main/java/com/ubluetech/reservationservice/domain/Room.java +++ b/src/main/java/com/ubluetech/reservationservice/domain/Room.java @@ -3,13 +3,58 @@ import java.math.BigDecimal; import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Getter; +@Entity +@Table(name = "reserved_room") @Getter class Room { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + // The parent reference is marked as non-updatable, to prevent breaking the equals/hashCode contract + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "reservation_id", + nullable = false, + updatable = false) + private Reservation reservation; + @Column(nullable = false) private String roomNumber; + @Enumerated(EnumType.STRING) + private RoomType roomType; + @Column(nullable = false) private BigDecimal price; + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (!(obj instanceof Room)) + return false; + + return id != null && + id.equals(((Room) obj).getId()); + } + + } diff --git a/src/main/java/com/ubluetech/reservationservice/domain/RoomType.java b/src/main/java/com/ubluetech/reservationservice/domain/RoomType.java new file mode 100644 index 0000000..9b4e514 --- /dev/null +++ b/src/main/java/com/ubluetech/reservationservice/domain/RoomType.java @@ -0,0 +1,5 @@ +package com.ubluetech.reservationservice.domain; + +public enum RoomType { + SINGLE, DOUBLE, STUDIO, QUEEN, KING, TWIN, LUXURY, SUITE, VILLA, SMOKING +} From 44fbc929c7dee8c1249241052a6b504a3917ab56 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 29 Mar 2024 21:02:54 +0700 Subject: [PATCH 2/6] Apply deploy and build image on local by Google build docker (#8) Co-authored-by: Khoa Nguyen --- .github/workflows/release-workflow.yml | 2 +- Dockerfile | 42 ----------------------- build-deploy-ks8.sh | 8 +++++ compose.yaml | 10 ------ k8s/deployment.yaml | 40 +++++++++++++++++++++ k8s/service.yaml | 13 +++++++ pom.xml | 3 -- src/main/resources/application.properties | 8 +++++ 8 files changed, 70 insertions(+), 56 deletions(-) delete mode 100644 Dockerfile create mode 100755 build-deploy-ks8.sh delete mode 100644 compose.yaml create mode 100644 k8s/deployment.yaml create mode 100644 k8s/service.yaml diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 77a0748..270e489 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -40,6 +40,6 @@ jobs: IMAGE_TAG: ${{ steps.vars.outputs.tag_name }} if: ${{ env.IMAGE_TAG != '' }} # Only build and push if a tag is present run: | - ./mvnw clean package jib:dockerBuild -DskipTests -Djib.to.tags=${{ env.IMAGE_TAG }} + ./mvnw clean package jib:dockerBuild -DskipTests -Dimage=reservation-service:${{ env.IMAGE_TAG }} docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} docker push ${{ secrets.DOCKER_USERNAME }}/reservation-service:${{ env.IMAGE_TAG }} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3540e98..0000000 --- a/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -# syntax=docker/dockerfile:1.4 -# the first stage of our build will extract the layers -FROM maven:3.9.6-eclipse-temurin-21-alpine AS builder - -# Create user to run app as (instead of root) -RUN addgroup -S app && adduser -S app -G app -# Use user "app" -USER app - -WORKDIR /workdir/server -COPY pom.xml /workdir/server/pom.xml -RUN mvn dependency:go-offline - -COPY src /workdir/server/src -RUN mvn install - -FROM builder AS prepare-production -RUN mkdir -p target/dependency -WORKDIR /workdir/server/target/dependency -RUN jar -xf ../*.jar - -# the second stage of our build will copy the extracted layers -FROM eclipse-temurin:21-jdk-alpine -EXPOSE 8080 -VOLUME /tmp -ARG DEPENDENCY=/workdir/server/target/dependency - -# FROM eclipse-temurin:17-jre as builder -# WORKDIR application -# ARG JAR_FILE=target/*.jar -# COPY ${JAR_FILE} application.jar -# RUN java -Djarmode=layertools -jar application.jar extract - -# COPY --from=builder application/dependencies/ ./ -# COPY --from=builder application/spring-boot-loader/ ./ -# COPY --from=builder application/snapshot-dependencies/ ./ -# COPY --from=builder application/application/ ./ -# ENTRYPOINT [ "java", "org.springframework.boot.loader.JarLauncher" ] -COPY --from=prepare-production ${DEPENDENCY}/BOOT-INF/lib /app/lib -COPY --from=prepare-production ${DEPENDENCY}/META-INF /app/META-INF -COPY --from=prepare-production ${DEPENDENCY}/BOOT-INF/classes /app -ENTRYPOINT ["java","-cp","app:app/lib/*","com.ubluetech.reservation.ReservationApplication"] diff --git a/build-deploy-ks8.sh b/build-deploy-ks8.sh new file mode 100755 index 0000000..0ef0226 --- /dev/null +++ b/build-deploy-ks8.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +eval $(minikube docker-env) +# Jib google docker build with minikube +./mvnw com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=reservation-service:v0.1.0-alpha + +# Build deployment and service +kubectl apply -f ./k8s \ No newline at end of file diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index 49d35a8..0000000 --- a/compose.yaml +++ /dev/null @@ -1,10 +0,0 @@ -version: '3.6' -services: - reservation-service: - build: . - ports: - - 8080:8080 - networks: - - microservices -networks: - microservices: \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..1305541 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reservation-service-deployment + labels: + app: reservation-service +spec: + replicas: 1 + selector: + matchLabels: + app: reservation-service + template: + metadata: + labels: + app: reservation-service + spec: + automountServiceAccountToken: false + containers: + - name: reservation-service + image: reservation-service:v0.1.0-alpha + resources: + limits: + cpu: "1" + memory: "1Gi" + + # readinessProbe: + # httpGet: + # port: 8080 + # path: /actuator/health/readiness + + # livenessProbe: + # httpGet: + # port: 8080 + # path: /actuator/health/liveness + + # lifecycle: + # preStop: + # exec: + # command: ["sh", "-c", "sleep 10"] + \ No newline at end of file diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..a4508ba --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: reservation-service-kuservice +spec: + type: LoadBalancer + selector: + app: reservation-service + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 385d0f5..985957c 100644 --- a/pom.xml +++ b/pom.xml @@ -144,9 +144,6 @@ eclipse-temurin:21-jdk-alpine - - docker.io/khoazamioza/reservation-service - diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e49a891..4ff8080 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,10 @@ spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update + +# Enable The Actuator Probe Endpoints +management.endpoint.health.probes.enabled=true +management.health.livenessstate.enabled=true +management.health.readinessstate.enabled=true + +# Handling In Fflight Requests +server.shutdown=graceful From 1021cec2020c34e02cc8fd1916713b436c0671ff Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Tue, 2 Apr 2024 14:19:48 +0700 Subject: [PATCH 3/6] Feature/using skaffold facilitates continuous development (#13) * Apply deploy and build image on local by Google build docker * Easy using skaffold on local development --------- Co-authored-by: Khoa Nguyen --- build-deploy-ks8.sh | 2 +- k8s/deployment.yaml | 1 + skaffold.yaml | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 skaffold.yaml diff --git a/build-deploy-ks8.sh b/build-deploy-ks8.sh index 0ef0226..51f5523 100755 --- a/build-deploy-ks8.sh +++ b/build-deploy-ks8.sh @@ -1,6 +1,6 @@ #!/bin/bash -eval $(minikube docker-env) +# eval $(minikube docker-env) # Jib google docker build with minikube ./mvnw com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=reservation-service:v0.1.0-alpha diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 1305541..10dbcab 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -18,6 +18,7 @@ spec: containers: - name: reservation-service image: reservation-service:v0.1.0-alpha + imagePullPolicy: Never # SHOULD NOT DO IT ON PRODUCTION the kubelet does not try fetching the image. If the image is somehow already present locally resources: limits: cpu: "1" diff --git a/skaffold.yaml b/skaffold.yaml new file mode 100644 index 0000000..c44ee5a --- /dev/null +++ b/skaffold.yaml @@ -0,0 +1,13 @@ +apiVersion: skaffold/v4beta9 +kind: Config +metadata: + name: reservation-service +build: + artifacts: + - image: reservation-service + jib: + project: com.ubluetech:reservation-service +manifests: + rawYaml: + - k8s/deployment.yaml + - k8s/service.yaml From 5dda72f3fc8bea5a127694a0f91703856d1eb29b Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Tue, 9 Apr 2024 17:52:06 +0700 Subject: [PATCH 4/6] Event Brainstoming and Kafka deploy (#15) Co-authored-by: Khoa Nguyen --- README.md | 144 +++++++++++++++++++++++- kustomize/base/application.yaml | 4 + {k8s => kustomize/base}/deployment.yaml | 9 ++ kustomize/base/kafka-local.yaml | 118 +++++++++++++++++++ kustomize/base/kustomization.yaml | 14 +++ kustomize/base/namespace.yaml | 5 + {k8s => kustomize/base}/service.yaml | 1 + kustomize/qa/kustomization.yaml | 8 ++ kustomize/qa/update-replicas.yaml | 6 + skaffold.yaml | 6 +- 10 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 kustomize/base/application.yaml rename {k8s => kustomize/base}/deployment.yaml (81%) create mode 100644 kustomize/base/kafka-local.yaml create mode 100644 kustomize/base/kustomization.yaml create mode 100644 kustomize/base/namespace.yaml rename {k8s => kustomize/base}/service.yaml (86%) create mode 100644 kustomize/qa/kustomization.yaml create mode 100644 kustomize/qa/update-replicas.yaml diff --git a/README.md b/README.md index d9cc1b9..dd5d0c4 100644 --- a/README.md +++ b/README.md @@ -1 +1,143 @@ -# reservation-service +# Reservation-Service +Bootstrap Skaffold configuration +Run the following command to generate a skaffold.yaml config file: +skaffold init + +### Use skaffold dev +Run the following command to begin using Skaffold for continuous development +skaffold dev + +### Provide external IP +minikube tunnel + +### Kafka +#### Create a topic and recovery +kubectl exec -it kafka-0 -- bash + +#### Create a topic named reservation with three partitions and a replication factor of 3. +kafka-topics --create --topic reservation --partitions 2 --replication-factor 2 --bootstrap-server kafka-0.kafka-headless.kafka.svc.cluster.local:9092 + +#### Verify the topic partitions are replicated across all three brokers: +kafka-topics --describe --topic reservation --bootstrap-server kafka-0.kafka-headless.kafka.svc.cluster.local:9092 + +### Debugging With Skaffold + + +## EventStorming Proccess +### Schema + +### Topic +1. reservation + +### Unstructured Exploration +1. ReservationRequestedEvent +Triggered by the customer submitting a reservation request. +2. AvailabilityConfirmed +Emitted by the system after validating the request and confirming availability. +1. ReservationCreatedEvent +Signals that a new reservation has been successfully created. +2. ReservationCanceledEvent +Indicates that a reservation has been cancelled. +3. ReservationModifiedEvent +Notifies that changes have been made to an existing reservation. +4. ReservationCheckedInEvent +Signals that a booked service or resource usage has started. +5. ReservationCheckedOutEvent +Indicates that a booked service or resource usage has ended. +6. AddedToWaitlistEvent +Notifies that a customer has been added to a waitlist for a service/resource. +7. PromotionAppliedEvent +Signals the successful application of a promotion or discount to a reservation. +8. ReservationExpiredEvent +Signals that a reservation request has expired due to inactivity. +9. OverreservationProcessedEvent +Signals that the system has handled the situation of overreservation by managing excess reservations. +10. ReservationConfirmationSentEvent +Indicates that a confirmation notification has been sent to the customer after a successful reservation. +11. PaymentAuthorizedEvent (Policy Event Trigger) +Signals successful authorization of payment associated with a reservation. +12. PaymentCompletedEvent +Indicates the successful completion of a payment transaction for a reservation. +13. PaymentFailedEvent +Signals that a payment transaction for a reservation has failed. + +### Timelines +Happy Path Workflow: +1. Reservation Creation +- Customer submits a reservation request. +- System validates the request and confirms availability. +- Reservation is successfully created. +- Confirmation is sent to the customer. +- Payment authorization is requested. +- Payment is successfully authorized. +- Payment completion is confirmed. +- Reservation is finalized. +2. Reservation Modification +- Customer requests a modification to an existing reservation. +- System validates the modification and confirms availability. +- Reservation is successfully updated. +- Confirmation of modification is sent to the customer. +- Payment authorization may be requested for additional charges. +- Payment, if required, is successfully authorized and completed. +- Updated reservation details are finalized. +3. Reservation Cancellation +- Customer requests cancellation of a reservation. +- System confirms cancellation. +- Reservation is successfully cancelled. +- Confirmation of cancellation is sent to the customer. +- Any applicable refunds are processed. +4. Check-In and Check-Out +- Customer checks in for a booked service/resource. +- System confirms check-in. +- Customer uses the service/resource. +- Customer checks out. +- System confirms check-out. + + +Alternative Path Workflow +1. Reservation Creation Failure +- Customer submits a reservation request. +- System validates the request but finds no availability. +- System notifies the customer of unavailability. +- Optionally, customer may be added to a waitlist. +2. Reservation Modification Failure +- Customer requests a modification to an existing reservation. +- System validates the modification but finds conflicts. +- System notifies the customer of the conflict and suggests alternatives. +3. Reservation Cancellation Failure +- Customer requests cancellation of a reservation. +- System encounters an error in cancellation. +- System notifies the customer of the failure and suggests contacting support. +4. Payment Failure +- Customer submits a reservation request. +- System validates the request and confirms availability. +- Payment authorization fails. +- System notifies the customer of the payment failure and suggests alternative payment methods. +5. Overreservation Handling +- Customer submits a reservation request. +- System validates the request and detects potential overreservation. +- System notifies the customer of the situation and suggests alternative reservation times or accommodations. + +### Commands +1. CreateReservationCommand +Initiates the process of creating a new reservation. +2. SendReservationConfirmationCommand +Sends a confirmation notification to the customer after a successful reservation. +3. CancelReservationCommand +Requests the cancellation of an existing reservation. +4. ModifyReservationCommand +Initiates changes to an existing reservation, such as altering the time, duration, or details of the reservation. +5. CheckinCommand +Indicates the beginning of a booked service or resource usage. +6. CheckoutCommand +Indicates the end of a booked service or resource usage. +7. AddToWaitlistCommand +Adds a customer to a waitlist for a service/resource that is currently unavailable. +8. ApplyPromotionCommand +Applies a promotion or discount to a reservation. +9. ExpireReservationCommand +Marks a reservation request as expired due to inactivity or lack of confirmation. +10. ProcessOverreservationCommand +Handles the situation of overreservation by managing the excess reservations. + + diff --git a/kustomize/base/application.yaml b/kustomize/base/application.yaml new file mode 100644 index 0000000..453642e --- /dev/null +++ b/kustomize/base/application.yaml @@ -0,0 +1,4 @@ +logging: + level: + org: + springframework: INFO \ No newline at end of file diff --git a/k8s/deployment.yaml b/kustomize/base/deployment.yaml similarity index 81% rename from k8s/deployment.yaml rename to kustomize/base/deployment.yaml index 10dbcab..9ebb11f 100644 --- a/k8s/deployment.yaml +++ b/kustomize/base/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: reservation-service-deployment + namespace: reservation-develop labels: app: reservation-service spec: @@ -18,6 +19,9 @@ spec: containers: - name: reservation-service image: reservation-service:v0.1.0-alpha + volumeMounts: + - name: config-volume + mountPath: /workspace/config imagePullPolicy: Never # SHOULD NOT DO IT ON PRODUCTION the kubelet does not try fetching the image. If the image is somehow already present locally resources: limits: @@ -38,4 +42,9 @@ spec: # preStop: # exec: # command: ["sh", "-c", "sleep 10"] + + volumes: + - name: config-volume + configMap: + name: reservation-service-config \ No newline at end of file diff --git a/kustomize/base/kafka-local.yaml b/kustomize/base/kafka-local.yaml new file mode 100644 index 0000000..726655d --- /dev/null +++ b/kustomize/base/kafka-local.yaml @@ -0,0 +1,118 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kafka + namespace: reservation-develop +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: kafka + name: kafka-headless + namespace: reservation-develop +spec: + clusterIP: None + clusterIPs: + - None + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: tcp-kafka-int + port: 9092 + protocol: TCP + targetPort: tcp-kafka-int + - name: tcp-kafka-ctrl + port: 29093 + protocol: TCP + targetPort: tcp-kafka-ctrl + selector: + app: kafka + sessionAffinity: None + type: ClusterIP +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: kafka + name: kafka + namespace: reservation-develop +spec: + podManagementPolicy: Parallel + replicas: 2 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: kafka # has to match .spec.template.metadata.labels + serviceName: kafka-headless + template: + metadata: + labels: + app: kafka # has to match .spec.selector.matchLabels + spec: + serviceAccountName: kafka + containers: + - command: + - sh + - -exc + - | + export CLUSTER_ID="6PMpHYL9QkeyXRj9Nrp4KA" && \ + export KAFKA_NODE_ID=${HOSTNAME##*-} + export KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://${POD_NAME}.kafka-headless.reservation-develop.svc.cluster.local:9092 + export KAFKA_CONTROLLER_QUORUM_VOTERS="0@kafka-0.kafka-headless.reservation-develop.svc.cluster.local:29093,1@kafka-1.kafka-headless.reservation-develop.svc.cluster.local:29093" + + exec /etc/confluent/docker/run + env: + - name: KAFKA_CONTROLLER_LISTENER_NAMES + value: "CONTROLLER" + - name: KAFKA_LISTENERS + value: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:29093 + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + name: kafka + image: docker.io/confluentinc/confluent-local:7.5.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9092 + name: tcp-kafka-int + protocol: TCP + - containerPort: 29093 + name: tcp-kafka-ctrl + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1400Mi + requests: + cpu: 250m + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + # readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsUser: 1000 + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /etc/kafka + name: config + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + fsGroup: 1000 + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: config + updateStrategy: + type: RollingUpdate \ No newline at end of file diff --git a/kustomize/base/kustomization.yaml b/kustomize/base/kustomization.yaml new file mode 100644 index 0000000..2bb9c46 --- /dev/null +++ b/kustomize/base/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- namespace.yaml +- kafka-local.yaml +- service.yaml +- deployment.yaml + +configMapGenerator: + - name: reservation-service-config + namespace: reservation-develop + files: + - application.yaml \ No newline at end of file diff --git a/kustomize/base/namespace.yaml b/kustomize/base/namespace.yaml new file mode 100644 index 0000000..29128fd --- /dev/null +++ b/kustomize/base/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: reservation-develop \ No newline at end of file diff --git a/k8s/service.yaml b/kustomize/base/service.yaml similarity index 86% rename from k8s/service.yaml rename to kustomize/base/service.yaml index a4508ba..8e323ff 100644 --- a/k8s/service.yaml +++ b/kustomize/base/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: reservation-service-kuservice + namespace: reservation-develop spec: type: LoadBalancer selector: diff --git a/kustomize/qa/kustomization.yaml b/kustomize/qa/kustomization.yaml new file mode 100644 index 0000000..3e84fb0 --- /dev/null +++ b/kustomize/qa/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../base + +patchesStrategicMerge: +- update-replicas.yaml \ No newline at end of file diff --git a/kustomize/qa/update-replicas.yaml b/kustomize/qa/update-replicas.yaml new file mode 100644 index 0000000..4fd3004 --- /dev/null +++ b/kustomize/qa/update-replicas.yaml @@ -0,0 +1,6 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reservation-service-deployment +spec: + replicas: 2 \ No newline at end of file diff --git a/skaffold.yaml b/skaffold.yaml index c44ee5a..35c3075 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -8,6 +8,6 @@ build: jib: project: com.ubluetech:reservation-service manifests: - rawYaml: - - k8s/deployment.yaml - - k8s/service.yaml + kustomize: + paths: + - kustomize/base From 61cf107aeae363098cb8da9e5c33b290f7e04636 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 29 Mar 2024 21:02:54 +0700 Subject: [PATCH 5/6] Apply deploy and build image on local by Google build docker (#8) Co-authored-by: Khoa Nguyen --- build-deploy-ks8.sh | 8 -------- 1 file changed, 8 deletions(-) delete mode 100755 build-deploy-ks8.sh diff --git a/build-deploy-ks8.sh b/build-deploy-ks8.sh deleted file mode 100755 index 51f5523..0000000 --- a/build-deploy-ks8.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# eval $(minikube docker-env) -# Jib google docker build with minikube -./mvnw com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=reservation-service:v0.1.0-alpha - -# Build deployment and service -kubectl apply -f ./k8s \ No newline at end of file From 5ba0cc0f808c2a1cdf3fbff1eaba96e538c28676 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Tue, 9 Apr 2024 17:52:06 +0700 Subject: [PATCH 6/6] Event Brainstoming and Kafka deploy (#15) Co-authored-by: Khoa Nguyen --- README.md | 144 +++++++++++++++++++++++- kustomize/base/application.yaml | 4 + {k8s => kustomize/base}/deployment.yaml | 9 ++ kustomize/base/kafka-local.yaml | 118 +++++++++++++++++++ kustomize/base/kustomization.yaml | 14 +++ kustomize/base/namespace.yaml | 5 + {k8s => kustomize/base}/service.yaml | 1 + kustomize/qa/kustomization.yaml | 8 ++ kustomize/qa/update-replicas.yaml | 6 + skaffold.yaml | 6 +- 10 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 kustomize/base/application.yaml rename {k8s => kustomize/base}/deployment.yaml (81%) create mode 100644 kustomize/base/kafka-local.yaml create mode 100644 kustomize/base/kustomization.yaml create mode 100644 kustomize/base/namespace.yaml rename {k8s => kustomize/base}/service.yaml (86%) create mode 100644 kustomize/qa/kustomization.yaml create mode 100644 kustomize/qa/update-replicas.yaml diff --git a/README.md b/README.md index d9cc1b9..dd5d0c4 100644 --- a/README.md +++ b/README.md @@ -1 +1,143 @@ -# reservation-service +# Reservation-Service +Bootstrap Skaffold configuration +Run the following command to generate a skaffold.yaml config file: +skaffold init + +### Use skaffold dev +Run the following command to begin using Skaffold for continuous development +skaffold dev + +### Provide external IP +minikube tunnel + +### Kafka +#### Create a topic and recovery +kubectl exec -it kafka-0 -- bash + +#### Create a topic named reservation with three partitions and a replication factor of 3. +kafka-topics --create --topic reservation --partitions 2 --replication-factor 2 --bootstrap-server kafka-0.kafka-headless.kafka.svc.cluster.local:9092 + +#### Verify the topic partitions are replicated across all three brokers: +kafka-topics --describe --topic reservation --bootstrap-server kafka-0.kafka-headless.kafka.svc.cluster.local:9092 + +### Debugging With Skaffold + + +## EventStorming Proccess +### Schema + +### Topic +1. reservation + +### Unstructured Exploration +1. ReservationRequestedEvent +Triggered by the customer submitting a reservation request. +2. AvailabilityConfirmed +Emitted by the system after validating the request and confirming availability. +1. ReservationCreatedEvent +Signals that a new reservation has been successfully created. +2. ReservationCanceledEvent +Indicates that a reservation has been cancelled. +3. ReservationModifiedEvent +Notifies that changes have been made to an existing reservation. +4. ReservationCheckedInEvent +Signals that a booked service or resource usage has started. +5. ReservationCheckedOutEvent +Indicates that a booked service or resource usage has ended. +6. AddedToWaitlistEvent +Notifies that a customer has been added to a waitlist for a service/resource. +7. PromotionAppliedEvent +Signals the successful application of a promotion or discount to a reservation. +8. ReservationExpiredEvent +Signals that a reservation request has expired due to inactivity. +9. OverreservationProcessedEvent +Signals that the system has handled the situation of overreservation by managing excess reservations. +10. ReservationConfirmationSentEvent +Indicates that a confirmation notification has been sent to the customer after a successful reservation. +11. PaymentAuthorizedEvent (Policy Event Trigger) +Signals successful authorization of payment associated with a reservation. +12. PaymentCompletedEvent +Indicates the successful completion of a payment transaction for a reservation. +13. PaymentFailedEvent +Signals that a payment transaction for a reservation has failed. + +### Timelines +Happy Path Workflow: +1. Reservation Creation +- Customer submits a reservation request. +- System validates the request and confirms availability. +- Reservation is successfully created. +- Confirmation is sent to the customer. +- Payment authorization is requested. +- Payment is successfully authorized. +- Payment completion is confirmed. +- Reservation is finalized. +2. Reservation Modification +- Customer requests a modification to an existing reservation. +- System validates the modification and confirms availability. +- Reservation is successfully updated. +- Confirmation of modification is sent to the customer. +- Payment authorization may be requested for additional charges. +- Payment, if required, is successfully authorized and completed. +- Updated reservation details are finalized. +3. Reservation Cancellation +- Customer requests cancellation of a reservation. +- System confirms cancellation. +- Reservation is successfully cancelled. +- Confirmation of cancellation is sent to the customer. +- Any applicable refunds are processed. +4. Check-In and Check-Out +- Customer checks in for a booked service/resource. +- System confirms check-in. +- Customer uses the service/resource. +- Customer checks out. +- System confirms check-out. + + +Alternative Path Workflow +1. Reservation Creation Failure +- Customer submits a reservation request. +- System validates the request but finds no availability. +- System notifies the customer of unavailability. +- Optionally, customer may be added to a waitlist. +2. Reservation Modification Failure +- Customer requests a modification to an existing reservation. +- System validates the modification but finds conflicts. +- System notifies the customer of the conflict and suggests alternatives. +3. Reservation Cancellation Failure +- Customer requests cancellation of a reservation. +- System encounters an error in cancellation. +- System notifies the customer of the failure and suggests contacting support. +4. Payment Failure +- Customer submits a reservation request. +- System validates the request and confirms availability. +- Payment authorization fails. +- System notifies the customer of the payment failure and suggests alternative payment methods. +5. Overreservation Handling +- Customer submits a reservation request. +- System validates the request and detects potential overreservation. +- System notifies the customer of the situation and suggests alternative reservation times or accommodations. + +### Commands +1. CreateReservationCommand +Initiates the process of creating a new reservation. +2. SendReservationConfirmationCommand +Sends a confirmation notification to the customer after a successful reservation. +3. CancelReservationCommand +Requests the cancellation of an existing reservation. +4. ModifyReservationCommand +Initiates changes to an existing reservation, such as altering the time, duration, or details of the reservation. +5. CheckinCommand +Indicates the beginning of a booked service or resource usage. +6. CheckoutCommand +Indicates the end of a booked service or resource usage. +7. AddToWaitlistCommand +Adds a customer to a waitlist for a service/resource that is currently unavailable. +8. ApplyPromotionCommand +Applies a promotion or discount to a reservation. +9. ExpireReservationCommand +Marks a reservation request as expired due to inactivity or lack of confirmation. +10. ProcessOverreservationCommand +Handles the situation of overreservation by managing the excess reservations. + + diff --git a/kustomize/base/application.yaml b/kustomize/base/application.yaml new file mode 100644 index 0000000..453642e --- /dev/null +++ b/kustomize/base/application.yaml @@ -0,0 +1,4 @@ +logging: + level: + org: + springframework: INFO \ No newline at end of file diff --git a/k8s/deployment.yaml b/kustomize/base/deployment.yaml similarity index 81% rename from k8s/deployment.yaml rename to kustomize/base/deployment.yaml index 10dbcab..9ebb11f 100644 --- a/k8s/deployment.yaml +++ b/kustomize/base/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: reservation-service-deployment + namespace: reservation-develop labels: app: reservation-service spec: @@ -18,6 +19,9 @@ spec: containers: - name: reservation-service image: reservation-service:v0.1.0-alpha + volumeMounts: + - name: config-volume + mountPath: /workspace/config imagePullPolicy: Never # SHOULD NOT DO IT ON PRODUCTION the kubelet does not try fetching the image. If the image is somehow already present locally resources: limits: @@ -38,4 +42,9 @@ spec: # preStop: # exec: # command: ["sh", "-c", "sleep 10"] + + volumes: + - name: config-volume + configMap: + name: reservation-service-config \ No newline at end of file diff --git a/kustomize/base/kafka-local.yaml b/kustomize/base/kafka-local.yaml new file mode 100644 index 0000000..726655d --- /dev/null +++ b/kustomize/base/kafka-local.yaml @@ -0,0 +1,118 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kafka + namespace: reservation-develop +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: kafka + name: kafka-headless + namespace: reservation-develop +spec: + clusterIP: None + clusterIPs: + - None + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: tcp-kafka-int + port: 9092 + protocol: TCP + targetPort: tcp-kafka-int + - name: tcp-kafka-ctrl + port: 29093 + protocol: TCP + targetPort: tcp-kafka-ctrl + selector: + app: kafka + sessionAffinity: None + type: ClusterIP +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: kafka + name: kafka + namespace: reservation-develop +spec: + podManagementPolicy: Parallel + replicas: 2 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: kafka # has to match .spec.template.metadata.labels + serviceName: kafka-headless + template: + metadata: + labels: + app: kafka # has to match .spec.selector.matchLabels + spec: + serviceAccountName: kafka + containers: + - command: + - sh + - -exc + - | + export CLUSTER_ID="6PMpHYL9QkeyXRj9Nrp4KA" && \ + export KAFKA_NODE_ID=${HOSTNAME##*-} + export KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://${POD_NAME}.kafka-headless.reservation-develop.svc.cluster.local:9092 + export KAFKA_CONTROLLER_QUORUM_VOTERS="0@kafka-0.kafka-headless.reservation-develop.svc.cluster.local:29093,1@kafka-1.kafka-headless.reservation-develop.svc.cluster.local:29093" + + exec /etc/confluent/docker/run + env: + - name: KAFKA_CONTROLLER_LISTENER_NAMES + value: "CONTROLLER" + - name: KAFKA_LISTENERS + value: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:29093 + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + name: kafka + image: docker.io/confluentinc/confluent-local:7.5.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9092 + name: tcp-kafka-int + protocol: TCP + - containerPort: 29093 + name: tcp-kafka-ctrl + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1400Mi + requests: + cpu: 250m + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + # readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsUser: 1000 + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /etc/kafka + name: config + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + fsGroup: 1000 + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: config + updateStrategy: + type: RollingUpdate \ No newline at end of file diff --git a/kustomize/base/kustomization.yaml b/kustomize/base/kustomization.yaml new file mode 100644 index 0000000..2bb9c46 --- /dev/null +++ b/kustomize/base/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- namespace.yaml +- kafka-local.yaml +- service.yaml +- deployment.yaml + +configMapGenerator: + - name: reservation-service-config + namespace: reservation-develop + files: + - application.yaml \ No newline at end of file diff --git a/kustomize/base/namespace.yaml b/kustomize/base/namespace.yaml new file mode 100644 index 0000000..29128fd --- /dev/null +++ b/kustomize/base/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: reservation-develop \ No newline at end of file diff --git a/k8s/service.yaml b/kustomize/base/service.yaml similarity index 86% rename from k8s/service.yaml rename to kustomize/base/service.yaml index a4508ba..8e323ff 100644 --- a/k8s/service.yaml +++ b/kustomize/base/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: reservation-service-kuservice + namespace: reservation-develop spec: type: LoadBalancer selector: diff --git a/kustomize/qa/kustomization.yaml b/kustomize/qa/kustomization.yaml new file mode 100644 index 0000000..3e84fb0 --- /dev/null +++ b/kustomize/qa/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../base + +patchesStrategicMerge: +- update-replicas.yaml \ No newline at end of file diff --git a/kustomize/qa/update-replicas.yaml b/kustomize/qa/update-replicas.yaml new file mode 100644 index 0000000..4fd3004 --- /dev/null +++ b/kustomize/qa/update-replicas.yaml @@ -0,0 +1,6 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reservation-service-deployment +spec: + replicas: 2 \ No newline at end of file diff --git a/skaffold.yaml b/skaffold.yaml index c44ee5a..35c3075 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -8,6 +8,6 @@ build: jib: project: com.ubluetech:reservation-service manifests: - rawYaml: - - k8s/deployment.yaml - - k8s/service.yaml + kustomize: + paths: + - kustomize/base