diff --git a/_modules.yml b/_modules.yml index 518f31c..950a2e0 100644 --- a/_modules.yml +++ b/_modules.yml @@ -34,4 +34,4 @@ modules: devops-custom-slave: name: Creating Custom Jenkins Slave Pods devops-env-info: - name: "Appnedix: Lab Environment" \ No newline at end of file + name: "Appendix: Lab Environment" diff --git a/devops-custom-slave.adoc b/devops-custom-slave.adoc index 291f74b..858938d 100644 --- a/devops-custom-slave.adoc +++ b/devops-custom-slave.adoc @@ -1,6 +1,6 @@ ## Creating Custom Jenkins Slave Pods -In this lab you will get familiar with creating custom slave container images for running distributed builds on OpenShfit. +In this lab you will get familiar with creating custom slave container images for running distributed builds on OpenShift. #### Background @@ -21,7 +21,7 @@ To facilitate the using of the Kubernetes plug-in, OpenShift Container Platform The base image for Jenkins slaves pulls in both required tools (headless Java, the Jenkins JNLP client) and generally useful ones (including git, tar, zip, nss among others) as well as running the slave agent. -The certified Jenkins image provided by OpenShift also provides auto-discovery and auto-configuration of slave images by searching for these in the existing image streams within the project that it is running in. The search specifically looks for image streams that have the label role=jenkins-slave. When it finds an image stream with this label, it generates the corresponding Kubernetes plug-in configuration so you can assign your Jenkins jobs to run in a pod running the container image provided by the image stream. +The certified Jenkins image provided by OpenShift also provides auto-discovery and auto-configuration of slave images by searching for these in the existing image streams within the project that it is running in. The search specifically looks for image streams that have the label `role=jenkins-slave`. When it finds an image stream with this label, it generates the corresponding Kubernetes plug-in configuration so you can assign your Jenkins jobs to run in a pod running the container image provided by the image stream. Note that this scanning is only performed once, when the Jenkins master is starting. @@ -70,7 +70,7 @@ $ oc label is/jenkins-slave-gradle-rhel7 role=jenkins-slave $ oc annotate is/jenkins-slave-gradle-rhel7 slave-label=gradle ---- -When Jenkins master starts for the first time, it automatically scans the image registry for slave images and configures them on Jenkins. Since you use an ephemeral Jenkins (without persistent storage) in this lab, restarting Jenkins causes a fresh Jenkins container to be deployed and to run the automatic configuration and discovery at startup to configure the Gradle slave image. When using a persistent Jenkins, all configurations would be kept and be available on the new container as well and therefore the automatic scan would not get triggered to avoid overwriting user configurations in Jenkins. In that case, you can configure the Gradle jenkins slave by adding a *Kubernetes Pod Template* in Jenkins configuration panel. +When Jenkins master starts for the first time, it automatically scans the image registry for slave images and configures them on Jenkins. Since you use an ephemeral Jenkins (without persistent storage) in this lab, restarting Jenkins causes a fresh Jenkins container to be deployed and to run the automatic configuration and discovery at startup to configure the Gradle slave image. When using a persistent Jenkins, all configurations would be kept and be available on the new container as well and therefore the automatic scan would not get triggered to avoid overwriting user configurations in Jenkins. In that case, you can configure the Gradle Jenkins slave by adding a *Kubernetes Pod Template* in Jenkins configuration panel. Delete the Jenkins pod so that OpenShift auto-healing capability starts a new Jenkins pod: @@ -144,4 +144,4 @@ In the _CI/CD Infra_ project, click on *Builds -> Pipelines* on the left sidebar image::devops-slave-job-log.png[Pipeline Log] -image::devops-slave-gradle-pipeline.png[OpenShift Pipeline with Gradle] \ No newline at end of file +image::devops-slave-gradle-pipeline.png[OpenShift Pipeline with Gradle] diff --git a/devops-deploy-jenkins.adoc b/devops-deploy-jenkins.adoc index 7ddcddb..a8bf095 100644 --- a/devops-deploy-jenkins.adoc +++ b/devops-deploy-jenkins.adoc @@ -51,4 +51,4 @@ $ oc policy add-role-to-user edit system:serviceaccount:ci-{{PROJECT_SUFFIX}}:je $ oc policy add-role-to-user edit system:serviceaccount:ci-{{PROJECT_SUFFIX}}:jenkins -n prod-{{PROJECT_SUFFIX}} ---- -Your Jenkins server is ready now. \ No newline at end of file +Your Jenkins server is ready now. diff --git a/devops-deployment-envs.adoc b/devops-deployment-envs.adoc index f063495..d8a379c 100644 --- a/devops-deployment-envs.adoc +++ b/devops-deployment-envs.adoc @@ -26,7 +26,7 @@ CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the ins image::devops-envs-create-dev.png[Create Dev Project, width=360] -The Dev deployment project for the Cart service is created now and is ready for the Cart service to be deployed. +The Dev deployment project for the Cart service is created now and is ready for the Cart service to be deployed. image::devops-envs-dev-project.png[Dev Project] @@ -61,7 +61,7 @@ CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the ins image::devops-envs-cart-newapp.png[Deploy Cart Service, width=800] -Click on *advanced options* to review advanced options for setting memory and cpu limits, environment variables, scaling and more when deploying an application. In this lab, similar to most development teams a Maven artifact repository (e.g. Sonatype Nexus and Artifactory) is used for managing Maven artifacts. Add the following environment variable under *Build Configuration* to specify the Maven repository manager URL to be used during the build phase: +Click on *advanced options* to review advanced options for setting memory and CPU limits, environment variables, scaling and more when deploying an application. In this lab, similar to most development teams a Maven artifact repository (e.g. Sonatype Nexus and Artifactory) is used for managing Maven artifacts. Add the following environment variable under *Build Configuration* to specify the Maven repository manager URL to be used during the build phase: * Name: `MAVEN_MIRROR_URL` * Value: `{{NEXUS_INTERNAL_URL}}/repository/maven-all-public` diff --git a/devops-env-info.adoc b/devops-env-info.adoc index ecf9996..39f03b1 100644 --- a/devops-env-info.adoc +++ b/devops-env-info.adoc @@ -1,13 +1,13 @@ ## Appendix: Environment Info -You find all urls, hostnames, usernames and passwords that are needed during the -labs in this page. Note that the urls are also embedded inside each lab instructions. +You find all URLs, hostnames, usernames and passwords that are needed during the +labs in this page. Note that the URLs are also embedded inside each lab instructions. **OPENSHIFT** Address: {{ OPENSHIFT_URL }} + -Username: `{{ OPENSHIFT_USER }}` + +Username: `{{ OPENSHIFT_USER }}` + Password: `{{ OPENSHIFT_PASSWORD }}` + IMPORTANT: Replace `{{ PROJECT_SUFFIX }}` with the id given to you by the instructor @@ -16,8 +16,8 @@ IMPORTANT: Replace `{{ PROJECT_SUFFIX }}` with the id given to you by the instru Web: http://{{ GIT_SERVER_URL }} -Username: `{{ GIT_USER }}` + -Password: `{{ GIT_PASSWORD }}` + +Username: `{{ GIT_USER }}` + +Password: `{{ GIT_PASSWORD }}` + **NEXUS MAVEN REPOSITORY** @@ -31,4 +31,4 @@ Web: {{ ECLIPSE_CHE_URL }} **OPENSHIFT DOCS** -Web: {{ OPENSHIFT_DOCS_BASE }} \ No newline at end of file +Web: {{ OPENSHIFT_DOCS_BASE }} diff --git a/devops-explore-openshift.adoc b/devops-explore-openshift.adoc index 51e51b0..32f6455 100644 --- a/devops-explore-openshift.adoc +++ b/devops-explore-openshift.adoc @@ -31,7 +31,7 @@ In order to login, you can use the `oc` command and then specify the server that $ oc login {{OPENSHIFT_URL}} ---- -Enter *Y* to use a potentially insecure connection. The reason you received this message is because we are using a self-signed certificate for this workshop, but we did not provide you with the CA certificate that was generated by OpenShift. In a real-world scenario, either OpenShift certificate would be signed by a standard CA (eg: Thawte, Verisign, StartSSL, etc.) or signed by a corporate-standard CA that you already have installed on your system. +Enter *Y* to use a potentially insecure connection. The reason you received this message is because we are using a self-signed certificate for this workshop, but we did not provide you with the CA certificate that was generated by OpenShift. In a real-world scenario, either OpenShift certificate would be signed by a standard CA (e.g. Thawte, Verisign, StartSSL, etc.) or signed by a corporate-standard CA that you already have installed on your system. Once you issue the `oc login` command, you will be prompted for the username and password combination for your user account. Replace XX with the username given to you by the instructor: diff --git a/devops-pipeline-scm.adoc b/devops-pipeline-scm.adoc index 6d1e72b..aeb319c 100644 --- a/devops-pipeline-scm.adoc +++ b/devops-pipeline-scm.adoc @@ -1,6 +1,6 @@ ## Pipeline Definition as Code -In this lab you will get familiar with definine a pipeline as code and manage its versions via a version control system. +In this lab you will get familiar with defining a pipeline as code and manage its versions via a version control system. #### Background Although it is convenient to embed a Jenkinsfile into an OpenShift Pipeline and edit it directly in the OpenShift Web Console, there is no history of changes made to the pipeline through the UI. Furthermore, switching back and forth between multiple versions of the pipeline becomes challenging with an embedded Jenkinsfile. Therefore, it is generally considered a best practice to create a Jenkinsfile and check it into the source control repository in order to manage its versions and history of changes applied to it. @@ -21,9 +21,9 @@ CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the ins [TIP] ==== -If you are using Eclipse Che, click on **Import Project...** and then enter the Git url -as the `URL` and click on **Import**. Make sure to replace your username and password in the -Git url: +If you are using Eclipse Che, click on **Import Project...** and then enter the Git URL +as the `URL` and click on **Import**. Make sure to replace your username and password in the +Git URL: http://{{GIT_USER}}:{{GIT_PASSWORD}}@{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git @@ -78,7 +78,7 @@ pipeline { dc = openshift.selector("dc", "cart") dc.rollout().latest() timeout(10) { - dc.rollout().status() + dc.rollout().status() } } } diff --git a/devops-promotion.adoc b/devops-promotion.adoc index 4137c36..9038eb3 100644 --- a/devops-promotion.adoc +++ b/devops-promotion.adoc @@ -66,7 +66,7 @@ Tag cart:prod set to dev-{{PROJECT_SUFFIX}}/cart@sha256:ee898ec51ab7bbce53ff4142 The above command promotes the `cart:latest` container image which is the latest image build of the Cart service in the _Dev_ environment, to the _Prod_ environment and names it `cart:prod`. As soon as the cart image is promoted to the _Prod_ environment, the Cart container gets automatically deployed. As new Cart service container images are built, the _Prod_ environment remains intact until you promote the new image builds to the _Prod_ environment after sufficient testing. -When the Cart service is ready, click on the Web UI route url and verify that CoolStore online shop is working correctly. If the product list is not displayed correctly, refresh the page a few times. +When the Cart service is ready, click on the Web UI route URL and verify that CoolStore online shop is working correctly. If the product list is not displayed correctly, refresh the page a few times. image::devops-intro-coolstore.png[CoolStore Webshop] @@ -85,7 +85,7 @@ CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the ins stage('Promote to Prod') { steps { timeout(time:15, unit:'MINUTES') { - input message: "Approve Promotion to Prod?", ok: "Promote" + input message: "Approve Promotion to Prod?", ok: "Promote" } script { openshift.withCluster() { diff --git a/devops-simple-pipeline.adoc b/devops-simple-pipeline.adoc index cc0f5ab..2640935 100644 --- a/devops-simple-pipeline.adoc +++ b/devops-simple-pipeline.adoc @@ -39,7 +39,7 @@ pipeline { Running builds, especially large builds, frequently requires a lot of resources and quite soon surpass the available resources on the Jenkins server. Jenkins supports a master-slave architecture in order to be able to scale and run many builds and pipelines simultaneously. A slave is a Jenkins worker instance that is configured to offload build jobs (e.g. pipeline execution) from the master. In a master-slave setup, a number of slave instances are configured for the Jenkins master and the master distributes running builds between the slaves instances based on the build tools and others configurations available on each slave instance. -The Jenkins certified image on OpenShift is pre-configured to {{OPENSHIFT_DOCS_BASE}}/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs[dynamically create Jenkins slave containers] when running OpenShift pipelines. The `agent { labe 'maven' }` statement instructs Jenkins to dynamically deploy a Jenkins slave container which is configured for running Apache Maven builds and execute the pipeline on that container. Dynamic provisioning of the Jenkins slave containers allows running many builds in parallel on OpenShift without overloading the Jenkins master. +The Jenkins certified image on OpenShift is pre-configured to {{OPENSHIFT_DOCS_BASE}}/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs[dynamically create Jenkins slave containers] when running OpenShift pipelines. The `agent { label 'maven' }` statement instructs Jenkins to dynamically deploy a Jenkins slave container which is configured for running Apache Maven builds and execute the pipeline on that container. Dynamic provisioning of the Jenkins slave containers allows running many builds in parallel on OpenShift without overloading the Jenkins master. Although one can use OpenShift CLI in the pipeline definition to interact with OpenShift, OpenShift Pipelines also provide a set of easy to use building blocks via the https://github.com/openshift/jenkins-client-plugin[OpenShift DSL Jenkins Plugin] which simplify performing actions against OpenShift deployments. You will use this plugin in the next section. @@ -83,7 +83,7 @@ spec: dc = openshift.selector("dc", "cart") dc.rollout().latest() timeout(10) { - dc.rollout().status("-w") + dc.rollout().status("-w") } } } @@ -109,7 +109,7 @@ Click on *Overview* in the OpenShift Web Console, and see that a Jenkins server image::devops-simple-pipeline-jenkins-autoprovision.png[Jenkins Auto-provisioning] -When you deployed Cart service, the deployment is configured to automatically initiate a new deployment everytime a new version of the Cart container image is available. When using pipelines, you might want the pipeline to control when a deployment should happen independent of whether an updated Cart container image is available. In order to do that, you can change the automatic deployment to manual on the Cart deploymentconfig using OpenShift CLI: +When you deployed Cart service, the deployment is configured to automatically initiate a new deployment every time a new version of the Cart container image is available. When using pipelines, you might want the pipeline to control when a deployment should happen independent of whether an updated Cart container image is available. In order to do that, you can change the automatic deployment to manual on the Cart deploymentconfig using OpenShift CLI: CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. diff --git a/devops-webhook.adoc b/devops-webhook.adoc index d7b090c..391a853 100644 --- a/devops-webhook.adoc +++ b/devops-webhook.adoc @@ -1,6 +1,6 @@ ## Running the CI/CD Pipeline on Every Change -In this lab you will learn about webhooks and how to automatically run the changes through the pipeline everytime there is a change in the application source repository. +In this lab you will learn about Webhooks and how to automatically run the changes through the pipeline every time there is a change in the application source repository. #### Background diff --git a/devops-zerodowntime-automated.adoc b/devops-zerodowntime-automated.adoc index a099c81..f4b0d21 100644 --- a/devops-zerodowntime-automated.adoc +++ b/devops-zerodowntime-automated.adoc @@ -52,7 +52,7 @@ pipeline { dc = openshift.selector("dc", "cart") dc.rollout().latest() timeout(10) { - dc.rollout().status() + dc.rollout().status() } } } @@ -100,7 +100,7 @@ pipeline { stage('Approve Go Live') { steps { timeout(time:15, unit:'MINUTES') { - input message: "Approve Promotion to Prod?", ok: "Promote" + input message: "Approve Promotion to Prod?", ok: "Promote" } script { openshift.withCluster() { @@ -175,4 +175,4 @@ Notice that the shipping cost is zero since the total order is above the 20$ min Now that the new minimum order rule is verified in the new version of Cart service in the Prod environment, you can approve the *Go Live*. Go back to *Builds -> Pipelines* and click on *Input Required* and then *Promote* to approve the Go Live. Add a Pebble Smart Watch to your shopping cart again and verify that shipping is now free in the live version. -image::devops-zerodowntime-bg-approved.png[Deployment Pipeline Complete] \ No newline at end of file +image::devops-zerodowntime-bg-approved.png[Deployment Pipeline Complete] diff --git a/devops-zerodowntime-manual.adoc b/devops-zerodowntime-manual.adoc index 885f3ef..27b522f 100644 --- a/devops-zerodowntime-manual.adoc +++ b/devops-zerodowntime-manual.adoc @@ -4,15 +4,15 @@ In this lab you will get familiar with production deployments without requiring #### Background -Although you have automated the build and deployment of the Cart service all the way from development to production, every time the pipeline performs the deployment in production the service is unavailable for the period it takes for the Cart container to start up. This might be acceptable for certain services however an unavailable service for an online shop equalis lost orders and revenue specially during shopping seasons like Christmas. +Although you have automated the build and deployment of the Cart service all the way from development to production, every time the pipeline performs the deployment in production the service is unavailable for the period it takes for the Cart container to start up. This might be acceptable for certain services however an unavailable service for an online shop equals lost orders and revenue specially during shopping seasons like Christmas. Zero downtime deployments refers to a number of deployment pattern that allow deploying to production environment during work hours without a need for service windows and without causing any disruption for the live services. Blue-Green and Canary Release are two popular patterns that are often used to achieve zero downtime deployments. -Canary Release refers to deploying a new version of your app into production parallel to the live version and redirectly only a fraction of production traffic to the new version. After verifying that the canary deployment works correctly, incremental more production traffic is switched to the canary version until it serves 100% of the production traffic. Canary Release allows you to test the application directly in the production with subset of users so that in case of failure, only a small user set will be affected. +Canary Release refers to deploying a new version of your app into production parallel to the live version and redirecting only a fraction of production traffic to the new version. After verifying that the canary deployment works correctly, incremental more production traffic is switched to the canary version until it serves 100% of the production traffic. Canary Release allows you to test the application directly in the production with subset of users so that in case of failure, only a small user set will be affected. In Blue-Green deployment approach you also have two parallel production environments but at any point in time only one of them is active and receives the production traffic, for example the blue one. When you deploy the new version of the application in production, you deploy into the inactive environment, green in this example, and after ensuring that the new version works correctly in production you switch the router so that all incoming production traffic goes to the green environment, making the blue one idle. -Blue-green deployment also enables you to be able to quickly rollback to the previous version. if anything goes wrong with the new version after the switch, you can switch back the router the blue version. You still need to manage transactions and database changes when deploying new versions of your application however there are other patterns to specifically deal with those issues separately for example depending on your environment and application design, you might be able to feed transactions to both environments so that the blue environment acts as a backup or run the application in read-only mode before doing a switch. +Blue-green deployment also enables you to be able to quickly rollback to the previous version. If anything goes wrong with the new version after the switch, you can switch back the router the blue version. You still need to manage transactions and database changes when deploying new versions of your application however there are other patterns to specifically deal with those issues separately for example depending on your environment and application design, you might be able to feed transactions to both environments so that the blue environment acts as a backup or run the application in read-only mode before doing a switch. image::devops-zerodowntime-bluegreen-diagram.png[Blue-Green Deployment] @@ -94,12 +94,8 @@ $ oc create -f ~/cart-blue.yaml $ oc create -f ~/cart-green.yaml ---- -Now that the Cart Blue and Cart Green deployment and services are defined, you can deploy those containers in the the Prod environment. Click on *Applications -> Deployments* and then on *cart-blue*. Deploy the Cart Blue service by clicking on the *Deploy* button. Go back to the list of deployments and click on *cart-green*, and then *Deploy* button to also deploy the Cart Green service. - The Cart Blue and Green containers will be deployed alongside the previous Cart container. -image::devops-zerodowntime-cart-bluegreen.png[Cart Blue Service and Cart Green Service] - You created the Cart blue and green services but the route is still pointing to the old container instead of either blue or the green container. Click on *Applications -> Routes* on the left sidebar menu and then click on *cart* route. Notice that it is currently pointing at the cart service. Click on *Actions* → *Edit* from the top-right menu. You can create a blue/green route by clicking on *Split traffic across multiple services* and adding `cart-blue` and `cart-green` services with 100 and 0 weight respectively to send all traffic to the cart-blue service and then click on *Save*. You can {{OPENSHIFT_DOCS_BASE}}/dev_guide/routes.html#routes-load-balancing-for-AB-testing[split the traffic] coming to a route across multiple backend services via weighting however in this lab you only need the `cart-blue` and `cart-green` services. @@ -132,7 +128,7 @@ $ oc get routes Verify the routes are working using the `curl` command: -CAUTION: Replace the urls with routes in your project +CAUTION: Replace the URLs with routes in your project [source,shell] ---- @@ -164,9 +160,9 @@ public void applyShippingPromotions(ShoppingCart shoppingCart) { Notice that the minimum order for free shipping is currently 75$. In order to match a competitor website, you want to change the promotion rules and reduce the minimum to 40$. Click on the pencil icon to open `PromoService.java` in the web-based editor. -image::devops-zerodowntime-gogs-editor.png[Gogs Web Editort] +image::devops-zerodowntime-gogs-editor.png[Gogs Web Editor] -Change the minium order to 40$. The `PromoService.java` should look like this after the edit: +Change the minimum order to 40$. The `PromoService.java` should look like this after the edit: [source,java] ---- @@ -199,7 +195,7 @@ $ curl -X POST http://{{CART_GREEN_ROUTE}}/api/cart/FOO/444434/2 {"cartItemTotal":48.0,"cartItemPromoSavings":0.0,"shippingTotal":0.0,"shippingPromoSavings":-4.99,"cartTotal":52.99,"shoppingCartItemList":[{"price":24.0,"quantity":2,"promoSavings":0.0,"product":{"itemId":"444434","name":"Pebble Smart Watch","desc":"Smart glasses and smart watches are perhaps two of the most exciting developments in recent years. ","price":24.0}}]} ---- -Notice that the shipping cost is zero since the total order is above the 40$ minimum order. However the change is still not live and invoking the production endpoints for the Cart service should still have the 75$ minimum order. Click on the Web UI route url and add 2 Pebble Smart Watches to your shopping cart. As expected, the shipping cost is not zero. +Notice that the shipping cost is zero since the total order is above the 40$ minimum order. However the change is still not live and invoking the production endpoints for the Cart service should still have the 75$ minimum order. Click on the Web UI route URL and add 2 Pebble Smart Watches to your shopping cart. As expected, the shipping cost is not zero. image::devops-zerodowntime-shipping-costs.png[CoolStore Shopping Cart] diff --git a/images/devops-zerodowntime-cart-bluegreen.png b/images/devops-zerodowntime-cart-bluegreen.png deleted file mode 100644 index 749fef2..0000000 Binary files a/images/devops-zerodowntime-cart-bluegreen.png and /dev/null differ