diff --git a/ChangeLog.md b/ChangeLog.md
index f54269c..2ed712f 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+## 2.1.0
+**Support to deploy on Cloud K8s cluter:**
+* Adjust manifests to deploy in a cloud cluster as a cloud native solution
+* Deployed, ran and tested on Google Kubernetes Engine (GKE)
+
## 2.0.4
**Health checks implementation & ConfigMap set up:**
* Add health checks to all microservices
diff --git a/ExternalSystem/PaymentService/.config/dotnet-tools.json b/ExternalSystem/PaymentService/.config/dotnet-tools.json
new file mode 100644
index 0000000..56e0950
--- /dev/null
+++ b/ExternalSystem/PaymentService/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "3.1.2",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/ExternalSystem/PaymentService/PaymentService.csproj b/ExternalSystem/PaymentService/PaymentService.csproj
index 0cdb35b..094cb5a 100644
--- a/ExternalSystem/PaymentService/PaymentService.csproj
+++ b/ExternalSystem/PaymentService/PaymentService.csproj
@@ -6,6 +6,7 @@
+
diff --git a/ExternalSystem/PaymentService/Properties/PublishProfiles/DuberPaymentExternalService - Web Deploy.pubxml b/ExternalSystem/PaymentService/Properties/PublishProfiles/PaymentServiceExternal - Web Deploy.pubxml
similarity index 61%
rename from ExternalSystem/PaymentService/Properties/PublishProfiles/DuberPaymentExternalService - Web Deploy.pubxml
rename to ExternalSystem/PaymentService/Properties/PublishProfiles/PaymentServiceExternal - Web Deploy.pubxml
index 2273e80..0b0fe35 100644
--- a/ExternalSystem/PaymentService/Properties/PublishProfiles/DuberPaymentExternalService - Web Deploy.pubxml
+++ b/ExternalSystem/PaymentService/Properties/PublishProfiles/PaymentServiceExternal - Web Deploy.pubxml
@@ -6,23 +6,26 @@ by editing this MSBuild file. In order to learn more about this please visit htt
MSDeploy
- /subscriptions/508e9034-6149-4cab-aded-3e97f650ae2a/resourcegroups/Default/providers/Microsoft.Web/sites/DuberPaymentExternalService
- Default
+ /subscriptions/b9fa199b-d651-4969-a504-266371834927/resourcegroups/duber/providers/Microsoft.Web/sites/PaymentServiceExternal
+ duber
AzureWebSite
Release
Any CPU
- http://duberpaymentexternalservice.azurewebsites.net
+ https://paymentserviceexternal.azurewebsites.net
True
False
+ netcoreapp3.1
8504d9b8-c4e8-4172-8da3-cbd9971e3207
- duberpaymentexternalservice.scm.azurewebsites.net:443
- DuberPaymentExternalService
+ false
+ paymentserviceexternal.scm.azurewebsites.net:443
+ PaymentServiceExternal
True
WMSVC
True
- $DuberPaymentExternalService
+ $PaymentServiceExternal
<_SavePWD>True
<_DestinationType>AzureWebSite
+ False
\ No newline at end of file
diff --git a/deploy/k8s/gke/default-ingress.yaml b/deploy/k8s/gke/default-ingress.yaml
new file mode 100644
index 0000000..f033740
--- /dev/null
+++ b/deploy/k8s/gke/default-ingress.yaml
@@ -0,0 +1,23 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: default-ingress
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ nginx.ingress.kubernetes.io/rewrite-target: /$1
+spec:
+ rules:
+ - http:
+ paths:
+ - backend:
+ serviceName: trip
+ servicePort: 80
+ path: /services/trip/(.*)
+ - backend:
+ serviceName: invoice
+ servicePort: 80
+ path: /services/invoice/(.*)
+ - backend:
+ serviceName: frontend
+ servicePort: 80
+ path: /(.*)
\ No newline at end of file
diff --git a/deploy/k8s/gke/delete-resources.sh b/deploy/k8s/gke/delete-resources.sh
new file mode 100644
index 0000000..9ff547b
--- /dev/null
+++ b/deploy/k8s/gke/delete-resources.sh
@@ -0,0 +1,26 @@
+# configmap
+kubectl delete cm env-config
+
+# common ingress
+kubectl delete ing default-ingress
+
+# invoice
+kubectl delete deploy invoice
+kubectl delete svc invoice
+kubectl delete hpa invoice
+
+# trip
+kubectl delete deploy trip
+kubectl delete hpa trip
+kubectl delete svc trip
+
+# website
+kubectl delete deploy frontend
+kubectl delete hpa frontend
+kubectl delete svc frontend
+
+#notificatiosn
+kubectl delete deploy notifications
+kubectl delete hpa notifications
+kubectl delete ing notifications
+kubectl delete svc notifications
\ No newline at end of file
diff --git a/deploy/k8s/gke/deploy.sh b/deploy/k8s/gke/deploy.sh
new file mode 100644
index 0000000..befcf81
--- /dev/null
+++ b/deploy/k8s/gke/deploy.sh
@@ -0,0 +1,26 @@
+# configmap
+kubectl apply -f env-config.yaml
+
+# common ingress
+kubectl apply -f default-ingress.yaml
+
+# invoice
+kubectl apply -f invoice\invoice-deployment.yaml
+kubectl apply -f invoice\invoice-service.yaml
+kubectl apply -f invoice\invoice-hpa.yaml
+
+# trip
+kubectl apply -f trip\trip-deployment.yaml
+kubectl apply -f trip\trip-hpa.yaml
+kubectl apply -f trip\trip-service.yaml
+
+# website
+kubectl apply -f website\website-deployment.yaml
+kubectl apply -f website\website-hpa.yaml
+kubectl apply -f website\website-service.yaml
+
+#notificatiosn
+kubectl apply -f notifications\notifications-deployment.yaml
+kubectl apply -f notifications\notifications-hpa.yaml
+kubectl apply -f notifications\notifications-ingress.yaml
+kubectl apply -f notifications\notifications-service.yaml
\ No newline at end of file
diff --git a/deploy/k8s/gke/env-config.yaml b/deploy/k8s/gke/env-config.yaml
new file mode 100644
index 0000000..9410cf1
--- /dev/null
+++ b/deploy/k8s/gke/env-config.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: env-config
+data:
+ ASPNETCORE_ENVIRONMENT: Production
+ ConnectionStrings__InvoiceDB: {your invoice db connection string}
+ ConnectionStrings__WebsiteDB: {your website db connection string}
+ ConnectionStrings__SignalrBackPlane: {your redis connection string}
+ EventStoreConfiguration__ConnectionString: {your mongo db connection string}
+ EventBusConnection: {your service bus connection string}
+ EventBusUserName: {your rabbitmq user}
+ EventBusPassword: {your rabbitmq password}
+ PaymentServiceBaseUrl: {your payment service url}
+ InvoiceApiSettings__BaseUrl: http://invoice
+ TripApiSettings__BaseUrl: http://trip
+ TripApiSettings__NotificationsClientUrl: http://{your load balancer ip}/notifications
+ TripApiSettings__NotificationsServerUrl: http://notifications
+ AzureServiceBusEnabled: "false"
+ IsDeployedOnCluster: "true"
\ No newline at end of file
diff --git a/deploy/k8s/gke/invoice/invoice-deployment-with-proxy.yaml b/deploy/k8s/gke/invoice/invoice-deployment-with-proxy.yaml
new file mode 100644
index 0000000..bcfce2d
--- /dev/null
+++ b/deploy/k8s/gke/invoice/invoice-deployment-with-proxy.yaml
@@ -0,0 +1,62 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: invoice
+spec:
+ selector:
+ matchLabels:
+ app: invoice
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: invoice
+ spec:
+ containers:
+ - name: invoice
+ image: vany0114/duber.invoice.api
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "100m"
+ limits:
+ memory: "256Mi"
+ cpu: "500m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ env:
+ - name: ReverseProxyPrefix
+ value: "services/invoice"
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 30
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
+ - name: cloudsql-proxy
+ image: gcr.io/cloudsql-docker/gce-proxy:1.16
+ command: ["/cloud_sql_proxy",
+ "-instances==tcp:3306",
+ "-credential_file=/secrets/cloudsql/creadentials.json"]
+ securityContext:
+ runAsUser: 2 # non-root user
+ allowPrivilegeEscalation: false
+ volumeMounts:
+ - name: cloudsql-instance-credentials
+ mountPath: /secrets/cloudsql
+ readOnly: true
+ volumes:
+ - name: cloudsql-instance-credentials
+ secret:
+ secretName: cloudsql-instance-credentials
\ No newline at end of file
diff --git a/deploy/k8s/gke/invoice/invoice-deployment.yaml b/deploy/k8s/gke/invoice/invoice-deployment.yaml
new file mode 100644
index 0000000..06138c0
--- /dev/null
+++ b/deploy/k8s/gke/invoice/invoice-deployment.yaml
@@ -0,0 +1,46 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: invoice
+spec:
+ selector:
+ matchLabels:
+ app: invoice
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: invoice
+ spec:
+ containers:
+ - name: invoice
+ image: vany0114/duber.invoice.api
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "100m"
+ limits:
+ memory: "256Mi"
+ cpu: "500m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ env:
+ - name: ReverseProxyPrefix
+ value: "services/invoice"
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 30
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/invoice/invoice-hpa.yaml b/deploy/k8s/gke/invoice/invoice-hpa.yaml
new file mode 100644
index 0000000..99d7ea3
--- /dev/null
+++ b/deploy/k8s/gke/invoice/invoice-hpa.yaml
@@ -0,0 +1,12 @@
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: invoice
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: invoice
+ minReplicas: 2
+ maxReplicas: 4
+ targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/gke/invoice/invoice-service.yaml b/deploy/k8s/gke/invoice/invoice-service.yaml
new file mode 100644
index 0000000..4c41e3b
--- /dev/null
+++ b/deploy/k8s/gke/invoice/invoice-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: invoice
+spec:
+ selector:
+ app: invoice
+ ports:
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/notifications/notifications-deployment.yaml b/deploy/k8s/gke/notifications/notifications-deployment.yaml
new file mode 100644
index 0000000..817de15
--- /dev/null
+++ b/deploy/k8s/gke/notifications/notifications-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: notifications
+spec:
+ selector:
+ matchLabels:
+ app: notifications
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: notifications
+ spec:
+ containers:
+ - name: notifications
+ image: vany0114/duber.trip.notifications
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "200m"
+ limits:
+ memory: "256Mi"
+ cpu: "600m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 30
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/notifications/notifications-hpa.yaml b/deploy/k8s/gke/notifications/notifications-hpa.yaml
new file mode 100644
index 0000000..70cc79a
--- /dev/null
+++ b/deploy/k8s/gke/notifications/notifications-hpa.yaml
@@ -0,0 +1,12 @@
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: notifications
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: notifications
+ minReplicas: 4
+ maxReplicas: 5
+ targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/gke/notifications/notifications-ingress.yaml b/deploy/k8s/gke/notifications/notifications-ingress.yaml
new file mode 100644
index 0000000..b4a0732
--- /dev/null
+++ b/deploy/k8s/gke/notifications/notifications-ingress.yaml
@@ -0,0 +1,17 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: notifications
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-path: /notifications/
+ nginx.ingress.kubernetes.io/rewrite-target: /$1
+spec:
+ rules:
+ - http:
+ paths:
+ - backend:
+ serviceName: notifications
+ servicePort: 80
+ path: /notifications/(.*)
\ No newline at end of file
diff --git a/deploy/k8s/gke/notifications/notifications-service.yaml b/deploy/k8s/gke/notifications/notifications-service.yaml
new file mode 100644
index 0000000..94b1213
--- /dev/null
+++ b/deploy/k8s/gke/notifications/notifications-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: notifications
+spec:
+ selector:
+ app: notifications
+ ports:
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/trip/trip-deployment.yaml b/deploy/k8s/gke/trip/trip-deployment.yaml
new file mode 100644
index 0000000..74e94dc
--- /dev/null
+++ b/deploy/k8s/gke/trip/trip-deployment.yaml
@@ -0,0 +1,46 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: trip
+spec:
+ selector:
+ matchLabels:
+ app: trip
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: trip
+ spec:
+ containers:
+ - name: trip
+ image: vany0114/duber.trip.api
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "200m"
+ limits:
+ memory: "256Mi"
+ cpu: "600m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ env:
+ - name: ReverseProxyPrefix
+ value: "services/trip"
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 30
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/trip/trip-hpa.yaml b/deploy/k8s/gke/trip/trip-hpa.yaml
new file mode 100644
index 0000000..7a7703b
--- /dev/null
+++ b/deploy/k8s/gke/trip/trip-hpa.yaml
@@ -0,0 +1,12 @@
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: trip
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: trip
+ minReplicas: 2
+ maxReplicas: 4
+ targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/gke/trip/trip-service.yaml b/deploy/k8s/gke/trip/trip-service.yaml
new file mode 100644
index 0000000..44960b8
--- /dev/null
+++ b/deploy/k8s/gke/trip/trip-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: trip
+spec:
+ selector:
+ app: trip
+ ports:
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/website/website-deployment-with-proxy.yaml b/deploy/k8s/gke/website/website-deployment-with-proxy.yaml
new file mode 100644
index 0000000..02f732e
--- /dev/null
+++ b/deploy/k8s/gke/website/website-deployment-with-proxy.yaml
@@ -0,0 +1,76 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: frontend
+spec:
+ selector:
+ matchLabels:
+ app: frontend
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: frontend
+ spec:
+ containers:
+ - name: frontend
+ image: vany0114/duber.website
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "200m"
+ limits:
+ memory: "256Mi"
+ cpu: "600m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ env:
+ - name: HealthChecksUI__HealthChecks__0__Name
+ value: "Invoice HTTP Check"
+ - name: HealthChecksUI__HealthChecks__0__Uri
+ value: $(InvoiceApiSettings__BaseUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__1__Name
+ value: "Trip HTTP Check"
+ - name: HealthChecksUI__HealthChecks__1__Uri
+ value: $(TripApiSettings__BaseUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__2__Name
+ value: "Notifications HTTP Check"
+ - name: HealthChecksUI__HealthChecks__2__Uri
+ value: $(TripApiSettings__NotificationsServerUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__3__Name
+ value: "Frontend HTTP Check"
+ - name: HealthChecksUI__HealthChecks__3__Uri
+ value: "http://frontend/readiness"
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 60
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
+ - name: cloudsql-proxy
+ image: gcr.io/cloudsql-docker/gce-proxy:1.16
+ command: ["/cloud_sql_proxy",
+ "-instances==tcp:3306",
+ "-credential_file=/secrets/cloudsql/creadentials.json"]
+ securityContext:
+ runAsUser: 2 # non-root user
+ allowPrivilegeEscalation: false
+ volumeMounts:
+ - name: cloudsql-instance-credentials
+ mountPath: /secrets/cloudsql
+ readOnly: true
+ volumes:
+ - name: cloudsql-instance-credentials
+ secret:
+ secretName: cloudsql-instance-credentials
\ No newline at end of file
diff --git a/deploy/k8s/gke/website/website-deployment.yaml b/deploy/k8s/gke/website/website-deployment.yaml
new file mode 100644
index 0000000..3327b74
--- /dev/null
+++ b/deploy/k8s/gke/website/website-deployment.yaml
@@ -0,0 +1,60 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: frontend
+spec:
+ selector:
+ matchLabels:
+ app: frontend
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: frontend
+ spec:
+ containers:
+ - name: frontend
+ image: vany0114/duber.website
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: "128Mi"
+ cpu: "200m"
+ limits:
+ memory: "256Mi"
+ cpu: "600m"
+ envFrom:
+ - configMapRef:
+ name: env-config
+ env:
+ - name: HealthChecksUI__HealthChecks__0__Name
+ value: "Invoice HTTP Check"
+ - name: HealthChecksUI__HealthChecks__0__Uri
+ value: $(InvoiceApiSettings__BaseUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__1__Name
+ value: "Trip HTTP Check"
+ - name: HealthChecksUI__HealthChecks__1__Uri
+ value: $(TripApiSettings__BaseUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__2__Name
+ value: "Notifications HTTP Check"
+ - name: HealthChecksUI__HealthChecks__2__Uri
+ value: $(TripApiSettings__NotificationsServerUrl)/readiness
+ - name: HealthChecksUI__HealthChecks__3__Name
+ value: "Frontend HTTP Check"
+ - name: HealthChecksUI__HealthChecks__3__Uri
+ value: "http://frontend/readiness"
+ livenessProbe:
+ httpGet:
+ port: 80
+ path: /liveness
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /readiness
+ port: 80
+ initialDelaySeconds: 60
+ periodSeconds: 60
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/gke/website/website-hpa.yaml b/deploy/k8s/gke/website/website-hpa.yaml
new file mode 100644
index 0000000..999fdab
--- /dev/null
+++ b/deploy/k8s/gke/website/website-hpa.yaml
@@ -0,0 +1,12 @@
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: frontend
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: frontend
+ minReplicas: 2
+ maxReplicas: 4
+ targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/gke/website/website-service.yaml b/deploy/k8s/gke/website/website-service.yaml
new file mode 100644
index 0000000..9f7074c
--- /dev/null
+++ b/deploy/k8s/gke/website/website-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend
+spec:
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 80
\ No newline at end of file
diff --git a/deploy/k8s/local/notifications/notifications-hpa.yaml b/deploy/k8s/local/notifications/notifications-hpa.yaml
index 833e9dd..70cc79a 100644
--- a/deploy/k8s/local/notifications/notifications-hpa.yaml
+++ b/deploy/k8s/local/notifications/notifications-hpa.yaml
@@ -8,5 +8,5 @@ spec:
kind: Deployment
name: notifications
minReplicas: 4
- maxReplicas: 10
+ maxReplicas: 5
targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/local/trip/trip-hpa.yaml b/deploy/k8s/local/trip/trip-hpa.yaml
index 492807b..7a7703b 100644
--- a/deploy/k8s/local/trip/trip-hpa.yaml
+++ b/deploy/k8s/local/trip/trip-hpa.yaml
@@ -7,6 +7,6 @@ spec:
apiVersion: apps/v1
kind: Deployment
name: trip
- minReplicas: 3
- maxReplicas: 7
+ minReplicas: 2
+ maxReplicas: 4
targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/k8s/local/website/website-hpa.yaml b/deploy/k8s/local/website/website-hpa.yaml
index f5cdef0..999fdab 100644
--- a/deploy/k8s/local/website/website-hpa.yaml
+++ b/deploy/k8s/local/website/website-hpa.yaml
@@ -7,6 +7,6 @@ spec:
apiVersion: apps/v1
kind: Deployment
name: frontend
- minReplicas: 3
- maxReplicas: 5
+ minReplicas: 2
+ maxReplicas: 4
targetCPUUtilizationPercentage: 50
\ No newline at end of file
diff --git a/deploy/redis/readme.md b/deploy/redis/readme.md
new file mode 100644
index 0000000..61be1f6
--- /dev/null
+++ b/deploy/redis/readme.md
@@ -0,0 +1,31 @@
+# Deploying Redis Cache
+
+The ARM template `redisdeploy.json` and its parameter file (`redisdeploy.parameters.json`) are used to deploy following resources:
+
+1. One Redis Cache
+
+## Editing sbusdeploy.parameters.json file
+
+You can edit the `redisdeploy.parameters.parameters.json` file to set your values, but is not needed. The only parameter than can
+be set is:
+
+1. `namespaceprefix` is a string that is used to create the Redis namespace. ARM script creates unique values by appending a unique string to this parameter value, so you can leave the default value.
+
+## Deploy the template
+
+Once parameter file is edited you can deploy it using [create-resources script](../readme.md).
+
+i. e. if you are in windows, to deploy a Redis cache in a new Azure Resource Group located in westus, go to `deploy\az` folder and type:
+
+```
+create-resources.cmd redis\redisdeploy newResourceGroup -c westus
+```
+
+
+
+
+
+
+
+
+
diff --git a/deploy/redis/redisdeploy.json b/deploy/redis/redisdeploy.json
new file mode 100644
index 0000000..04b53a3
--- /dev/null
+++ b/deploy/redis/redisdeploy.json
@@ -0,0 +1,42 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "namespaceprefix": {
+ "type": "string",
+ "metadata": {
+ "description": "Name of the Redis namespace"
+ }
+ }
+ },
+ "variables": {
+ "location": "[resourceGroup().location]",
+ "namespaceprefix": "[concat(parameters('namespaceprefix'), uniqueString(resourceGroup().id))]",
+ "sbVersion": "2016-04-01"
+ },
+ "resources": [
+ {
+ "type": "Microsoft.Cache/Redis",
+ "name": "[variables('namespaceprefix')]",
+ "apiVersion": "[variables('sbVersion')]",
+ "location": "[variables('location')]",
+ "scale": null,
+ "properties": {
+ "redisVersion": "3.2.7",
+ "sku": {
+ "name": "Standard",
+ "family": "C",
+ "capacity": 1
+ },
+ "enableNonSslPort": true,
+ "redisConfiguration": {
+ "maxclients": "1000",
+ "maxmemory-reserved": "50",
+ "maxfragmentationmemory-reserved": "50",
+ "maxmemory-policy": "volatile-lru",
+ "maxmemory-delta": "50"
+ }
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/deploy/redis/redisdeploy.parameters.json b/deploy/redis/redisdeploy.parameters.json
new file mode 100644
index 0000000..da66878
--- /dev/null
+++ b/deploy/redis/redisdeploy.parameters.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "namespaceprefix": {
+ "value": "duber-redis"
+ }
+ }
+}
\ No newline at end of file
diff --git a/deploy/servicebus/sbusdeploy.json b/deploy/servicebus/sbusdeploy.json
index f3d8844..d4e4baf 100644
--- a/deploy/servicebus/sbusdeploy.json
+++ b/deploy/servicebus/sbusdeploy.json
@@ -13,7 +13,8 @@
"serviceBusTopicName": "duber_event_bus",
"TripSubscriptionName": "Trip",
"InvoiceSubscriptionName": "Invoice",
- "WebSiteSubscriptionName": "WebSite",
+ "WebSiteSubscriptionName": "WebSite",
+ "NotificationsSubscriptionName": "Notifications",
"location": "[resourceGroup().location]",
"sbVersion": "2015-08-01",
"defaultSASKeyName": "Root",
@@ -130,6 +131,26 @@
"autoDeleteOnIdle": "10675199.02:48:05.4775807",
"entityAvailabilityStatus": "Available"
}
+ },
+ {
+ "apiVersion": "[variables('sbVersion')]",
+ "name": "[variables('NotificationsSubscriptionName')]",
+ "type": "Subscriptions",
+ "dependsOn": [
+ "[variables('serviceBusTopicName')]"
+ ],
+ "properties": {
+ "lockDuration": "00:00:30",
+ "requiresSession": false,
+ "defaultMessageTimeToLive": "14.00:00:00",
+ "deadLetteringOnMessageExpiration": true,
+ "deadLetteringOnFilterEvaluationExceptions": true,
+ "maxDeliveryCount": 10,
+ "enableBatchedOperations": false,
+ "status": "Active",
+ "autoDeleteOnIdle": "10675199.02:48:05.4775807",
+ "entityAvailabilityStatus": "Available"
+ }
}
]
}
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index 39e0327..5b0c186 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -6,6 +6,7 @@ services:
- ASPNETCORE_ENVIRONMENT=${APP_ENVIRONMENT:-Development}
- ConnectionStrings__InvoiceDB=${AZURE_INVOICE_DB:-Server=sql.data;Database=Duber.InvoiceDb;User Id=sa;Password=Pass@word}
- EventBusConnection=${AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusConnectionHC=${AZURE_SERVICE_BUS:-rabbitmq}
- PaymentServiceBaseUrl=${PAYMENT_SERVICE_URL:-http://externalsystem.payment}
- AzureServiceBusEnabled=${SERVICE_BUS_ENABLED:-False}
ports:
@@ -16,6 +17,7 @@ services:
- ASPNETCORE_ENVIRONMENT=${APP_ENVIRONMENT:-Development}
- EventStoreConfiguration__ConnectionString=${AZURE_TRIP_DB:-mongodb://nosql.data}
- EventBusConnection=${AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusConnectionHC=${AZURE_SERVICE_BUS:-rabbitmq}
- AzureServiceBusEnabled=${SERVICE_BUS_ENABLED:-False}
ports:
- "32775:80"
@@ -25,6 +27,7 @@ services:
- ASPNETCORE_ENVIRONMENT=${APP_ENVIRONMENT:-Development}
- ConnectionStrings__WebsiteDB=${AZURE_WEBSITE_DB:-Server=sql.data;Database=Duber.WebSiteDb;User Id=sa;Password=Pass@word}
- EventBusConnection=${AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusConnectionHC=${AZURE_SERVICE_BUS:-rabbitmq}
- InvoiceApiSettings__BaseUrl=${INVOICE_SERVICE_BASE_URL:-http://duber.invoice.api}
- TripApiSettings__BaseUrl=${TRIP_SERVICE_BASE_URL:-http://duber.trip.api}
- TripApiSettings__NotificationsServerUrl=${NOTIFICATIONS_SERVER_URL:-http://duber.trip.notifications}
@@ -64,6 +67,7 @@ services:
- ASPNETCORE_ENVIRONMENT=${APP_ENVIRONMENT:-Development}
- ConnectionStrings__SignalrBackPlane=${REDIS_DB:-}
- EventBusConnection=${AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusConnectionHC=${AZURE_SERVICE_BUS:-rabbitmq}
- AzureServiceBusEnabled=${SERVICE_BUS_ENABLED:-False}
ports:
- "32778:80"
\ No newline at end of file
diff --git a/src/Application/Duber.Invoice.API/Startup.cs b/src/Application/Duber.Invoice.API/Startup.cs
index c286233..af0fd94 100644
--- a/src/Application/Duber.Invoice.API/Startup.cs
+++ b/src/Application/Duber.Invoice.API/Startup.cs
@@ -1,10 +1,8 @@
using System;
+using System.Collections.Generic;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper;
-using Duber.Infrastructure.EventBus.Abstractions;
-using Duber.Invoice.API.Application.IntegrationEvents.Events;
-using Duber.Invoice.API.Application.IntegrationEvents.Hnadlers;
using Duber.Invoice.API.Application.Validations;
using Duber.Invoice.API.Extensions;
using Duber.Invoice.API.Infrastructure.AutofacModules;
@@ -17,6 +15,8 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.OpenApi.Models;
+
// ReSharper disable InconsistentNaming
// ReSharper disable AssignNullToNotNullAttribute
#pragma warning disable 618
@@ -97,10 +97,20 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
});
});
- app.UseSwagger()
+ app.UseSwagger(x =>
+ {
+ var reverseProxyPrefix = Configuration.GetValue("ReverseProxyPrefix");
+ if (!string.IsNullOrEmpty(reverseProxyPrefix))
+ {
+ x.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List
+ {
+ new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/{reverseProxyPrefix}" }
+ });
+ }
+ })
.UseSwaggerUI(c =>
{
- c.SwaggerEndpoint("/swagger/v1/swagger.json", "Duber.Invoice V1");
+ c.SwaggerEndpoint("./swagger/v1/swagger.json", "Duber.Invoice V1");
c.RoutePrefix = string.Empty;
});
}
diff --git a/src/Application/Duber.Invoice.API/appsettings.json b/src/Application/Duber.Invoice.API/appsettings.json
index c39420b..be6d776 100644
--- a/src/Application/Duber.Invoice.API/appsettings.json
+++ b/src/Application/Duber.Invoice.API/appsettings.json
@@ -14,6 +14,7 @@
},
"AzureServiceBusEnabled": false,
"EventBusConnection": "",
+ "EventBusConnectionHC": "",
"SubscriptionClientName": "Invoice",
"EventBusRetryCount": 5,
"PaymentServiceBaseUrl": "http://localhost:32777",
@@ -23,5 +24,6 @@
"SqlClientExceptionsAllowedBeforeBreaking": 4,
"ConnectionStrings": {
"InvoiceDB": "Server=tcp:127.0.0.1,5433;Initial Catalog=Duber.InvoiceDb;User Id=sa;Password=Pass@word"
- }
+ },
+ "ReverseProxyPrefix": ""
}
diff --git a/src/Application/Duber.Trip.API/Extensions/ServiceCollectionExtensions.cs b/src/Application/Duber.Trip.API/Extensions/ServiceCollectionExtensions.cs
index 246c27f..d024042 100644
--- a/src/Application/Duber.Trip.API/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Application/Duber.Trip.API/Extensions/ServiceCollectionExtensions.cs
@@ -150,6 +150,7 @@ public static IServiceCollection AddHealthChecks(this IServiceCollection service
hcBuilder
.AddMongoDb(
configuration["EventStoreConfiguration:ConnectionString"],
+ mongoDatabaseName: string.Empty,
name: "TripDB-check",
tags: new string[] { "tripdb" });
diff --git a/src/Application/Duber.Trip.API/Startup.cs b/src/Application/Duber.Trip.API/Startup.cs
index fd2cfb4..48532a4 100644
--- a/src/Application/Duber.Trip.API/Startup.cs
+++ b/src/Application/Duber.Trip.API/Startup.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Duber.Trip.API.Application.Validations;
@@ -13,6 +14,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using Microsoft.OpenApi.Models;
// ReSharper disable InconsistentNaming
@@ -86,10 +88,20 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
});
});
- app.UseSwagger()
+ app.UseSwagger(x =>
+ {
+ var reverseProxyPrefix = Configuration.GetValue("ReverseProxyPrefix");
+ if (!string.IsNullOrEmpty(reverseProxyPrefix))
+ {
+ x.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List
+ {
+ new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/{reverseProxyPrefix}" }
+ });
+ }
+ })
.UseSwaggerUI(c =>
{
- c.SwaggerEndpoint("/swagger/v1/swagger.json", "Duber.Trip V1");
+ c.SwaggerEndpoint("./swagger/v1/swagger.json", "Duber.Trip V1");
c.RoutePrefix = string.Empty;
});
}
diff --git a/src/Application/Duber.Trip.API/appsettings.json b/src/Application/Duber.Trip.API/appsettings.json
index 0ae0e43..b88623d 100644
--- a/src/Application/Duber.Trip.API/appsettings.json
+++ b/src/Application/Duber.Trip.API/appsettings.json
@@ -14,13 +14,15 @@
},
"AzureServiceBusEnabled": false,
"EventBusConnection": "",
+ "EventBusConnectionHC": "",
"SubscriptionClientName": "Trip",
"EventStoreConfiguration": {
"ConnectionString": "mongodb://nosql.data",
"DatabaseName": "EventStore",
"AggregateCollectionName": "Aggregates",
"EventCollectionName": "Events",
- "CommandCollectionName": "Commands"
+ "CommandCollectionName": "Commands"
},
- "EventBusRetryCount": 5
+ "EventBusRetryCount": 5,
+ "ReverseProxyPrefix": ""
}
diff --git a/src/Application/Duber.Trip.Notifications/appsettings.json b/src/Application/Duber.Trip.Notifications/appsettings.json
index 8550a68..c4e16a7 100644
--- a/src/Application/Duber.Trip.Notifications/appsettings.json
+++ b/src/Application/Duber.Trip.Notifications/appsettings.json
@@ -1,9 +1,15 @@
{
"Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "IncludeScopes": false,
+ "Debug": {
+ "LogLevel": {
+ "Default": "Warning"
+ }
+ },
+ "Console": {
+ "LogLevel": {
+ "Default": "Information"
+ }
}
},
"AllowedHosts": "*",
@@ -12,6 +18,7 @@
},
"AzureServiceBusEnabled": false,
"EventBusConnection": "",
+ "EventBusConnectionHC": "",
"SubscriptionClientName": "Notifications",
"EventBusRetryCount": 5,
"IsDeployedOnCluster": false
diff --git a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.RabbitMQ/IoC/ServiceCollectionExtensions.cs b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.RabbitMQ/IoC/ServiceCollectionExtensions.cs
index fad5b4a..effa72f 100644
--- a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.RabbitMQ/IoC/ServiceCollectionExtensions.cs
+++ b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.RabbitMQ/IoC/ServiceCollectionExtensions.cs
@@ -17,14 +17,28 @@ public static IServiceCollection AddRabbitMQ(this IServiceCollection services, I
retryCount = int.Parse(configuration["EventBusRetryCount"]);
}
+ var connectionFactory = new ConnectionFactory()
+ {
+ HostName = configuration["EventBusConnection"],
+ DispatchConsumersAsync = true,
+ AutomaticRecoveryEnabled = true
+ };
+
+ if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
+ {
+ connectionFactory.UserName = configuration["EventBusUserName"];
+ }
+
+ if (!string.IsNullOrEmpty(configuration["EventBusPassword"]))
+ {
+ connectionFactory.Password = configuration["EventBusPassword"];
+ }
+
+ services.AddSingleton(connectionFactory);
services.AddSingleton(sp =>
{
var logger = sp.GetRequiredService>();
- var factory = new ConnectionFactory()
- {
- HostName = configuration["EventBusConnection"],
- DispatchConsumersAsync = true
- };
+ var factory = sp.GetRequiredService();
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
});
@@ -47,8 +61,7 @@ public static IServiceCollection AddRabbitMQ(this IServiceCollection services, I
public static IHealthChecksBuilder AddRabbitMQ(this IHealthChecksBuilder healthChecksBuilder, IConfiguration configuration, string name = "rabbitmqbus-check")
{
healthChecksBuilder
- .AddRabbitMQ(
- $"amqp://{configuration["EventBusConnection"]}",
+ .AddRabbitMQ((sp) => sp.GetRequiredService().CreateConnection(),
name: name,
tags: new string[] { "rabbitmqbus" });
diff --git a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/EventBusServiceBus.cs b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/EventBusServiceBus.cs
index 02ddc12..5feb638 100644
--- a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/EventBusServiceBus.cs
+++ b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/EventBusServiceBus.cs
@@ -32,8 +32,7 @@ public class EventBusServiceBus : IEventBus
_logger = logger;
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
- _subscriptionClient = new SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder,
- subscriptionClientName);
+ _subscriptionClient = new SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder, subscriptionClientName);
_autofac = autofac;
_retryCount = retryCount;
@@ -80,7 +79,7 @@ public void SubscribeDynamic(string eventName)
where T : IntegrationEvent
where TH : IIntegrationEventHandler
{
- var eventName = typeof(T).Name.Replace(INTEGRATION_EVENT_SUFFIX, "");
+ var eventName = GetEventName();
var containsKey = _subsManager.HasSubscriptionsForEvent();
if (!containsKey)
@@ -93,15 +92,28 @@ public void SubscribeDynamic(string eventName)
Name = eventName
}).GetAwaiter().GetResult();
}
- catch(ServiceBusException)
+ catch(ServiceBusException ex)
{
- _logger.LogInformation($"The messaging entity {eventName} already exists.");
+ _logger.LogInformation($"The messaging entity {eventName} already exists.", ex);
}
}
_subsManager.AddSubscription();
}
+ private string GetEventName()
+ {
+ var type = typeof(T);
+ var eventName = type.Name.Replace(INTEGRATION_EVENT_SUFFIX, "");
+ if (type.GetGenericArguments().Length > 0)
+ {
+ eventName = eventName.Remove(eventName.IndexOf('`'));
+ eventName += type.GetGenericArguments()[0].Name.Replace(INTEGRATION_EVENT_SUFFIX, "");
+ }
+
+ return eventName;
+ }
+
public void Unsubscribe()
where T : IntegrationEvent
where TH : IIntegrationEventHandler
diff --git a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/IoC/ServiceCollectionExtensions.cs b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/IoC/ServiceCollectionExtensions.cs
index 942fdce..6cc578e 100644
--- a/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/IoC/ServiceCollectionExtensions.cs
+++ b/src/Infrastructure/EventBus/Duber.Infrastructure.EventBus.ServiceBus/IoC/ServiceCollectionExtensions.cs
@@ -46,7 +46,7 @@ public static IHealthChecksBuilder AddAzureServiceBusTopic(this IHealthChecksBui
{
healthChecksBuilder
.AddAzureServiceBusTopic(
- configuration["EventBusConnection"],
+ configuration["EventBusConnectionHC"], // this connection string can't contains the EntityPath (topic name)
topicName: "duber_event_bus",
name,
tags: new string[] { "az-servicebus" });
diff --git a/src/Web/Duber.WebSite/appsettings.json b/src/Web/Duber.WebSite/appsettings.json
index 459ab05..c6e0d5a 100644
--- a/src/Web/Duber.WebSite/appsettings.json
+++ b/src/Web/Duber.WebSite/appsettings.json
@@ -7,6 +7,7 @@
},
"AzureServiceBusEnabled": false,
"EventBusConnection": "",
+ "EventBusConnectionHC": "",
"SubscriptionClientName": "WebSite",
"EventBusRetryCount": 5,
"HttpClientRetryCount": 5,
| |