You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: guides/deployment/microservices.md
+58-52Lines changed: 58 additions & 52 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ A comprehensive guide on deploying your CAP application as microservices.
13
13
## Create a Solution Monorepo <UnderConstruction/>
14
14
15
15
Assumed we want to create a composite application consisting of two or more micro services, each living in a separate GitHub repository, for example:
16
-
16
+
<!-- Those links aren't working links. Why do we use those? -->
17
17
-https://github.com/capire/bookstore
18
18
-https://github.com/capire/reviews
19
19
-https://github.com/capire/orders
@@ -24,9 +24,9 @@ With some additional repos, used as dependencies in the same manner, like:
24
24
-https://github.com/capire/bookshop
25
25
-https://github.com/capire/data-viewer
26
26
27
-
This guide describes a way to manage development and deployment via *[monorepos](https://en.wikipedia.org/wiki/Monorepo)* using *[npm workspaces](https://docs.npmjs.com/cli/using-npm/workspaces)* and *[git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)* techniques...
27
+
This guide describes a way to manage development and deployment via *[monorepos](https://en.wikipedia.org/wiki/Monorepo)* using *[NPM workspaces](https://docs.npmjs.com/cli/using-npm/workspaces)* and *[git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)* techniques...
28
28
29
-
1. Create a new monorepo root directory using `npm` workspaces:
29
+
1. Create a new monorepo root directory using *NPM workspaces*:
30
30
31
31
```sh
32
32
mkdir capire
@@ -47,14 +47,14 @@ This guide describes a way to manage development and deployment via *[monorepos]
47
47
git submodule update --init
48
48
```
49
49
50
-
Add a .gitignore
50
+
Add a _.gitignore_ file with the following content:
51
51
```txt
52
52
node_modules
53
53
gen
54
54
```
55
55
> The outcome of this looks and behaves exactly as the monorepo layout in *[cap/samples](https://github.com/sap-samples/cloud-cap-samples)*, so we can exercise the subsequent steps in there...
56
56
57
-
3. Test-drive locally as usual
57
+
3. Test-drive locally:
58
58
```sh
59
59
npm install
60
60
```
@@ -67,8 +67,12 @@ This guide describes a way to manage development and deployment via *[monorepos]
67
67
cds w bookstore
68
68
```
69
69
70
+
Each microservice can be started independently. If you start each microservice, one after the other in a different terminal, the connection is already established.
70
71
71
-
::: details Other project structures
72
+
[Learn more about Automatic Bindings by `cds watch`](../extensibility/composition#bindings-via-cds-watch){.learn-more}
73
+
74
+
75
+
::: details The project structure
72
76
73
77
The project structure used here is as follows:
74
78
@@ -81,13 +85,13 @@ The project structure used here is as follows:
81
85
└─ package.json
82
86
```
83
87
84
-
The individual services (`bookstore`, `reviews`, `orders`) can be
88
+
The individual services (`bookstore`, `reviews`, `orders`) can be one of the following:
85
89
* folders, committed directly to the root project
86
90
* git submodules
87
91
88
-
Links between the projects are established using npm dependencies.
92
+
Links between the projects are established using NPM dependencies.
89
93
Since the root project defines workspaces, these dependencies are also found locally without the need for publishing or linking.
90
-
When one of the projects is cloned in isolation, it is still possible to fetch dependencies to other modules via the npm registry.
94
+
When one of the projects is cloned in isolation, it's still possible to fetch dependencies to other modules via the NPM registry.
91
95
92
96
:::
93
97
@@ -97,22 +101,24 @@ If you have multiple CAP applications relying on the same domain model or want t
97
101
98
102
In the following steps, we create an additional project to easily collect the relevant models from these projects, and act as a vehicle to deploy these models to SAP HANA in a controlled way.
99
103
100
-
::: details Evaluation
104
+
::: details Why a shared database?
105
+
106
+
A shared database is beneficial if the following are important for you:
107
+
108
+
-**Query Performance:** Complex queries are executed much faster, for example `$expand` to an entity on another microservice, compared to calls across services with own data persistencies.
109
+
-**Independent Scalability** of application runtimes, compared to a monolithic application.
101
110
102
-
The advantages are as follows:
103
-
-**Query Performance:** Complex queries are executed much faster, for example $expand to an entity on another microservice (compared to calls across services with own data persistencies)
104
-
-**Independent Scalability** of application runtimes (compared to a monolithic application)
111
+
These are the (not so beneficial) side effects you when using a shared persistence:
105
112
106
-
Disadvantages:
107
-
- Accessing data directly (without an API) means any changes in the data model affect all applications directly
108
-
- every change in one of the services either requires
109
-
- a redeployment of all microservices involved
110
-
- a logic to decide which microservices need redeployment to avoid inconsistencies
111
-
- violates 12 factors concept
113
+
- Accessing data directly (without an API) means any changes in the data model affect all applications directly.
114
+
- Every change in one of the services requires either one of the following:
115
+
- Redeployment of all microservices involved.
116
+
- Logic to decide which microservices need redeployment to avoid inconsistencies.
117
+
- Violates the 12 factors concept.
112
118
113
119
:::
114
120
115
-
### Add a project for shared database
121
+
### Add a Project For Shared Database
116
122
117
123
1. Add another `cds` project to collect the models from these projects:
118
124
@@ -127,7 +133,7 @@ The advantages are as follows:
127
133
npm add @capire/orders
128
134
```
129
135
130
-
> Note how *npm workspaces* allows us to use the package names of the projects, and nicely creates symlinks in *node_modules* accordingly.
136
+
> Note how *NPM workspaces* allows us to use the package names of the projects, and nicely creates symlinks in *node_modules* accordingly.
131
137
132
138
2. Add a `db/schema.cds` file as a mashup to actually collect the models:
133
139
@@ -181,15 +187,15 @@ The project structure used here is as follows:
181
187
└─ package.json
182
188
```
183
189
184
-
The `shared-db` module is simply another CAP project, with only db content. The dependencies are installed via npm, so it is still possible to install via an npm registry if used outside of the monorepo setup.
190
+
The `shared-db` module is simply another CAP project, with only db content. The dependencies are installed via NPM, so it's still possible to install via an NPM registry if used outside of the monorepo setup.
185
191
186
-
The db model could also be collected on root level instead of creating a separate `shared-db` module. When collecting on root level, the `cds build --ws` option can be used to collect the models of all npm workspaces.
192
+
The db model could also be collected on root level instead of creating a separate `shared-db` module. When collecting on root level, the `cds build --ws` option can be used to collect the models of all NPM workspaces.
187
193
188
194
:::
189
195
190
-
### Deployment as separate mta
196
+
### Deployment as Separate MTA
191
197
192
-
In a setup with multiple deployment units, we can add the `shared-db` project as its own mta deployment:
198
+
In a setup with multiple deployment units, we can add the `shared-db` project as its own MTA deployment:
193
199
194
200
```sh
195
201
cds add mta
@@ -260,11 +266,11 @@ resources:
260
266
261
267
262
268
263
-
#### Binding to shared database
269
+
#### Binding to a Shared Database
264
270
265
271
The only thing left to care about is to ensure all 3+1 projects are bound and connected to the same database at deployment, subscription, and runtime.
266
272
267
-
Configure the mta.yaml of the other apps to bind to the existing shared database, for example, in the reviews module:
273
+
Configure the _mta.yaml_ of the other apps to bind to the existing shared database, for example, in the reviews module:
268
274
269
275
```yaml [reviews/mta.yaml]
270
276
...
@@ -295,15 +301,15 @@ resources:
295
301
#### Subsequent updates
296
302
297
303
- TODO...
298
-
- Whenever one of the projects has changes affecting the database, that triggers a new deployment of the `shared-db` project
304
+
- Whenever one of the projects has changes affecting the database that triggers a new deployment of the `shared-db` project
299
305
- `git submodules`gives you control of which versions to pull, for example by `git branches` or `git tags`
300
306
- Ensure to first deploy `shared-db` before deploying the others
301
307
302
308
303
309
304
310
## All-in-one Deployment
305
311
306
-
Here we go on with our guide how to deploy all 3+1 projects at once with a common `mta.yaml`
312
+
This section is about how to deploy all 3+1 projects at once with a common _mta.yaml_.
307
313
308
314

309
315
@@ -359,18 +365,18 @@ build-parameters:
359
365
360
366
361
367
::: info `cds build --ws`
362
-
If the CDS models of every npm workspace contained in the monorepo should be considered, then instead of creating this `shared-db` folder, you can also use:
368
+
If the CDS models of every NPM workspace contained in the monorepo should be considered, then instead of creating this `shared-db` folder, you can also use:
363
369
```shell
364
370
cds build --for hana --production --ws
365
371
```
366
-
The `--ws` aggregates all models in the npm workspaces.
372
+
The `--ws` aggregates all models in the NPM workspaces.
367
373
368
374
In this walkthrough, we only include a subset of the CDS models in the deployment.
369
375
:::
370
376
371
377
372
378
::: details Configure each app for cloud readiness
373
-
The preceding steps added configuration only to the workspace root.
379
+
The preceding steps only added configuration to the workspace root.
374
380
375
381
Additionally add database configuration to each module that we want to deploy - bookstore, orders, and reviews:
376
382
@@ -384,7 +390,7 @@ npm i @cap-js/hana --workspace reviews
384
390
385
391
### Applications
386
392
387
-
Replace the mta module for samples-srv with versions for each CAP service and adjust `name`, `path`, and `provides[0].name` to match the module name. Also change the `npm-ci` builder to the `npm` builder.
393
+
Replace the MTA module for `samples-srv` with versions for each CAP service and adjust `name`, `path`, and `provides[0].name` to match the module name. Also change the `npm-ci` builder to the `npm` builder.
388
394
389
395
::: code-group
390
396
```yaml [mta.yaml]
@@ -500,7 +506,7 @@ Add the admin role
500
506
:::
501
507
502
508
::: details Configure each app for cloud readiness
503
-
Add npm dependency `@sap/xssec`:
509
+
Add NPM dependency `@sap/xssec`:
504
510
505
511
```shell
506
512
npm i @sap/xssec --workspace bookstore
@@ -713,7 +719,7 @@ modules:
713
719
714
720
#### Static Content
715
721
716
-
The approuter can serve static content. Since our UIs are located in different npm workspaces, we create symbolic links to them as an easy way to deploy them as part of the approuter.
722
+
The approuter can serve static content. Since our UIs are located in different NPM workspaces, we create symbolic links to them as an easy way to deploy them as part of the approuter.
717
723
718
724
```shell
719
725
mkdir .deploy/app-router/resources
@@ -768,7 +774,7 @@ modules:
768
774
```
769
775
:::
770
776
771
-
The xs-app.json file describes how to forward incoming request to the API endpoint / OData services and is located in the app/router folder. Each exposed CAP Service endpoint needs to be directed to the corresponding application which is providing this CAP service.
777
+
The _xs-app.json_ file describes how to forward incoming request to the API endpoint / OData services and is located in the app/router folder. Each exposed CAP Service endpoint needs to be directed to the corresponding application which is providing this CAP service.
772
778
773
779
::: code-group
774
780
```json [.deploy/app-router/xs-app.json]
@@ -854,7 +860,7 @@ Additionally, the welcomeFile is important for deployed Vue UIs as they obtain C
854
860
855
861
### Deploy
856
862
857
-
In order to build, deploy, and undeploy easily, add these `npm` scripts:
863
+
To build, deploy, and undeploy easily, add these `npm` scripts:
858
864
859
865
::: code-group
860
866
```json [package.json]
@@ -868,13 +874,13 @@ In order to build, deploy, and undeploy easily, add these `npm` scripts:
868
874
869
875
Before deploying you need to log in to Cloud Foundry.
870
876
871
-
To locally build the apps, run
877
+
Build the apps locally:
872
878
873
879
```shell
874
880
npm run build
875
881
```
876
882
877
-
To deploy the built artifacts to Cloud Foundry, run
883
+
Deploy the built artifacts to Cloud Foundry:
878
884
879
885
```shell
880
886
npm run deploy
@@ -923,26 +929,26 @@ While these benefits exist, they are accompanied by complexity and performance l
923
929
924
930
Instead of just choosing between a monolith and microservices, these aspects can be combined into an architecture that fits the specific product.
925
931
926
-
Since each cut not only has benefits, but also drawbacks, it is important to choose which benefits actually help the overall product and which drawbacks can be accepted.
932
+
Since each cut not only has benefits, but also drawbacks, it's important to choose which benefits actually help the overall product and which drawbacks can be accepted.
927
933
928
934

929
935
930
936
### A Late Cut
931
937
932
-
When developing a product it may initially not be apparent where the boundaries are.
938
+
When developing a product, it may initially not be apparent where the boundaries are.
933
939
934
940
Keeping this in mind, an app can be developed as a modular application with use case specific CAP services.
935
941
It can first be deployed as a [monolith / modulith](#monolith-or-microservice). Once the boundaries are clear, it can then be split into multiple applications.
936
942
937
943
Generally, the semantic separation and structure can be enforced using modules. The deployment configuration is then an independent step on top. In this way, the same application can be deployed as a monolith, as microservices with shared db, as true microservices, or a combination of these, just via configuration change.
938
944
939
-

945
+

* Prefer staying loosely coupled → for example, ReviewsService → reviewed events → UPDATE avg ratings
946
952
* Leverage db-level integration selectively → Prefer referring to (public) service entities, not (private) db entities
947
953
948
954
## Appendix
@@ -956,14 +962,14 @@ A monolith is a single deployment unit with a single application. This is very c
956
962
A modulith, even though the app is separated into multiple CAP services inside multiple modules, can still be deployed as a single monolithic application.
957
963
This combines the benefit of a clear structure and distributed development while keeping a simple deployment.
958
964
959
-

965
+

960
966
961
967
True microservices each consist of their own deployment unit with their own application and their own database.
962
-
Meaning that they are truly independent of each other. And it works well if they actually are independent.
968
+
Meaning that they're truly independent of each other. And it works well if they are actually independent.
963
969
964
970

965
971
966
-
The above is a simplified view. In an actual microservice deployment, there are typically shared service instances and wiring needs to be provided so that apps can talk to each other, directly or via events.
972
+
What was mentioned earlier is a simplified view. In an actual microservice deployment, there are typically shared service instances and wiring needs to be provided so that apps can talk to each other, directly or via events.
967
973
If the microservices are not cut well, the communication overhead leads to high performance losses and often the need for data replication or caching.
968
974
969
975

@@ -983,7 +989,7 @@ Benefits:
983
989
Requirement:
984
990
- The app needs to be stateless, state needs to be persisted
985
991
986
-
Multiple app instances can be used both for monoliths and microservices.
992
+
Multiple app instances can be used for both monoliths and microservices.
987
993
988
994

989
995
@@ -1027,7 +1033,7 @@ For some parts, a 100% cpu utilization over an extended period is accepted for e
1027
1033
1028
1034
#### Fault Tolerance
1029
1035
1030
-
While app instances already provide some resilience, there are failure classes (e.g. bugs) which affect each app instance.
1036
+
While app instances already provide some resilience, there are failure classes (for example, bugs) which affect each app instance.
1031
1037
1032
1038
Separating functionality into different apps means that when one app experiences issues, the functionality of the other apps is still available.
1033
1039
In the bookstore example, while reviews may be down, orders may still be possible.
@@ -1038,7 +1044,7 @@ This benefit is null for apps with synchronous dependencies on each other. If A
1038
1044
1039
1045
With multiple apps, you can still deploy them together as one unit, for example as part of a multitarget application archive.
1040
1046
Once an application grows bigger, this takes a significant amount of time.
1041
-
Deployments can then be split up either by type (e.g. deploying UIs separately) or horizontally (e.g. deploying each app via its own deployment unit).
1047
+
Deployments can then be split up either by type (for example, deploying UIs separately) or horizontally (for example, deploying each app via its own deployment unit).
1042
1048
1043
1049
Benefits:
1044
1050
- Faster individual deploy times
@@ -1048,7 +1054,7 @@ Drawbacks:
1048
1054
- Coordination between deployment units for updates with dependencies
1049
1055
- Configuration wiring to connect systems across deployment units
1050
1056
1051
-

1057
+

1052
1058
1053
1059
1054
1060
With a single deployment unit, when a fix for one part needs to be deployed, the risk of redeploying the rest of the application needs to be considered.
@@ -1067,7 +1073,7 @@ Here we need to differentiate between two scenarios:
1067
1073
- Using multiple databases of the same type
1068
1074
1069
1075
A polyglot persistence can be used when the app has different requirements for the types of data it needs to store.
1070
-
For example, there may be a large amount of large files that can be stored in a document store, while corresponding administrative data is stored in a relational database.
1076
+
For example, there may be a large number of large files that can be stored in a document store, while corresponding administrative data is stored in a relational database.
1071
1077
1072
1078
Benefits:
1073
1079
- Use suitable technology for different use cases
@@ -1093,7 +1099,7 @@ Drawbacks:
1093
1099
1094
1100
When data is distributed across multiple databases, strategies may be necessary to combine data from multiple sources.
0 commit comments