{"id":92048,"date":"2020-08-22T07:42:57","date_gmt":"2020-08-22T05:42:57","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines"},"modified":"2020-08-22T07:42:57","modified_gmt":"2020-08-22T05:42:57","slug":"sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines","title":{"rendered":"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Hello everyone in this blog! Here is the third post in our series showing how to deploy modern web applications on Red Hat OpenShift.<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/9c3337b13a3f045d36343308ce6154cc.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn the previous two posts, we explained how to deploy modern web applications in just a few steps and how to use the new S2I image along with a ready-made HTTP server image, like NGINX, with the help of chained builds for production deployment.<\/p>\n<p>Today, we will show how to run a development server for your application on the OpenShift platform and sync it with your local file system, as well as discuss what OpenShift Pipelines are and how they can serve as an alternative to chained builds.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>OpenShift as a Development Environment<\/h3>\n<p><\/p>\n<h4>Development Workflow<\/h4>\n<p>\nAs mentioned in the <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/511954\/\">first post<\/a><\/noindex>, a typical development process for modern web applications involves a 'development server' that monitors changes in local files. When changes occur, it triggers a build of the application, and then the application is updated in the browser.<\/p>\n<p>In most modern frameworks, such a 'development server' is built into the corresponding command line tools.<\/p>\n<h4>Local Example<\/h4>\n<p>\nFirst, let's see how this works with local application launches. We'll take the application <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\">React<\/a><\/noindex> from previous articles, although the same workflow concepts apply across all other modern frameworks.<br \/>\nSo, to start the 'development server' in our React example, we enter the following command:<\/p>\n<pre><code class=\"plaintext\">$ npm run start\n<\/code><\/pre>\n<p>\nThen, we will see something like the following in the terminal window:<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/06f84ffb4c9a6a5868b8b47b8ad1d9ec.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>And our application will open in the default browser:<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/72341bb0796352e7343bf31ceb8233cd.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Now, if we make changes to the file, the application should update in the browser.<\/p>\n<p>OK, development in local mode is clear, but how do we achieve the same on OpenShift?<\/p>\n<h4>Development Server on OpenShift<\/h4>\n<p>\nIf you remember, in the <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/513948\/\">the previous post<\/a><\/noindex>, we discussed the so-called run phase of the S2I image and saw that by default, our web application is served by the serve module.<\/p>\n<p>However, if we take a closer look at the <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/nodeshift\/ubi8-s2i-web-app\/blob\/master\/s2i\/run#L10\">run script<\/a><\/noindex> from that example, there is an environment variable $NPM_RUN, which allows you to execute your command.<\/p>\n<p>For example, you can use the nodeshift module to deploy our application:<\/p>\n<pre><code class=\"plaintext\">$ npx nodeshift --deploy.env NPM_RUN=\"yarn start\" --dockerImage=nodeshift\/ubi8-s2i-web-app\n<\/code><\/pre>\n<p>\n<i>Note: The example above is presented in a condensed form to illustrate the general idea.<\/i><\/p>\n<p>Here we added an environment variable NPM_RUN to our deployment, which tells the execution stage to run the yarn start command that starts the React development server inside our OpenShift pod.<\/p>\n<p>If you check the log of the running pod, it will look something like this:<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/5b090223e08e32a3356608881068ce1a.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Of course, this will all be meaningless until we can synchronize local code with the code that is also monitored for changes but lives on a remote server.<\/p>\n<h4>Synchronization of remote and local code<\/h4>\n<p>\nFortunately, nodeshift makes synchronization easy, and to track changes, you can use the watch command.<\/p>\n<p>So after we executed the command to deploy the development server for our application, we can confidently use the following command:<\/p>\n<pre><code class=\"plaintext\">$ npx nodeshift watch\n<\/code><\/pre>\n<p>\nAs a result, a connection will be made to the running pod that we created earlier, synchronization of our local files with the remote cluster will be activated, and the files on our local system will start being monitored for changes.<\/p>\n<p>Therefore, if we now update the file src\/App.js, the system will respond to these changes, copy them to the remote cluster, and start the development server, which will then update our application in the browser.<\/p>\n<p>To complete the picture, let's show what these commands look like in full:<\/p>\n<pre><code class=\"plaintext\">$ npx nodeshift --strictSSL=false --dockerImage=nodeshift\/ubi8-s2i-web-app --build.env YARN_ENABLED=true --expose --deploy.env NPM_RUN=\"yarn start\" --deploy.port 3000\n\n$ npx nodeshift watch --strictSSL=false\n<\/code><\/pre>\n<p>\nThe watch command is an abstraction over the oc rsync command; you can learn more about how it works. <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.okd.io\/latest\/dev_guide\/copy_files_to_container.html\">here<\/a><\/noindex>.<\/p>\n<p>This was an example for React, but the same method can be used with other frameworks; just configure the environment variable NPM_RUN accordingly.<br \/>\n\u2003<\/p>\n<h3>OpenShift Pipelines<\/h3>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/33b932d3591b22dd00d82509b352d489.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Next, we will discuss a tool called OpenShift Pipelines and how it can be used as an alternative to chained builds.<\/p>\n<h4>What are OpenShift Pipelines?<\/h4>\n<p>\nOpenShift Pipelines is a cloud-oriented CI\/CD system for continuous integration and delivery, designed to organize pipelines using Tekton. Tekton is a flexible Kubernetes-native CI\/CD framework with open source, allowing for deployment automation across various platforms (Kubernetes, serverless, virtual machines, etc.) by abstracting from the underlying layer.<\/p>\n<p>Certain knowledge of Pipelines is required to understand this article, so we strongly recommend starting with the <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/openshift\/pipelines-tutorial\">official documentation.<\/a><\/noindex>.<\/p>\n<h4>Setting Up the Working Environment<\/h4>\n<p>\nTo experiment with the examples in this article, you first need to prepare the working environment:<\/p>\n<ol>\n<li>Install and set up an OpenShift 4 cluster. We use CodeReady Containers (CRC) in our examples, and installation instructions can be found <noindex><a rel=\"nofollow\" href=\"https:\/\/cloud.redhat.com\/openshift\/install\/crc\/installer-provisioned\">here<\/a><\/noindex>.<\/li>\n<li>Once the cluster is ready, you need to install the Pipeline Operator. Don't worry, it's easy, the installation instructions <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/openshift\/pipelines-tutorial\/blob\/master\/install-operator.md\">here<\/a><\/noindex>.<\/li>\n<li>Download <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tektoncd\/cli#installing-tkn\">Tekton CLI<\/a><\/noindex> (tkn) <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/tektoncd\/cli#installing-tkn\">here<\/a><\/noindex>.<\/li>\n<li>Run the create-react-app command line tool to generate an application that will later be deployed (this is a simple application <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/nodeshift-starters\/react-pipeline-example\">React<\/a><\/noindex>).<\/li>\n<li>(Optional) Clone the repository to run the application locally using the command npm install and then npm start.<\/li>\n<\/ol>\n<p>\nIn the application repository, there will also be a k8s folder containing the Kubernetes\/OpenShift YAML files used for deploying the application. There, you will find Tasks, ClusterTasks, Resources, and Pipelines that we will create in this <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/nodeshift\/webapp-pipeline-tutorial\">the repository<\/a><\/noindex>.<\/p>\n<h4>Let's get started<\/h4>\n<p>\nFirst, we need to create a new project in the OpenShift cluster for our example. We will call this project webapp-pipeline and create it with the following command:<\/p>\n<pre><code class=\"plaintext\">$ oc new-project webapp-pipeline\n<\/code><\/pre>\n<p>\nThis project name will appear in the code, so if you decide to name it something else, be sure to adjust the code in the examples accordingly. Starting from this point, we will go bottom-up: first creating all the components of the pipeline and only then the pipeline itself.<\/p>\n<p>So, first things first\u2026<\/p>\n<h4>Tasks<\/h4>\n<p>\nLet's create a couple of tasks that will help deploy the application within our pipeline. The first task \u2013 apply_manifests_task \u2013 is responsible for applying the YAML specifications of the Kubernetes resources (service, deployment, and route) located in the k8s folder of our application. The second task \u2013 update_deployment_task \u2013 is responsible for updating the already deployed image to the one created by our pipeline.<\/p>\n<p>Don't worry if it's not very clear yet. In fact, these tasks are somewhat like utilities, and we'll go into more detail a bit later. For now, let's just create them:<\/p>\n<pre><code class=\"plaintext\">$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/tasks\/update_deployment_task.yaml\n$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/tasks\/apply_manifests_task.yaml\n<\/code><\/pre>\n<p>\nThen we will use the tkn CLI command to check that the tasks have been created:<\/p>\n<pre><code class=\"plaintext\">$ tkn task ls\n\nNAME                AGE\napply-manifests     1 minute ago\nupdate-deployment   1 minute ago\n<\/code><\/pre>\n<p>\n<i>Note: these are local tasks for your current project.<\/i><\/p>\n<h4>Cluster tasks<\/h4>\n<p>\nCluster tasks are essentially the same as regular tasks. They are a reusable collection of steps that are combined in some way when a specific task is run. The difference is that a cluster task is available throughout the cluster. To see the list of cluster tasks that are automatically created when adding a Pipeline Operator, we will again use the tkn CLI command:<\/p>\n<pre><code class=\"plaintext\">$ tkn clustertask ls\n\nNAME                       AGE\nbuildah                    1 day ago\nbuildah-v0-10-0            1 day ago\njib-maven                  1 day ago\nkn                         1 day ago\nmaven                      1 day ago\nopenshift-client           1 day ago\nopenshift-client-v0-10-0   1 day ago\ns2i                        1 day ago\ns2i-go                     1 day ago\ns2i-go-v0-10-0             1 day ago\ns2i-java-11                1 day ago\ns2i-java-11-v0-10-0        1 day ago\ns2i-java-8                 1 day ago\ns2i-java-8-v0-10-0         1 day ago\ns2i-nodejs                 1 day ago\ns2i-nodejs-v0-10-0         1 day ago\ns2i-perl                   1 day ago\ns2i-perl-v0-10-0           1 day ago\ns2i-php                    1 day ago\ns2i-php-v0-10-0            1 day ago\ns2i-python-3               1 day ago\ns2i-python-3-v0-10-0       1 day ago\ns2i-ruby                   1 day ago\ns2i-ruby-v0-10-0           1 day ago\ns2i-v0-10-0                1 day ago\n<\/code><\/pre>\n<p>\nNow let's create two cluster tasks. The first will generate an S2I image and send it to the OpenShift internal registry; the second will build our image based on NGINX, using the application we have built as the content.<\/p>\n<h4>Creating and sending the image<\/h4>\n<p>\nWhen creating the first task, we will repeat what we have already done in the previous article about related builds. Let's recall that we used the S2I image (ubi8-s2i-web-app) to 'build' our application, resulting in an image stored in the internal OpenShift registry. Now we will use this S2I web application image to create a DockerFile for our application, and then we will use Buildah to perform the actual build and push the resulting image to the internal OpenShift registry, as this is exactly what OpenShift does when you deploy your applications using NodeShift.<\/p>\n<p>Wondering where we learned all this? From <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/openshift\/pipelines-catalog\/blob\/master\/s2i-nodejs\/s2i-nodejs-task.yaml\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 official Node.js<\/a><\/noindex>, we simply copied it and adjusted it for ourselves.<\/p>\n<p>Now, let's create the cluster task s2i-web-app:<\/p>\n<pre><code class=\"plaintext\">$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/clustertasks\/s2i-web-app-task.yaml\n<\/code><\/pre>\n<p>\nWe won't go into detail here, but we will focus on the OUTPUT_DIR parameter:<\/p>\n<pre><code class=\"plaintext\">params:\n      - name: OUTPUT_DIR\n        description: The location of the build output directory\n        default: build\n<\/code><\/pre>\n<p>\nBy default, this parameter is set to build, which is where React places the compiled content. Other frameworks use different paths, for example in Ember it's dist. The output of our first cluster task will be an image containing the HTML, JavaScript, and CSS that we compiled.<\/p>\n<h4>Building an image based on NGINX<\/h4>\n<p>\nAs for our second cluster task, it should build an image based on NGINX using the content of the application we have already compiled. Essentially, this is the part of the previous section where we discussed related builds.<\/p>\n<p>To do this, we will create a cluster task webapp-build-runtime just like we did above:<\/p>\n<pre><code class=\"plaintext\">$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/clustertasks\/webapp-build-runtime-task.yaml\n<\/code><\/pre>\n<p>\nIf you look at the code of these cluster tasks, you will see that the Git repository we are working with or the names of the images we are creating are not specified. We only define what exactly we are passing to Git or some image where the final image should be output. This is why these cluster tasks can be reused when working with other applications.<\/p>\n<p>And here we gracefully transition to the next point...<\/p>\n<h4>Resources<\/h4>\n<p>\nSo, as we just mentioned, since clustered tasks should be as general as possible, we need to create resources that will be used as input (Git repository) and output (final images). The first resource we need is Git, where our application is located, something like this:<\/p>\n<pre><code class=\"plaintext\"># This resource is the location of the git repo with the web application source\napiVersion: tekton.dev\/v1alpha1\nkind: PipelineResource\nmetadata:\n  name: web-application-repo\nspec:\n  type: git\n  params:\n    - name: url\n      value: https:\/\/github.com\/nodeshift-starters\/react-pipeline-example\n    - name: revision\n      value: master\n<\/code><\/pre>\n<p>\nHere, PipelineResource has the type git. The key url in the params section specifies the specific repository and sets the master branch (this is optional, but we include it for completeness).<\/p>\n<p>Now we need to create a resource for the image where the results of the s2i-web-app task will be saved, which is done like this:<\/p>\n<pre><code class=\"plaintext\"># This resource is the result of running &quot;npm run build&quot;,  the resulting built files will be located in \/opt\/app-root\/output\napiVersion: tekton.dev\/v1alpha1\nkind: PipelineResource\nmetadata:\n  name: built-web-application-image\nspec:\n  type: image\n  params:\n    - name: url\n      value: image-registry.openshift-image-registry.svc:5000\/webapp-pipeline\/built-web-application:latest\n<\/code><\/pre>\n<p>\nHere, PipelineResource has the type image, and the value of the url parameter points to the internal OpenShift Image Registry, specifically the one located in the webapp-pipeline namespace. Don't forget to change this parameter if you are using another namespace.<\/p>\n<p>And finally, the last resource we will need will also be of type image, and it will be the final NGINX image that will be used during deployment.<\/p>\n<pre><code class=\"plaintext\"># This resource is the image that will be just the static html, css, js files being run with nginx\napiVersion: tekton.dev\/v1alpha1\nkind: PipelineResource\nmetadata:\n  name: runtime-web-application-image\nspec:\n  type: image\n  params:\n    - name: url\n      value: image-registry.openshift-image-registry.svc:5000\/webapp-pipeline\/runtime-web-application:latest\n<\/code><\/pre>\n<p>\nAnd again, note that this resource saves the image in the internal OpenShift registry in the webapp-pipeline namespace.<\/p>\n<p>To create all these resources at once, we will use the create command:<\/p>\n<pre><code class=\"plaintext\">$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/resources\/resource.yaml\n<\/code><\/pre>\n<p>\nYou can check that the resources have been created like this:<\/p>\n<pre><code class=\"plaintext\">$ tkn resource ls\n<\/code><\/pre>\n<p><\/p>\n<h4>Pipeline<\/h4>\n<p>\nNow that we have all the necessary components, let's assemble them into a pipeline by running the following command:<\/p>\n<pre><code class=\"plaintext\">$ oc create -f https:\/\/raw.githubusercontent.com\/nodeshift\/webapp-pipeline-tutorial\/master\/pipelines\/build-and-deploy-react.yaml\n<\/code><\/pre>\n<p>\nBut before we run this command, let's break down these components. The first is the name:<\/p>\n<pre><code class=\"plaintext\">apiVersion: tekton.dev\/v1alpha1\nkind: Pipeline\nmetadata:\n  name: build-and-deploy-react\n<\/code><\/pre>\n<p>\nThen in the spec section, we see the indication of the resources we created earlier:<\/p>\n<pre><code class=\"plaintext\">spec:\n  resources:\n    - name: web-application-repo\n      type: git\n    - name: built-web-application-image\n      type: image\n    - name: runtime-web-application-image\n      type: image\n<\/code><\/pre>\n<p>\nNext, we create the tasks that our pipeline should perform. First, it should execute the task we already created, s2i-web-app:<\/p>\n<pre><code class=\"plaintext\">tasks:\n    - name: build-web-application\n      taskRef:\n        name: s2i-web-app\n        kind: ClusterTask\n<\/code><\/pre>\n<p>\nThis task takes input (git resource) and output (built-web-application-image resource) parameters. We also pass it a special parameter so that it does not verify TLS, since we are using self-signed certificates:<\/p>\n<pre><code class=\"plaintext\">resources:\n        inputs:\n          - name: source\n            resource: web-application-repo\n        outputs:\n          - name: image\n            resource: built-web-application-image\n      params:\n        - name: TLSVERIFY\n          value: \"false\"\n<\/code><\/pre>\n<p>\nThe next task is almost the same, but here we call the cluster task webapp-build-runtime that we have already created.<\/p>\n<pre><code class=\"plaintext\">name: build-runtime-image\n    taskRef:\n      name: webapp-build-runtime\n      kind: ClusterTask\n<\/code><\/pre>\n<p>\nAs with the previous task, we pass the resource, but now it is built-web-application-image (the output of our previous task). And as output, we again specify the image. Since this task needs to run after the previous one, we add the runAfter field:<\/p>\n<pre><code class=\"plaintext\">resources:\n        inputs:\n          - name: image\n            resource: built-web-application-image\n        outputs:\n          - name: image\n            resource: runtime-web-application-image\n        params:\n        - name: TLSVERIFY\n          value: \"false\"\n      runAfter:\n        - build-web-application\n<\/code><\/pre>\n<p>\nThe next two tasks are responsible for applying the YAML files for the service, route, and deployment, which reside in the k8s directory of our web application, as well as updating this deployment when new images are created. We defined these two cluster tasks back at the beginning of the article.<\/p>\n<h4>Start the pipeline<\/h4>\n<p>\nSo, all parts of our pipeline are created, and we will start it with the following command:<\/p>\n<pre><code class=\"plaintext\">$ tkn pipeline start build-and-deploy-react\n<\/code><\/pre>\n<p>\nAt this stage, the command line is used interactively, and you need to select the appropriate resources in response to each prompt: for the git resource choose web-application-repo, then for the first image resource \u2013 built-web-application-image, and finally, for the second image resource \u2013 runtime-web-application-image:<\/p>\n<pre><code class=\"plaintext\">? Choose the git resource to use for web-application-repo: web-application-repo (https:\/\/github.com\/nodeshift-starters\/react-pipeline-example)\n? Choose the image resource to use for built-web-application-image: built-web-application-image (image-registry.openshift-image-registry.svc:5000\/webapp-pipeline\/built-web-\napplication:latest)\n? Choose the image resource to use for runtime-web-application-image: runtime-web-application-image (image-registry.openshift-image-registry.svc:5000\/webapp-pipeline\/runtim\ne-web-application:latest)\nPipelinerun started: build-and-deploy-react-run-4xwsr\n<\/code><\/pre>\n<p>\nNow let's check the status of the pipeline using the following command:<\/p>\n<pre><code class=\"plaintext\">$ tkn pipeline logs -f\n<\/code><\/pre>\n<p>\nOnce the pipeline starts and the application is deployed, we can retrieve the published route with the following command:<\/p>\n<pre><code class=\"plaintext\">$ oc get route react-pipeline-example --template='http:\/\/{{.spec.host}}'\n<\/code><\/pre>\n<p>\nFor better visibility, we can view our pipeline in Developer mode in the web console under <b>Pipelines<\/b>, as shown in Fig. 1.<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/ede9b076414e389c2cd212adeda08956.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><i>Fig. 1. Overview of running pipelines.<\/i><\/p>\n<p>Clicking on the running pipeline displays additional details, as shown in Fig. 2.<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/64581b1f6d8ff91aedd963019ef29be5.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><i>Fig. 2. Additional details about the pipeline.<\/i><\/p>\n<p>After viewing the additional details, we can see the running applications in the <b>Topology<\/b>, as shown in Fig. 3.<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/d23f723e14514ff60ecfddd8eb9bf752.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><i>Fig. 3. Running pod.<\/i><\/p>\n<p>Clicking on the circle in the upper right corner of the icon opens our application, as shown in Fig. 4.<\/p>\n<p><img decoding=\"async\" alt=\"Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines\" src=\"\/wp-content\/uploads\/2020\/08\/aa8e09d9fd9f33d5faffc7f661d84ca4.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><i>Fig. 4. Running React application.<\/i><\/p>\n<h3>Conclusion<\/h3>\n<p>\nWe have shown how to launch a development server for your application on OpenShift and synchronize it with the local file system. We also discussed how to simulate a chained-build template using OpenShift Pipelines. All example codes from this article can be found <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/nodeshift\/webapp-pipeline-tutorial\">here<\/a><\/noindex>.<\/p>\n<h3>Additional resources (EN)<\/h3>\n<p><\/p>\n<ul>\n<li>Free eBook <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/books\/deploying-openshift\/\">\u201cDeveloping on OpenShift: A Guide for the Impatient\u201d<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/blog\/2018\/06\/11\/container-native-nodejs-istio-rhoar\/\">Building container-oriented Node.js applications using Red Hat OpenShift Application Runtimes and Istio<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/blog\/2018\/05\/15\/debug-your-node-js-application-on-openshift-with-chrome-devtools\/\">Debugging Node.js applications on OpenShift with Chrome DevTools<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/blog\/2018\/04\/16\/zero-express-openshift-3-commands\/\">Three commands to master Express on OpenShift from scratch<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/blog\/2018\/03\/12\/rhoar-nodejs-annoucement\/\">Announcement of the public release of Node.js as part of Red Hat OpenShift Application Runtimes<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/blog\/2018\/12\/21\/monitoring-node-js-applications-on-openshift-with-prometheus\/\">Monitoring Node.js applications on OpenShift with Prometheus<\/a><\/noindex><\/li>\n<li>Other articles on <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/topics\/kubernetes\/\">OpenShift and Kubernetes<\/a><\/noindex> on the Red Hat website<\/li>\n<\/ul>\n<h3>Announcements of upcoming webinars<\/h3>\n<p>\nWe are starting a series of Friday webinars on the native experience of using Red Hat OpenShift Container Platform and Kubernetes:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/events.redhat.com\/profile\/form\/index.cfm?PKformID=0x232599abcd&amp;sc_cid=7013a000002gwqQAAQ\"><b>August 28, Webinar Emperor \u201cOperator\u201d: Operators in OpenShift and Kubernetes<\/b><\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/events.redhat.com\/profile\/form\/index.cfm?PKformID=0x232694abcd&amp;sc_cid=7013a000002gwrdAAA\"><b>September 11, DeploymentConfig vs Deployment \u2013 OpenShift-specific magic for building and deploying applications<\/b><\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/events.redhat.com\/profile\/form\/index.cfm?PKformID=0x232789abcd&amp;sc_cid=7013a000002gws7AAA\"><b>September 25, Red Hat OpenShift and Machine API<\/b><\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/events.redhat.com\/profile\/form\/index.cfm?PKformID=0x232884abcd&amp;sc_cid=7013a000002gwsqAAA\"><b>October 9, How to handle sudden load spikes<\/b><\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/events.redhat.com\/profile\/form\/index.cfm?PKformID=0x232979abcd&amp;sc_cid=7013a000002gwumAAA\"><b>October 23, Built-in Jenkins, Pipeline-builds, Tekton in Red Hat OpenShift Container Platform<\/b><\/a><\/noindex><\/li>\n<\/ul>\n<p>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/515988\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442 \u0432\u0441\u0435\u043c \u0432 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u0433\u0435! \u0421 \u0432\u0430\u043c\u0438 \u0442\u0440\u0435\u0442\u0438\u0439 \u043f\u043e\u0441\u0442 \u0438\u0437 \u0441\u0435\u0440\u0438\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Red Hat OpenShift. \u0412 \u0434\u0432\u0443\u0445 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u043f\u043e\u0441\u0442\u0430\u0445 \u043c\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b\u0438, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0433\u043e \u0437\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0430\u0433\u043e\u0432 \u0438 \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 S2I \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, NGINX \u0441 \u043f\u043e\u043c\u043e\u0449\u044c \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0431\u043e\u0440\u043e\u043a chained [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":92049,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-92048","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442 \u0432\u0441\u0435\u043c \u0432 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u0433\u0435!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 OpenShift, \u0447\u0430\u0441\u0442\u044c 3: OpenShift \u043a\u0430\u043a \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u044b OpenShift Pipelines | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442 \u0432\u0441\u0435\u043c \u0432 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u0433\u0435!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-08-22T05:42:57+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-08-22T05:42:57+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Modern Applications on OpenShift, Part 3: OpenShift as a Development Environment and OpenShift Pipelines | ProHoster","description":"Hello everyone in this blog!","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 OpenShift, \u0447\u0430\u0441\u0442\u044c 3: OpenShift \u043a\u0430\u043a \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u044b OpenShift Pipelines | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442 \u0432\u0441\u0435\u043c \u0432 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u0433\u0435!","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-3-openshift-kak-sreda-razrabotki-i-konvejery-openshift-pipelines","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-08-22T05:42:57+00:00","article:modified_time":"2020-08-22T05:42:57+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"92048","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:16:43","updated":"2022-10-02 02:53:55","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/92048","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=92048"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/92048\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/92049"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=92048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=92048"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=92048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}