|
3 | 3 | :commandkey: ⌘ |
4 | 4 | :toc: macro |
5 | 5 |
|
6 | | -== Reactive Java Microservices with JHipster Demo Steps |
| 6 | +// Why h2 vs h1? |
7 | 7 |
|
8 | | -Today, I'd like to show you how to use the JHipster 7 to create a reactive Java microservices architecture with Spring Boot, Spring Cloud, Spring Cloud Gateway, and Spring WebFlux. |
| 8 | += Kubernetes to the Cloud with JHipster Demo Steps |
| 9 | + |
| 10 | +Today, I'd like to show you how to use JHipster 7 to create a reactive Java microservices architecture and deploy it to Google Cloud with Kubernetes. |
9 | 11 |
|
10 | 12 | **Prerequisites:** |
11 | 13 |
|
12 | | -- https://adoptopenjdk.net/[Java 11]+ |
| 14 | +- https://sdkman.io/[Java 11]+ |
13 | 15 | - https://nodejs.org/[Node 14]+ |
14 | 16 | - https://docs.docker.com/get-docker/[Docker] |
15 | 17 |
|
16 | 18 | toc::[] |
17 | 19 |
|
18 | | -=== Build a Reactive Java Microservices Architecture |
19 | | - |
20 | | -In this demo, I'll show you how to generate a microservice architecture that uses OAuth 2.0, an API gateway, and two microservices (a blog and a store). The gateway will use PostgreSQL with R2DBC, the blog will use Neo4j, and the store will use MongoDB. |
21 | | - |
22 | | -. Install JHipster 7: |
23 | | -+ |
24 | | -[source,shell] |
25 | | ----- |
26 | | -npm i -g generator-jhipster@7 |
27 | | ----- |
28 | | - |
29 | | -. Create a directory called `reactive-stack` and initialize `git`. |
30 | | -+ |
31 | | -[source,shell] |
32 | | ----- |
33 | | -take reactive-stack # mkdir reactive-stack && cd reactive-stack |
34 | | -git init # initialize git, so apps aren't created with their own .git |
35 | | ----- |
36 | | - |
37 | | -. Use the JDL below to define your architecture and apps. |
38 | | -+ |
39 | | -==== |
40 | | ----- |
41 | | -application { |
42 | | - config { |
43 | | - baseName gateway // <1> |
44 | | - reactive true // <2> |
45 | | - packageName com.okta.developer.gateway |
46 | | - applicationType gateway |
47 | | - authenticationType oauth2 // <3> |
48 | | - buildTool gradle // <4> |
49 | | - clientFramework vue // <5> |
50 | | - prodDatabaseType postgresql |
51 | | - serviceDiscoveryType eureka |
52 | | - testFrameworks [cypress] // <6> |
53 | | - } |
54 | | - entities Blog, Post, Tag, Product |
55 | | -} |
56 | | -
|
57 | | -application { |
58 | | - config { |
59 | | - baseName blog |
60 | | - reactive true |
61 | | - packageName com.okta.developer.blog |
62 | | - applicationType microservice // <7> |
63 | | - authenticationType oauth2 |
64 | | - buildTool gradle |
65 | | - databaseType neo4j |
66 | | - devDatabaseType neo4j |
67 | | - prodDatabaseType neo4j |
68 | | - enableHibernateCache false |
69 | | - serverPort 8081 |
70 | | - serviceDiscoveryType eureka |
71 | | - } |
72 | | - entities Blog, Post, Tag |
73 | | -} |
74 | | -
|
75 | | -application { |
76 | | - config { |
77 | | - baseName store |
78 | | - reactive true |
79 | | - packageName com.okta.developer.store |
80 | | - applicationType microservice |
81 | | - authenticationType oauth2 |
82 | | - buildTool gradle |
83 | | - databaseType mongodb |
84 | | - devDatabaseType mongodb |
85 | | - prodDatabaseType mongodb |
86 | | - enableHibernateCache false |
87 | | - serverPort 8082 |
88 | | - serviceDiscoveryType eureka |
89 | | - } |
90 | | - entities Product |
91 | | -} |
92 | | -
|
93 | | -entity Blog { |
94 | | - name String required minlength(3) |
95 | | - handle String required minlength(2) |
96 | | -} |
97 | | -
|
98 | | -entity Post { |
99 | | - title String required |
100 | | - content TextBlob required |
101 | | - date Instant required |
102 | | -} |
103 | | -
|
104 | | -entity Tag { |
105 | | - name String required minlength(2) |
106 | | -} |
107 | | -
|
108 | | -entity Product { |
109 | | - title String required |
110 | | - price BigDecimal required min(0) |
111 | | - image ImageBlob |
112 | | -} |
113 | | -
|
114 | | -relationship ManyToOne { |
115 | | - Blog{user(login)} to User |
116 | | - Post{blog(name)} to Blog |
117 | | -} |
118 | | -
|
119 | | -relationship ManyToMany { |
120 | | - Post{tag(name)} to Tag{post} |
121 | | -} |
122 | | -
|
123 | | -paginate Post, Tag with infinite-scroll |
124 | | -paginate Product with pagination |
125 | | -
|
126 | | -microservice Product with store |
127 | | -microservice Blog, Post, Tag with blog |
128 | | -
|
129 | | -deployment { // <8> |
130 | | - deploymentType docker-compose |
131 | | - appsFolders [gateway, blog, store] |
132 | | - dockerRepositoryName "mraible" |
133 | | -} |
134 | | ----- |
135 | | -<.> The first app is an API gateway. |
136 | | -<.> Because the gateway is reactive, it'll use Spring Cloud Gateway. |
137 | | -<.> The gateway and microservice apps must use the same authentication type. |
138 | | -<.> Use Gradle, because a lot of y'all love it. |
139 | | -<.> Vue support is new in JHipster 7, let's use it! |
140 | | -<.> JHipster 7 supports Cypress! It seems to be more reliable than Protractor. |
141 | | -<.> Make sure and specify `microservice` as the application type for the blog and store apps. |
142 | | -<.> JDL allows you to create Docker Compose and Kubernetes deployments too! |
143 | | -==== |
144 | | -+ |
145 | | -TIP: You can find additional JDL samples on GitHub in the https://github.com/jhipster/jdl-samples[jdl-samples repository]. |
146 | | - |
147 | | -. Import this architecture definition and generate `gateway`, `blog`, and `store` apps. |
148 | | -+ |
149 | | -[source,shell] |
150 | | ----- |
151 | | -jhipster jdl reactive-ms.jdl |
152 | | ----- |
153 | | -+ |
154 | | -As part of this process, several Docker Compose files are generated for you. These allow you to run databases, the https://www.jhipster.tech/jhipster-registry/[JHipster Registry] (for service discovery), https://www.keycloak.org/[Keycloak] (for identity), all with Docker. |
155 | | - |
156 | | -=== Run Your Reactive Java Microservices |
157 | | - |
158 | | -. Open a terminal and run the following commands to start Keycloak, PostgreSQL, and the JHipster Registry. |
159 | | -+ |
160 | | -[source,shell] |
161 | | ----- |
162 | | -cd gateway |
163 | | -docker-compose -f src/main/docker/keycloak.yml up -d #jhkeycloakup |
164 | | -docker-compose -f src/main/docker/postgresql.yml up -d #jhpostgresqlup |
165 | | -docker-compose -f src/main/docker/jhipster-registry.yml up -d #jhregistryup |
166 | | -./gradlew |
167 | | ----- |
168 | | -+ |
169 | | -TIP: JHipster has a https://www.jhipster.tech/oh-my-zsh/[Oh My ZSH! plugin] that I highly recommend. It provides aliases for starting Docker containers and is a real time-saver. I've included these commands as comments above. |
170 | | - |
171 | | -. Open a new terminal window, start the blog app's Neo4j database, and then the app itself. |
172 | | -+ |
173 | | -[source,shell] |
174 | | ----- |
175 | | -cd ../blog |
176 | | -docker-compose -f src/main/docker/neo4j.yml up -d #jhneo4jup |
177 | | -./gradlew |
178 | | ----- |
179 | | - |
180 | | -. Open another terminal window, start the store app's MongoDB database, and the microservice. |
181 | | -+ |
182 | | -[source,shell] |
183 | | ----- |
184 | | -cd ../store |
185 | | -docker-compose -f src/main/docker/mongodb.yml up -d #jhmongoup |
186 | | -./gradlew |
187 | | ----- |
188 | | -+ |
189 | | -[CAUTION] |
190 | | -==== |
191 | | -To make Keycloak work, you need to add the following line to your hosts file (`/etc/hosts` on Mac/Linux, `c:\Windows\System32\Drivers\etc\hosts` on Windows). |
192 | | -
|
193 | | ----- |
194 | | -127.0.0.1 keycloak |
195 | | ----- |
196 | | -
|
197 | | -This is because you will access your application with a browser on your machine (which is named localhost, or `127.0.0.1`), but inside Docker, it will run in its own container, which is named `keycloak`. |
198 | | -==== |
199 | | - |
200 | | -. Open `http://localhost:8080` in your favorite browser. You should be able to login with `admin/admin` as credentials. |
201 | | - |
202 | | -. To prove everything works, you can run `npm run e2e` in the gateway project's directory. This will run a number of end-to-end tests with https://www.cypress.io/[Cypress]. |
203 | | - |
204 | | -=== Prepare Your Reactive Java Stack for Production |
205 | | - |
206 | | -Keycloak is a superb open source identity provider. It has excellent support for OAuth 2.0 and OpenID Connect (OIDC) and easily runs in a Docker container. I greatly appreciate Keycloak's ease-of-use. I also ❤️ Spring Security's OAuth and OIDC support. |
207 | | - |
208 | | -Spring Security makes it so you only need to override three properties to switch from Keycloak to Okta! |
209 | | - |
210 | | -Spring Cloud Gateway makes it easy to relay an access token between a gateway and microservices. It's just five lines of YAML: |
211 | | - |
212 | | -[source,yaml] |
213 | | ----- |
214 | | -spring: |
215 | | - cloud: |
216 | | - gateway: |
217 | | - default-filters: |
218 | | - - TokenRelay |
219 | | ----- |
220 | | - |
221 | | -. Install the https://cli.okta.com[Okta CLI] and run `okta register`. |
222 | | - |
223 | | -. In the gateway project's directory, run the command below. Accept the default redirect URIs. |
224 | | -+ |
225 | | -[source,shell] |
226 | | ----- |
227 | | -okta apps create jhipster |
228 | | ----- |
229 | | - |
230 | | -==== Update the JHipster Registry to Distribute OIDC Configuration |
231 | | - |
232 | | -Spring Cloud Config allows you to distribute Spring's configuration between apps. In this section, you'll configure JHipster's Spring Security settings to use Okta across all your services. |
233 | | - |
234 | | -. Add the following YAML to `gateway/src/main/docker/central-server-config/localhost-config/application.yml`. You can find the values for each property in the `.okta.env` file. |
235 | | -+ |
236 | | -[source,yaml] |
237 | | ----- |
238 | | -spring: |
239 | | - security: |
240 | | - oauth2: |
241 | | - client: |
242 | | - provider: |
243 | | - oidc: |
244 | | - issuer-uri: https://<your-okta-domain>/oauth2/default |
245 | | - registration: |
246 | | - oidc: |
247 | | - client-id: <client-id> |
248 | | - client-secret: <client-secret> |
249 | | ----- |
250 | | - |
251 | | -. Save your changes and restart the JHipster Registry: |
252 | | -+ |
253 | | -[source,shell] |
254 | | ----- |
255 | | -jhregistrydown |
256 | | -jhregistryup |
257 | | ----- |
258 | | - |
259 | | -. Use kbd:[Ctrl + C] to kill all your `./gradlew` processes and start them again. |
260 | | - |
261 | | -. Open an incognito window, go to `http://localhost:8080`, and sign in. Rejoice that using Okta for authentication works! |
262 | | - |
263 | | -. If you're feeling lucky, you can set your Okta credentials as environment variables and run end-to-end tests (from the `gateway` directory). |
264 | | -+ |
265 | | -[source,shell] |
266 | | ----- |
267 | | -export CYPRESS_E2E_USERNAME=<your-username> |
268 | | -export CYPRESS_E2E_PASSWORD=<your-password> |
269 | | -npm run e2e |
270 | | ----- |
271 | | - |
272 | | -=== Create Docker Images for Your Microservice Apps |
273 | | - |
274 | | -. Stop all your apps with kbd:[Ctrl + C]. Stop all your Docker instances too. |
275 | | -+ |
276 | | -[source,shell] |
277 | | ----- |
278 | | -docker stop $(docker ps -a -q) |
279 | | ----- |
280 | | -+ |
281 | | -TIP: Bump up the memory and CPU that Docker uses in Docker > Preferences > Resources. I have my Docker preferences set to 6 CPUs and 12GB of RAM. |
282 | | - |
283 | | -. To run your reactive stack with Docker Compose, you need to create Docker images for each app. In your three different app directories, run the following Gradle command: |
284 | | -+ |
285 | | -[source,shell] |
286 | | ----- |
287 | | -./gradlew -Pprod bootJar jibDockerBuild |
288 | | ----- |
289 | | - |
290 | | -=== Run Your Microservices Stack with Docker Compose |
291 | | - |
292 | | -Once your Docker containers are finished building, you'll want to add your Okta settings to Spring Cloud Config in JHipster Registry. |
293 | | - |
294 | | -. Open `docker-compose/docker-compose.yml` in your favorite IDE and remove the Keycloak image at the bottom. You can leave it if you like, but it won't be used in this example. |
295 | | - |
296 | | -. Update `docker-compose/central-server-config/application.yml` to contain your OIDC settings that you want to share with all your microservices. |
297 | | -+ |
298 | | -[source,yaml] |
299 | | ----- |
300 | | -spring: |
301 | | - security: |
302 | | - oauth2: |
303 | | - client: |
304 | | - provider: |
305 | | - oidc: |
306 | | - issuer-uri: https://<your-okta-domain>/oauth2/default |
307 | | - registration: |
308 | | - oidc: |
309 | | - client-id: <client-id> |
310 | | - client-secret: <client-secret> |
311 | | ----- |
312 | | - |
313 | | -. In the `docker-compose` directory, run the following command to start all your containers. |
314 | | -+ |
315 | | -[source,shell] |
316 | | ----- |
317 | | -docker-compose up |
318 | | ----- |
319 | | - |
320 | | -. Open `http://localhost:8080`, sign in, and access all of your microservices. Pretty slick, eh?! 🤓 |
321 | | - |
322 | | -== What About Kotlin Microservices? |
323 | | - |
324 | | -JHipster supports Kotlin-based microservices thanks to its https://github.com/jhipster/jhipster-kotlin[Kotlin blueprint], supported by https://github.com/sendilkumarn[Sendil Kumar N]. |
325 | | - |
326 | | -You can install it using npm: |
327 | | - |
328 | | -[source,shell] |
329 | | ----- |
330 | | -npm install -g generator-jhipster-kotlin |
331 | | ----- |
332 | | - |
333 | | -Then, use `khipster jdl reactive-ms` to create the same stack you did above with Kotlin. |
334 | | - |
335 | | -NOTE: At the time of this writing, JHipster's Kotlin blueprint doesn't support JHipster 7. Watch the https://github.com/jhipster/jhipster-kotlin/releases[project's releases page] for updates. |
336 | | - |
337 | | -== How Do I Deploy to the Cloud? |
338 | | - |
339 | | -JHipster creates a cloud-native microservices architecture that can be deployed to many cloud providers. There's specific support for AWS, Microsoft Azure, Heroku, and Google Cloud Platform. |
340 | | - |
341 | | -However, if you're doing microservices, you'll probably want to leverage Docker as you did in this tutorial. When your apps are containerized, they can be orchestrated with Kubernetes. |
342 | | - |
343 | | -JHipster has a https://www.jhipster.tech/kubernetes/[Kubernetes] sub-generator that you can use to deploy it to the cloud. I'll cover this in a future demo. |
| 20 | +== Create a Kubernetes-Ready Microservices Architecture |
344 | 21 |
|
345 | | -In the meantime, you can watch a presentation that https://twitter.com/saturnism[Ray Tsang] and I did recently that shows how to deploy JHipster microservices with Kubernetes. If you start watching from https://youtu.be/AG4z18qePEw?t=2778[46:18], you'll see Ray show how to deploy to Google Cloud using Kubernetes. |
| 22 | +== Generate Kubernetes Deployment Descriptors |
346 | 23 |
|
347 | | -++++ |
348 | | -<div style="text-align: center; margin-bottom: 1.25rem"> |
349 | | -<iframe width="700" height="394" src="https://www.youtube.com/embed/AG4z18qePEw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> |
350 | | -</div> |
351 | | -++++ |
| 24 | +== Install Minikube to Run Kubernetes Locally |
352 | 25 |
|
353 | | -== Should You Go Reactive? |
| 26 | +== Create Docker Images |
354 | 27 |
|
355 | | -As with most software architecture decisions, it depends. Are you building CRUD apps? Then no, Spring MVC is good enough. |
| 28 | +== Register an OIDC App for Auth |
356 | 29 |
|
357 | | -Are you dealing with massive amounts of steaming data and millions of customers? Then yes, reactive frameworks like Spring WebFlux might just save you $$$ on your monthly cloud bill. |
| 30 | +== Encrypt / Decrypt Your Spring Cloud Configuration |
358 | 31 |
|
359 | | -What about https://wiki.openjdk.java.net/display/loom/Main[Project Loom]? Will it allow you to write regular non-reactive code that performs as good as reactive frameworks? I'm not sure. I'm betting on reactive for now. I think it's a good skill to have for Java developers. |
| 32 | +== Deploy to Google Cloud (aka GCP) |
360 | 33 |
|
361 | | -== Stay Hip with JHipster! |
| 34 | +== Encrypt Kubernetes Secrets |
362 | 35 |
|
363 | | -⛑ Find the code on GitHub: https://github.com/oktadeveloper/java-microservices-examples/tree/main/reactive-jhipster[@oktadeveloper/java-microservices-examples/reactive-jhipster]. |
| 36 | +== Scale Your JHipster Microservices |
364 | 37 |
|
365 | | -👀 Read the blog post: https://developer.okta.com/blog/2021/01/20/reactive-java-microservices[Reactive Java Microservices with Spring Boot and JHipster]. |
| 38 | +== Monitor Your Kubernetes Cluster with K9s and KDash |
366 | 39 |
|
| 40 | +== Learn More About Java Microservices and Kubernetes |
0 commit comments