 Hello Angular and Spring Boot fans. Today I'd like to show you how to deploy Angular just with Docker, and then I'd like to show you how to combine your Angular and Spring Boot app into a single artifact. And then we'll use Docker to containerize that application and deploy it to Google Cloud using Knative. We'll also deploy it to Heroku and Cloud Foundry. Let's get started. This screencast is based off the blog post I wrote called Angular plus Docker with a big hug from Spring Boot. And you can see that Angular and Spring Boot is one of the most popular combinations, at least as far as search traffic goes with Google's keyword planner. If you try React and Spring Boot, only gets 1,000 versus Angular and Spring Boot 3,600. Other popular frameworks, less and less. So this is the fourth part in a series. There's three previous blog posts and three previous screencasts. At the bottom of this blog post, it links to a GitHub repo. So if you scroll all the way down, there it is and that GitHub repo is also open right here. And if I click on demo.adoc, this is an ASCII doc demo script that I wrote that's much shorter than the blog post and it just condenses all the steps. So if I view the raw version, I have my handy-dandy ASCII doctor plugin that makes it look good, right? So you'll need Java 11, Node 12 and Docker all installed and we'll go through these steps. We'll create an Angular and Spring Boot app. We'll use a previous one that we created. We'll create a Docker container for our Angular app. We'll deploy Angular and Docker to Heroku. We'll combine our Angular and Spring Boot jar into a single jar and then we'll Dockerize that and deploy all the rest of them. And I'll show a pretty cool feature in Spring Boot 2.3 that makes Docker images very easy. So we'll start by cloning our previous example which was Angular deployment and in that screencast and blog post, what I did is I just showed how to use Angular's NG deploy to deploy to various providers. So we'll go ahead and clone that and then we'll put these instructions on the left here and we'll log into Heroku. I've already logged in. So if you don't have a Heroku account, you'll need to do that, create a new app and call it bootiful Angular. And if this name is already taken, just choose another name and then we'll go into the resources tab and we'll add Octa this way. And so this will actually create an Octa developer account for you and provision it all through Heroku. And it takes about 20 seconds for that to create so you'll notice this free right here as soon as that turns into a checkbox then you'll be good to go. It sets up your account, creates two applications in it. One's a spa application, a single page application that you can use with Angular or ReactorView and then there's a web application which you can use with Spring Boot. It's already configured for Spring Boot in the backend. So if we go to our settings here and reveal the configuration variables, you can see it populated all those for us. And if you were to go back to resources and click on Octa, it will automatically log you in with an administrator account for that tenant. So you can click on applications and you'll see the applications that create it. So let's get our Spring Boot app running first. If we go to Octa Angular and go into the notes API directory, you can create an octa.env file and basically put these values in it. And we'll grab the issuer from our configuration variables. And now we can go ahead and start this by sourcing that octa.env and running it using Gradle W boot run. And if you're on Windows, you'll just create an octa.bat file and then instead of using export, just use set and then run octa.bat before running Gradle run. So if we were to go to localhost 8080 API notes, it'll redirect us. And since we're already logged in, it automatically locked us in. So that's pretty slick. And if we hadn't, if we tried to do it with like HTTP IE and went to 8080 API notes, it'll return a 401. So look up at the top there or a 302 because it tries to redirect us to log in. So that's all working. One thing I wanted to show you is an IntelliJ. If we open this up, you can easily configure the default spring boot process to use those same environment variables. So when it prompts you to import Gradle, click import and then modify the configuration that's generated for you. Actually, we wanna grab the variables first. So octa.env and go ahead and edit configurations. And then for environment and environment variables, just click on paste. And then you can remove these and click okay. And now you could run it right from your ID so we can stop this process here and run it right from IntelliJ. And we need to configure the Angular app to work with our created client ID and issuer. So under auth routing is where that's configured. So grab that same issuer, 108263 and change it from our previous one here. And then we'll also grab the ID for the spa, not for the web. And then it prompts us to run npm install. So we'll do that. And you can run ng serve in the notes directory. And once that's finished, you can open 4200 up in your browser. And let's try to log in. And so I have noticed this problem when you have a previous octa application that you ran on the same port. So if I clear the site data, try it again. Now I do log in. It all works. And if we view the notes, we can add a new one. First note on local and that all works. And if we go to our run tab, we can see that the demo application talked to it. So that's all working. You can commit that to source control to say, hey, we've configured OIDC with octa quickly and easily. So there we are. And let's make sure, yep, okay. So now we can create a Docker container for our Angular app. So to do that in the notes directory, create a Docker file and then I have a shortcut for it. So I just typed NG Docker, you can see it right there. That is an IntelliJ IDEA shortcut. So those are available, the ones that I created at IDEA Live Templates on GitHub under my username. And Live Templates basically allow you to just prerecord snippets. So I prerecorded all the ones that I'll use in this demo. And you can see that Docker file is one of them. So this basically pulls from node 14.1 Alpine and it copies the package.json into this opt web and then it runs npm install and then it goes ahead and runs ng-build-dash-prod. And then it pulls from nginx and uses the default configuration and copies from that compiled directory for Angular into the root directory for nginx. And so we can take and create an nginx that is spot aware. So if we create new nginx.config, you'll see that it listens on port 80, just any old server name that goes to that root. It's got that index.html, but this is the real spot awareness piece which says any file should go to index.html because that's where all the route handling happens. And then we can build it with docker-build-t and whatever name you give it. I'm gonna use ng-notes. You can see that took about seven minutes to run. A lot of that slowness is based on Camtasia. I found that if I don't have Camtasia running to record my screen, it actually executes much faster, but there is a lot going on there so it's not too unexpected. You can run it with docker run and map 80 to 4200. And then if you go to localhost 4200, you'll see there it is. And then if we try to view the notes, it actually makes a request to Heroku. You see beautiful Angular Heroku app and that's because the environments are configured that if you're in production, it wants to go to that URL versus in development and goes to this one. So when you build with ng-build-dash-prod, it uses this file instead of the other one. So to fix that, let's deploy our Spring Boot app to Heroku. But first I'm going to actually take these commands and put them in my package.json file just because I found that's an easier way to remember them. So you can run npm run docker to build it and npm run ng-notes to run it. So you'll first need a Heroku account which I have and the Heroku CLI. So if you don't have the Heroku CLI installed, you can Google for it and go ahead and install it from there. It's got support for Mac, Windows and Linux. So shut that one down, Heroku login. Press any key to open up a browser. Then click login. And now I'm logged in. And I can do Heroku apps. And I'll see that beautiful Angular one. So we're looking good there. And we'll start by associating our existing Git repo with that Heroku app. So we can go ahead and define an app name. Beautiful Angular. And then we'll do Heroku Git remote. And that'll add a new Heroku remote. So if we do git remote-v, you can see there it is. And then you can use what's called a mono repo build pack for Heroku to basically deploy from subdirectories in your project. By default, Heroku expects your top level directory to contain either a package.json or build.gradle or a pom.xml. So using the mono repo plugin, you can set an app base and then it'll read from that directory. So you need to add the mono repo build pack as well as Heroku Gradle. And then we'll go ahead and add Postgres. And by default, what Heroku does with the Gradle build pack is it runs Gradle build and excludes the tests. So we want it to run bootjar-p-prod. And if you wanna figure out how that bootjar works in the prod settings, check out my last video on Angular deployment where I took an Angular app that was basically configured locally and made it work in production and changed the production URLs. Change that to bootjar. And then I'm gonna edit the existing app using Heroku config edit. And I'm gonna remove the web part of the variable names because the Spring Boot app uses Okta's Spring Boot Starter and that expects a few properties. Okta OAuth client ID, client secret and issuer. If we use web as a suffix on these, it won't override those values. It won't set those values. So by just removing the web, then it'll override those values. So we update bootiful Angular with that and then we can push to Heroku. Once that completes, we can run Heroku open. And you'll see it actually logged us in and said, you know, hello to the user. And that's because in the Spring Boot project, there's a home controller that maps to the root URL and it grabs the OIDC root user and prints that out. So now our Angular app should be able to talk to it. Oh, it's not running. So let's go back to our steps. One thing is to actually set it. So by default, if you look in the resources application prod, it has the DDL auto to update. So that will create the schema the first time it runs. But we don't want to recreate the schema every time it runs because it'll actually drop the tables and then we lose our data. So go ahead and set that or override that value to be validate. And then if you were using a different application name, which I expect you might be, you'll need to go into this Angular app and change this name to match wherever you deploy to and then rebuild your actual, you know, Docker container. So you also need to modify the Heroku app to allow the allowed origins from a local host. So we can do that as well. And then if you want to see the logs from your Heroku app, you can do Heroku logs and dash dash tail. And you can see it's restarting there. And now it's up. And we don't need to rebuild our Docker container because we didn't change anything in the Angular app. So we can just do MPM run Docker. Hope that to be in the notes directory. And now if we go to local host 4200, that's the build one. So MPM run NG notes. There we are. So now if we were to view the notes, first of all, we get no errors. Let's try creating one. First note on Heroku, that actually worked. And if we're to go to back to our Heroku and go to API notes, we'll see that that was actually entered on Heroku. So that's all working. You can actually deploy your Angular app directly to Heroku as a Docker container. So this is part of Heroku's container registry and its features. So we'll stop that one. And we'll do Heroku container login. And we'll create a new application for our Spring, or for our Angular app. We've got RockyDawn 37186. So first of all, we'll need to add a new remote with that. So we'll call this a Docker remote, RockyDawn. And so now we have three remotes. We have the origin, we have Heroku for our Spring boot app, and we have Docker for our Angular app. And you'll need to update the nginx config. So it reads from a port variable. So specify that as port. This will be an environment variable that Heroku will set. And then locally, if it's not set, it'll run on port 80. And then we also need to escape this URI because what I'm gonna do is I'm gonna do some property substitution. And if we did, if we left that as a single dollar sign, it would actually replace that with nothing. So that's a way of escaping it. And then we can update our Docker file to use this Msubster project, which allows default variables. So normally you can replace certain text with environment variables. And with this one, it allows you to do the default like I have here. So most of them will make you specify one. This one allows you to specify default. So I'll go ahead and add this in here. So if you were to look, the big difference is, right from here to here. Everything else is pretty much the same. So we're gonna add curl. We're gonna grab that Msubster project and then copy the nginx config and go ahead and do the substitution when it starts up. So now we can push that container. Heroku container. And so this finds that Docker file in our project and automatically does the build and uploads it. So you see the image has been pushed successfully. Now we can do Heroku container release. And now we can open it up in our browser. So we can say Heroku open. And this is our new URL. So we have to configure Spring Boot to allow that URL. And we have to configure octa to know about it as well. So Heroku config edit. So for the allowed origins, we'll add another one here. And then control X, yes, yes. And so that will reload our Spring Boot app. If you wanna watch it, you can do Heroku logs, tail, remote Heroku, you'll see it restarting. And then we'll need to add that app URL to octa as well. So if we go to the spa app on octa, we can edit and add the redirect URI. So this will be allowed. And for the log out as well and save it. And now if we were to try and log in, you can see we're able to log in. If we view the notes, it will fetch the notes for the user. So that's all working pretty slick. How you can deploy a Docker file very easily to Heroku using their container registry. So if you look at our freshly deployed app on security headers.com, you'll notice it gets an F, right? That's not a very good security report score. So let's go ahead and fix it by modifying this engine X config and adding security headers. So you can see this adds a content security policy, allows XHR connections to octa.com and Heroku app. So if you're deploying somewhere else you'll need to modify that and refer a policy basically a number of security headers that security headers.com expects. So once we have those in there, we can redeploy using container push and container release. And this will be much faster this time because a lot of the information has been cast from the previous build. Now let's see how it does. Booyah, we got an A. All right. So now the next step is to combine our Angular and Spring Boot application into the same one. Currently we use octa's Angular SDK and Angular and we use octa's Spring Boot starter for Spring Boot. And that works, but it also stores access token on the client and Angular. And if we can have everything happen in Spring Boot and package the app in Spring Boot, then it's a little more secure. And there's no cross origin resource sharing involved. There's no access token stored in the browser. So we're gonna start by creating a new auth service for our Angular app because we're gonna have to replace what it uses to detect if the user's logged in or not. So we'll go ahead and create that under the shared directory. We'll call auth.service.ts. And this uses one of my live templates up at the top here, my IntelliJ live templates. These are a number of live templates that I've recorded beforehand. IntelliJ allows you to basically prerecord code and then just type a couple commands to recall it. So that's what I did there. And if we look at this class, it basically has an authentication state that it listens for if the user's information has changed. And then it calls getUser. So this will call getUser on the server for Spring Boot. And if it returns a user, then it goes ahead and just sets that authentication state to true. And then to check if it's authenticated, it looks and see if the user's undefined. So what we'll do on the Spring Boot side of things is we'll change that endpoint. So if the user's not logged in, it just returns nothing. And if they are logged in, it returns a username. And then when you click log in, it's gonna redirect to Spring Boot to do the actual login. And then to log out, it uses this logic, which posts to an API logout endpoint. And then you'll get a response from that and it'll go ahead and redirect to octet to log you out. So that was done by Angular beforehand, but now we have this 50 line service that does it for us. So you also need to create a user, TS file in the same directory. And we'll export class user. And it's just gonna have a couple properties of sub, which is a number and a full name, which is a string, actually lowercase string. And then we'll update app component to use this new service. So instead of octa auth service, we'll just delete that. And instead of octa auth, we'll just call it auth. And then we need to import that auth service and we need to adjust it so it's not importing octa one. Okay, so same code looks very similar. It's just not using octa anymore. It's talking to Spring Boot to get that information. And then we can remove the octa auth module from this app component spec because we don't need that anymore for testing. We will need HTTP client testing module though because there will be some client interactions that happen in the tests. And then home spec has it as well, client testing module and adjust the imports. Okay, we're looking pretty good. And then we'll change the buttons in app component. So instead of calling octa auth, calling auth, and then instead of login redirect, just call login. And then we'll update the home component to use the auth service as well and import that and adjust our imports. Okay, looking pretty good there. And then we can delete the auth routing module so we no longer need that. And we can delete shared octa which had our interceptor in it before. And then we'll need to modify the app.module. So first of all, imports that home component and then we can move the auth routing module and we'll need to import the HTTP client module since that was done by the auth routing module before. And then we can add our home component and its routes in app routing. And import that. Okay, we're looking pretty good. Now as far as our environments, we no longer are going to make a request to a different server so we can change them both to just be the current server. And then what we'll do to get around cores when we're running in development with NG serve is we'll use a proxy. So this is a proxy comp you need to create. So proxyconf.js. And this basically says any request to user, API, go off to our login, go ahead and proxy those to spring boot and add some debug logging so we can see what's going on. And then we can add this in angular.json. So under browser target, search for that. Okay, so we have notes.build, we're under serve. And so we'll add the proxy config right here. Make sure we're on the right one, yep. And this is just for serving it up. And then we can remove octazangular SDK and octa dev schematics since they're no longer used. So at this part, our angular app's ready to go but we need to configure spring boot to host that angular app. So let's go ahead and first of all, delete the home controller since that serves up the root route, we won't need that anymore since that'll be our angular app. And we'll create a route controller that requests or forwards all requests to the index.html. So right in here, we can create an angular Kotlin class, call it route controller. And you'll see what it does is it takes any paths and forwards them to that index.html. And then we'll modify security configuration to allow public access or anonymous access to our static web files and the user info endpoint. So we're just gonna grab these two lines here and we'll go ahead and put them right here. So that says you can access all those files and you can access the root directory and that user endpoint. And then we're gonna beef up the content security policy and our other security headers. So spring security does return a number of security headers by default. This is just adding to those so we'll get a good score on security headers.com. So the other thing we'll need to do is in the user controller, right now, if you tried to get to this, you would get a 401 if you're not logged in. So we wanna make it so it returns an empty user and the way to do that is to just make the parameters and the return type optional. And with Kotlin, you just do that by adding a question mark that says they're optional. And then we'll add a logout controller to handle the API logout. So a new Kotlin class, logout controller. I call it boot logout. And you can see this takes in a client register your repository, looks up octa and then it basically grabs the ID token using this annotation and it gets it right there. And it grabs the end session endpoint from the OIDC configuration and then it basically returns a logout URL and the ID token, which then the angular client uses to redirect to octa. And then we can also add a server port. So server port and we want it similar how we did it with Docker and Angular. We wanna make it so it allows overriding it, but it defaults to 8080. And then we'll modify some spring security configuration. So instead of returning the sub by default, it returns a preferred username, which will be an email when coming from octa. And then we no longer need allowed origins in either of these files because we have no cores and we can go into demo application and remove our cores filter and our allowed origins. We can just delete that whole body and then we format so our imports are good. And now we need to modify Gradle to build a single jar and include Angular in it. So open up the build.gradle.kts and first we'll add the node plugin for Gradle and then it will import MPM task. And once we do that, it'll refresh and reload Gradle. That's what's going on down here with IntelliJ. It might give me a little prompt up here to re-import it, but in the meantime, I'm gonna define the location of my Angular app. So it's gonna be in dot dot slash notes, so up a directory and then into the nodes directory. We're gonna use node 1216.2 and you can specify another property on here called download equals true and that will actually download and install node, but I already had no install, so I don't need to do that. And it basically says that hey, this is where to read from for the node modules and then we can add a build web task. So we'll go down here at the bottom. There's that auto reload I suspected would come and we can say Gradle web is my shortcut. And what this does is it uses that node project to run MPM install, run the build and pass in dash dash prod for Angular and then it has that inputs directory and inputs dir and the reason all these are set up is so there's caching involved. So it knows not to rebuild if it doesn't need to. And then we can also modify this process resources and this says if it's actually the production profile, then build the Angular app. And if not, then don't. And so we could actually show this working now. So we still have ng serve, right? For the Angular app and for the server. We can start it right here. Stop and rerun. So our Angular app is up. Our spring boot app is almost up. Okay, that's up as well. And now we can go to localhost 4200. And if we were to log in, it redirects to spring boot and it comes back and it's logged in here. And if we were to add a new note, new note in a single jar, not quite in a single jar yet, but you can see, right? We can still develop Angular locally using ng serve. We can still develop spring boot using boot run. And so any hot reloading or anything you get from both of those will all still work. And so you can also build everything with Gradle bootjar-p-prod. So we can go back to our terminal here and go into the notes API directory and run that command. And once that's finished, you can use Docker compose, which is already installed in here to run your Postgres production database. So I can do Docker compose, have source main Docker Postgres up. We'll just leave that. You can run it with dash d and it'll run as a daemon. So you don't see anything. I like to see stuff. So we'll do it that way. And then we'll go ahead and go into that notes API directory and run just the jar itself. So source that octa first and then Java dash jar build libs star dot jar. So 8080 is already in use. I have a nice command called fkill. You just kill it and try again. Now if we go to localhost 8080, there we are. And if we want to add a new note, first psql note, you can see it was saved and we see the logs there. So it's all working as a package jar. It's got Angular inside a spring boot, bit more secure than it was before. And now we can use Docker to actually build both of them. So jib is a plugin from Google that allows you to build Docker containers without having a Docker daemon running. You can actually put it right into the cloud if you want. I'm just gonna do it with the Docker daemon first. But if we add the jib plugin to cradle, that's the best way to begin. And then we have some jib configuration. So my image is going to be named mrable slash bootiful angular. So if you're using Docker, it's usually based on your username. So you might have a different username for your container. And then I'm mapping whatever the profile is to the environment. So it pulls in that and sets that spring profiles active. And then we can build a Docker image now. So we'll close everything down and run gradle w jib Docker build dash p product. And so jib is smart enough to just read from your gradle or your maven file and figure out all the different parameters it needs to build your image. So pretty slick that way. So you can see it took a little more than a minute to build that container. And a lot of that was just going through and figuring out if Angular was compiled or not. So normally you could run that container using Docker run and mapping that port of 8080 to your local 8080. But it won't work because you don't have any environment variables configured, right? Octa isn't configured. So it'll blow up when it tries to start. And so you can use Docker composed to actually solve that. So we could start, there's a slick feature of Docker where you can put a .env file into the current directory. So let's call it .env and then we'll remove these exports. And this means that any Docker file that starts from this directory will be able to read these properties. So then what we can do is create an app.yml for our app in here. And then the image name is mrables slash bootflangular might be different for you. And you'll see it reads those variables as well as this is configured to talk to that postgres container that is configured down here and we depend on it. So by using the depends on what that allows us to do is wait for postgres to start and then start the Spring Boot application. So there's two ways to do this. You can either go into source main Docker and run Docker compose, right? fapp.yml, that's certainly one way. But the way that I like to do is from the root directory. So I'm just gonna create a sim link that goes to source main Docker .env because Docker compose does look for that .env file in the same directory. And then I can run Docker compose dash f source main Docker app up. And you can use dash d, but by not using dash d you get to see the logs of everything starting. So this should allow us to view 8080 again. And it all works. And we could add another one to say second note works too. All right. So we're having some fun now. Well now what we can do is deploy this container to a number of different hosting providers. Let's start with Heroku. But before we do that, I want to actually deploy this to Docker Hub. So create a Docker Hub account if you don't have one at hub.docker.com slash sign up. I already have one. So I can log into it if I were to do Docker log in. So I'm already logged in. And then I can actually run Gradle Jib without Jib Docker build. And it'll deploy right to Docker Hub. So now we have our container on Docker Hub. If I was to go to Docker Hub, I think it's hub.docker.com sign in. You can see it was uploaded a few seconds ago. So it's working pretty well now. And what I can do is now deploy that to Heroku. So first of all, isn't it cool how Jib doesn't make you need a Docker file? It actually reads right from your POM or Gradle build and makes it all work. So let's start by creating a new Heroku app for this container. Heroku Create. And we get Animatic Reef. So we'll go ahead and grab this URL right here. Adding a new remote. So get remote, add, we'll call it Jib. And we'll go to that URL. And then we'll Heroku add-ons. We'll create a Postgres add-on. Heroku Postgres. And specify the remote is Jib. And normally what happens when you deploy a Spring Boot app and you have Heroku add-on configured, Heroku will know that it's Spring Boot and configure your Spring properties and parse your database URL accordingly. But since we're using Docker, it has no visibility into our actual project. So we'll need to do some manual configurations. So we'll get the database URL that it's set. And then we'll grab this. We'll create a new scratch file. We'll just say Text. And so what we need to do is make this into a JDBC URL. Let JDBC Postgresql to start. And then we need this name right here. So after the at sign is our URL. So we can set this accordingly here. Let's get these commands set up. And then we want to say the remote is Jib. We have these other ones here for setting the username and password. And this, that's the password. And the username. Copy those. And run them. Paste. Nope. Copy. Let's try a different terminal. There we go. And now we can add Octa. You could reuse the same settings for the other one, but you can also just add a new Octa add on for this one as well. And then all the URLs will be already configured. And we can run this command to check the creation process and progress. So it's still creating. And now it's created. And we can run Heroku config edit remote Jib. And the reason we're doing this is to remove the web suffix because the Spring Boot starter expects you to have Octa OAuth2 client ID defined and the secret as well as the issuer. And this web is not recognized. So it won't override those variables. And then you hit Control-X. Yes. Return. Yes. And it'll update those values. And now we can run these commands to deploy the image to GitHub. So first of all, Docker tag. And then M-Rable. And then Matic Reef and web. Now that that's pushed, we can release it. So Heroku container, release web, remote is Jib. I wonder if our push failed. Try it again. Let's try our push again. OK. Now we'll release it. And to watch the logs, see it's starting. You can do Heroku logs, tail, and the remote is Jib. And it changed from starting to up. So that's a good sign. We'll just cancel out of there. Heroku open dash dash jib, the remote jib. And if we were to try to log in, we can grab the values from over here. So personal, animatic reef, and the settings from the reveal config bars. We can grab the email here. Sure, we'll save that. And ask for a security question so you can do password recovery. And I like this one. So now, if we were to view the notes, there aren't any. But we can certainly add some. So first on Heroku, there's a single jar. And that's all working. And the cool thing is, if we check it in security headers, we get an A plus. So how cool is that? Way to go, spring boot. The last thing we want to do is change that DDL auto so it doesn't recreate the database each time it loads. So now let's try and deploy this container to Google Cloud using Knative. Knative is similar to Heroku, except what happens with Heroku is you reach a certain point where you can't do anything on the platform anymore and typically people move away. Versus Knative, you can do everything like you can on Heroku. But if you need to do more, then you just drop down to Kubernetes. So that's why people tend to like it. So we can go to Google Cloud Console to create a new project. And I'm just going to drag this over here. So it can create a new project. And we'll call it BootNG. And then we'll go to the Cloud Shell. And we'll start by enabling Cloud and Container APIs. And this does take a couple of minutes to run. So just be aware that the first time you run it, that it might take a while to get a response. Then you can set your default zone and region. And then create a Kubernetes cluster. And I asked James Ward to help me with this tutorial about these warnings that happen right here. And he said you can safely ignore them. So don't need to worry about those. And the cluster does take a little while to create. So just wait a minute. And then you can set up cluster administration and install Istio using these commands. And then install Knative. We want to run on HTTPS. So you'll need a domain to enable HTTPS. So set that up and point it to the cluster's IP. And then you can use CertManager to automatically provision and manage TLS certificates in Kubernetes. And then you can configure Let's Encrypt for free TLS certificates. It'll renew them when they expire. And then we can deploy everything in this full command. You'll notice what this does is it sets up Postgres. And then it configures username, password, and all that. And then it configures our app named Boudofla Angular comes from our container. And we map everything to Postgres and our other files. So let's go ahead and grab that. And so this is going to be MRABLE, Boudofla Angular. And up here, we make sure we don't have any brackets anywhere. We'll just call this Angular 123 for the password. And then we need to specify that right here. And for our octa settings, we'll just grab it from our Boudofla Angular project on Heroku. We can grab the issuer. Now you can run this to deploy everything. So you can see that Boudofla Angular was created. Now if we run kubectl get kservice, we'll get the IP of that. If we go there, it's not running. So it says once the deployment's completed, do it again. So let's try that. This will reset the Postgres so it doesn't recreate every time. So we'll just grab these and set that to validate. All right, so try that. OK, so it's reconfigured, but it's still not started. There we go. Now it's started. So if we were to log in, it wouldn't work, right? Because we have to add those URIs. Well, we can grab the URI from the URL. So go to, uh-oh, we quit IntelliJ. Great! I'll just use Visual Studio now. So take that, put that in there. And this is the code we need, all right, for Okta. So we'll go here, and we'll go to Resources. And we'll log in to Okta. Go to Applications, Web, and General. Add a new one for Knative. And if we try again, we don't want to go to the whole thing. We're going to start at the beginning. And then log in, all right? And then we need to grab the credentials from over here. So I'll grab that email, grab that password. And I will say spam. Now we're logged in. We can see notes, and we can say Knative notes. Yee-haw! There we are. So it's all working on Knative now. And the last thing I want to show you is Cloud Foundry. So you can create a Pivotal web services account at run.pivotal.io. I already happen to have one. You'll need to install the Cloud Foundry CLI. So you can do that with Homebrew. And then you'll do CFLogin. So if I did CFLogin, put in my email. OK. Now I'm logged in. And I can do CFPushNoStartO and mRable, beautiful Angular. And we'll call it SecureNotes. OK. So it created that, pulled my Docker images from Docker Hub. So that's pretty slick. And then I can create a Postgres instance. And then I can run CFBS to bind service, SecureNotes, my app to my SecureNotes psql service. And then I can use CFENV, SecureNotes, to see what it specified for the database URL. And if you scroll up to the top here, here's the URL it gave you. So we do need to convert this into a JDBC URL and set some properties. So we'll open up the scratch pad here and put everything on the right. And we'll go ahead and try to process this. So let's make it a little wider. We're going to want to use this guy for the URL. So that'll be our URL. And then username and password. The app name, so export app name equals SecureNotes. And then the driver class is fine. The URL is this guy here. The username is this. Now we can run these commands. So it gave me an error. I'm not sure why, maybe because I did CFRestage too soon. Let's try it again. We can just do CFStart. And it says it's running. So SecureNotes at cfapps.io. And lucky there it is running. So now we need to add the URL to octa. All right, that's our spa. So we want to do it to the web app. And then we need log in a lot to code octa. So that's right. Yep, just the regular one for the logout. And then we should be able to log in. We'll log in. And we can add a new note, like a CF note. All right, so that's all working. The last thing you want to do is set that autoDDL to Validate. And then if you CFRestage, SecureNotes, it won't recreate your database each time. So there is an initiative called Cloud Native Buildpacks, which Heroku and Pivotal both started because they basically use Buildpacks to detect what you're deploying and then auto-configure it for you. So similar to how Spring Boot auto-configures like a JDBC connection, they auto-configure the deployment and building of an app. So they created a Pac-CLI that allows you to generate Docker containers using Buildpacks. And so I've tried to use that. And it works well when you're just doing a single application. But when you have something like this which combines applications, it doesn't work so well. So Spring 2.3 actually uses Buildpacks under the covers and added the ability to generate Docker images. So it leverages Cloud Native Buildpacks just like the Pac-CLI. And there's two new commands. There's an MVN Spring Boot Build Image and a Greater Boot Build Image. And the Paquetto Java Build Pack is used by default to create your images. And Spring Boot will use Artifact ID inversion for the image name. So in this case, it would be NotesAPI001 snapshot. And I want to override it to be mrable bootable angular, right? So I can run this command to build my image, use those same Gradle commands to package everything together and actually package it all and run it. So we'll need to do this from the Notes API directory. So you see it took about a minute. Maybe it's faster without Camtasia running, but it's all good to go. And we can actually run it using Docker Compose just like we did before. So if we were to localhost 8080, you can see it and we can log in. And we can view the same Postgres Notes we added earlier. So pretty slick, if you ask me. I mean, that really makes it super easy to have it baked right into Spring Boot. And if you want to learn more, there's Phil Webbs creating Docker images with Spring Boot 2.3.0 M1. And so if you like to read, this is really good. If you like videos, then what I would recommend is watching this video, what's new in Spring Boot 2.3 from Phil Webbs Israel. And you can skip around to the different sections. So it uses layers and basically makes it so you really only have to compile your code and build that in an optimized fashion. So it caches a lot of the previously gathered logic and just works really nicely. So if you wanna read the blog post, if anything wasn't clear, what I would recommend is read through the blog post. It's about 49 pages, so there's a lot in there. And then you can of course find the code for everything that I created today on GitHub. It has all the same code, all the same stuff we did. So you can set it up and run it and try it yourself. Thanks for watching. If you liked this video, you can follow my team on Twitter at OctaDev. You can follow me on Twitter at mrable. And we have a YouTube channel that you should subscribe to. And you'll see more videos like this one and hopefully learn a bunch about Spring Boot, Angular, and OAuth. Thanks for watching and have an awesome day.