 So what I'll be showing is a very basic hello world application that will be deployed in a container to the OpenShift container cluster management solution. And essentially, we're going to build it and pretend we're testing it and deploy it and show how it works with our GitLab integration. So I've just imported a very basic application here into GitLab. So it's made up of two files, a server, RRB, which is just a Ruby server sitting out hello world, and a Docker file, which is what we're going to use to bundle up the application into a container. So it contains our base image that we're going to use to bring in all those dependencies we need to run our application. So in this case, the Ruby base image, it's going to copy in our files. It's going to expose our web application on port 5000, and then it's going to actually run our server. So in this demo, everything is blank, but we're going to assume that this is our application that we've been iterating on for a while within GitLab. We've been working on creating new merge requests. We've made new issues, iterated on work, created some branches, and maybe released some tags already. So we're going to pretend this is like a already, we've already done some work in this application. Next what we need to hook up is our testing solution, our continuous integration solution. So we're going to go ahead and do that next. So under the Settings tab in GitLab for your project, under the CI CD pipeline, we have this page where you can set up your CI runners. Now if your company had already set up shed runners, you may not have to do this. In this case, we're going to set up a very specific runner for this project. And we're going to make use of OpenShift to run our CI build. Using OpenShift or any Kubernetes cluster is pretty advantageous for our CI runners, because it's very easy to set up. And then you get the ability to run parallel CI jobs with very minimal setup. So here's my OpenShift Origin UI. I'm going to log into it. And here, I've already created two namespaces, the www namespace, which is where I'm going to be deploying our Hello World application. And it's currently blank. And the GitLab infrastructure namespace, which is where I'll be deploying my CI runners. And it's where the jobs will be running. The namespaces are separated so that we can keep the permissions of the different pods running separate more easily. So I've already added the GitLab runner template as a template to OpenShift, so any namespace could add a runner to their namespace here. So I'll just load it up here. In order to run it, I just need a few input variables. So I need the address of the GitLab instance, which I can find from the Pipelines page here. And I need the registration token that tells the runner which project it's allowed to associate with and identifies it to GitLab. So here's the deployment running for the GitLab runner. So OpenShift has taken our deployment config, and it's creating and booting up a pod, which has our container within it. So if I go into the pod, we'll see that the container is running a Docker image, which is our GitLab runner application. And here in OpenShift, it's assigned a few other things, like it's given a cluster IP address. It's monitoring the state. And we've also have various mounts and sequence mounted automatically. So this runner has registered itself with GitLab. So if we refresh the page, we'll see it show up. So what this runner does is it's going to be polling GitLab for any CI CD jobs to run. And then what it'll do is it'll bring up new pods here in this namespace to run those jobs. So now that we have a runner, we can set up our CI CD jobs. There's a set up CI button in GitLab. We'll click on that, and we get this GitLab CI YAML template, which is where we define the various build stages and define the jobs that make up our continuous integration pipeline. I'm going to show off the bash example. You know, this isn't a bash application. This kind of shows the easiest example here. So you're able to define an image, a Docker image specifically, to use as the default for all the different tasks. So that's going to define all the dependencies to run your CI task, not necessarily your application, but the dependencies needed to run your jobs that will define below. We have a before script. The runs before each job and after script. We have a build stage in this example with a single job to build your application, and then we have a test stage that we've defined two test jobs in that will run in parallel, and then a deploy stage that just has a single job at the end. So the example template I'll show off is the Docker one to just show an example of how you can build a Docker image using CI. So the dependency here is Docker, the Docker image itself, which brings in the Docker binary. And this does a Docker build and pushes it, in this case, to GitLab's own built-in registry in this example. So I'm going to go back to the bash example and just jump ahead. And I actually had a little bit out here, but all I did was change the images to a Ruby image and the deploy image to the Docker image. So I'll create a new branch and commit this. And we're just going to use this as an example of a CI pipeline. So over here in OpenShift, the runner picked up the fact that there was a job and brought up a new pod that had the Ruby image. If we go back and we look at our pipelines in GitLab, we can see we have one running pipeline. The build is finished in two parallel test jobs that kicked off, which we can see in OpenShift. And then the final, with the Docker image, is the deploy job. This was just echoing things, so it wasn't really doing anything, but it shows the whole pipeline in a way that you can make use of the parallel jobs and easily set up CI. So next, we're going to set up the actual integration we have with Kubernetes and OpenShift. So we have a Kubernetes OpenShift integration listed here. So we're going to, say, define which namespace we want to deploy our application to. We're going to put in the API URL of the Kubernetes cluster or in OpenShift's case, the OpenShift cluster. And we need a service token to give GitLab access to make new pods and deploy. In this case, we're going to just grab it from the UI. This is just an example case. You would want to create your own service user and grab a service token that lasts a little longer. The UI one expires when I log out. So now that is set up. We should be able to go back to our project. And now there's a set up auto deploy button beside our set up CI button. So we can click on that. And we're back in our GitLab CI YAML. And this time, we have both an OpenShift and a Kubernetes example. So the OpenShift one includes a dependency on an image that has the OC binary. But we're not going to show this one today. That one makes use of the OpenShift build pipelines. But we're going to show just raw Kubernetes, which also works with the OpenShift image. So we have the image defined as the, in this case, Kubernetes deploy, which basically is just bringing in the cube CTL as our dependency. I'm going to change it here to OpenShift deploy, which also has the OC binary to this example image. And then these images are meant as examples. And we want you to be able to take them and change them and make them your own for your own needs for deployment. So I switched to my own, which had an updated binary for the version I'm running. The only other thing I have to change in this example is the cube domain to be a wildcard domain that I'm using. In this case, apps.yourdomain.work. So that's where I'm going to deploy my various versions of the application. I'll just create this as a merge request so I can show off the merge request UI. So we have a pending pipeline, and we have our changes that we can comment on. Over in OpenShift, our pipeline is kicked off, and we're running our build image, which we can see if we come in and look at the pipeline in GitLab. We have build running, and then in this case, we're going to be running review deployment next. So the review job is kicked off to make the deployment. If we jump in, we can see it's going to create the new application, deploy it, wait for it to roll out, and then expose the route in OpenShift to the router and load balancer. So to go back into our namespace where we're deploying these, we can see we now have a service that's config and our pods started. In GitLab, if we look at our merge request that we had set up, we see we now have our pipeline having passed. We have a third stage that didn't run, which is actually the cleanup stage which closes this deployment, and it will run when the branch is removed. Because in this case, what we've done is we've deployed a review application. So the URL has been somewhat generated. It's not your final URL. And it's specific to this branch, this merge request. This isn't our master branch. So we're able to now review this application using OpenShift and leave comments, stop the environment when we want to. And there's a couple of other things we can do. So we can actually go into the environment tab and we can access the terminal from GitLab as well. You can do this directly from OpenShift as well, but we can debug the running application from GitLab. So if I go in, what we're going to do is we're going to show an updated deployment. So we're going to go into the branch and edit the server.rb and change what it's going to output from Hello World to be just Hello Open. We'll deploy that to our same branch so it shows up in that merge request. We can see a new pipeline has started. Under our changes, we have two commits. We have our old BI YAML file that we added before and our new change. And in our pipeline, we're running another build of the Docker file and then another push to deploy the review app. The back in our infrastructure namespace, we have the build just finished. Next, it'll pick off the task that will be responsible for doing the deployment of the review app. And over in our actual namespace where we're deploying this application, we should see the old application start to shut down. The new one, the triggered for starting up. So there it goes. So now it has two pods that it's running, one with the old image, one with the new, and it's actively working on scaling down the old one. And OpenShift has already taken care of removing the old one from the load balancer. So even though the pod isn't shut down, it's not accessible at this point. So if I refresh the domain where we had our review app, we see it's been updated and our pipeline is finished. We can go ahead and merge this in and we'll see the review app close. So this will trigger the cleanup job, which will take care of shutting down this particular review app.