{"id":76,"date":"2017-03-29T16:55:25","date_gmt":"2017-03-29T08:55:25","guid":{"rendered":"http:\/\/www.jsjs.org\/?p=76"},"modified":"2017-03-29T16:55:25","modified_gmt":"2017-03-29T08:55:25","slug":"microservices-with-continuous-delivery-using-docker-and-jenkins","status":"publish","type":"post","link":"https:\/\/blog.jsjs.org\/?p=76","title":{"rendered":"Microservices With Continuous Delivery Using Docker and Jenkins"},"content":{"rendered":"<div class=\"article-bumper ng-binding ng-scope\"><a href=\"https:\/\/dzone.com\/go?i=161130&amp;u=http%3A%2F%2Finfo.saucelabs.com%2Fpaper-the-devops-journey.html%3Futm_campaign%3Ddevopsjourney%2Bwp%26utm_medium%3Dtextlink%26utm_source%3Ddzone-devops%26utm_content%3Darticle\" target=\"_blank\" rel=\"nofollow noopener\">Download \u201cThe DevOps Journey &#8211; From Waterfall to Continuous Delivery\u201d<\/a> to learn\u00a0learn about the importance of integrating automated testing into the DevOps workflow, brought to you in partnership with <a href=\"https:\/\/dzone.com\/go?i=161130&amp;u=http%3A%2F%2Finfo.saucelabs.com%2Fpaper-the-devops-journey.html%3Futm_campaign%3Ddevopsjourney%2Bwp%26utm_medium%3Dtextlink%26utm_source%3Ddzone-devops%26utm_content%3Darticle\" target=\"_blank\" rel=\"nofollow noopener\">Sauce Labs<\/a>.<\/div>\n<div class=\"ng-scope\">\n<div class=\"content-html\">\n<p>Docker, microservices, Continuous Delivery <span id=\"result_box\" lang=\"en\">are currently some of\u00a0the most popular topics in the world of programming.\u00a0In an environment consisting of dozens of microservices\u00a0communicating with each other, it seems to be particularly important\u00a0the automation of the testing, building, and deployment process. Docker is an\u00a0excellent solution for microservices\u00a0because\u00a0it can create and run isolated containers with service.<\/span><\/p>\n<p><span id=\"result_box\" lang=\"en\">Today, I&#8217;m going to present you how to create a\u00a0basic Continuous Delivery pipeline for sample microservices using a popular software\u00a0automation tool: Jenkins.<\/span><\/p>\n<h2><span id=\"result_box\" lang=\"en\">Sample Microservices<\/span><\/h2>\n<p><span id=\"result_box\" lang=\"en\">Before I get into the main topic of this article, I&#8217;ll say a few words about<\/span> structure and tools used for\u00a0sample microservices creation. The sample application consists of two sample\u00a0microservices communicating with each other (account, customer), a discovery server (Eureka), and an API gateway (Zuul).\u00a0<span id=\"result_box\" lang=\"en\">It was implemented using Spring Boot and Spring Cloud frameworks. Its source code is available on <a href=\"https:\/\/github.com\/piomin\/sample-spring-microservices.git\" target=\"_blank\" rel=\"nofollow noopener\">GitHub<\/a>. Spring Cloud has support for microservices discovery\u00a0and gateway out of the box \u2014 we only have to define right dependencies inside maven project\u00a0configuration file (<code>pom.xml<\/code><span id=\"_tmp_pre_1\"><\/span>).<\/span><\/p>\n<p><span id=\"result_box\" lang=\"en\">The picture illustrating the adopted solution architecture is visible\u00a0below. Customer, account REST\u00a0API services, discovery server, and gateway are running inside separated\u00a0Docker containers. Gateway is the entry point to the microservices system. It is interacting with all other services. It proxies requests to the selected microservices searching its addresses in discovery service. In the\u00a0case of there being more than one instance of each account or customer\u00a0microservice, the request is load balanced with <code>Ribbon<\/code><span id=\"_tmp_pre_3\">\u00a0<\/span>and <code>Feign<\/code>\u00a0clients.<\/span><\/p>\n<p><span id=\"result_box\" lang=\"en\">Account and customer services are registering themselves into the discovery server after startup. There is also a possibility of interaction between them \u2014 for example, if we would like to find and return\u00a0all\u00a0customer&#8217;s account details.<\/span><\/p>\n<p><img decoding=\"async\" class=\"fr-fin fr-dib\" src=\"https:\/\/dzone.com\/storage\/temp\/4703327-docker-micro-1.png\" alt=\"Image title\" width=\"516\" \/><\/p>\n<p><span id=\"result_box\" lang=\"en\">I\u00a0wouldn&#8217;t like\u00a0to go into the details of those microservices\u00a0implementation with\u00a0Spring Boot and Spring\u00a0Cloud frameworks. If you are interested in a\u00a0detailed description of the sample application development, you can read it in my blog post <a href=\"https:\/\/piotrminkowski.wordpress.com\/2017\/02\/05\/part-1-creating-microservice-using-spring-cloud-eureka-and-zuul\/\" target=\"_blank\" rel=\"nofollow noopener\">here<\/a>.\u00a0Generally, Spring framework\u00a0has a full support for microservices with all Netflix OSS tools like Ribbon, Hystrix, and Eureka. In the blog post, I described how to implement service discovery, distributed tracing, load balancing, logging\u00a0trace ID propagation, and API gateway for microservices\u00a0with those solutions.<\/span><\/p>\n<h2>Dockerfiles<\/h2>\n<p>Each service in the sample source code has a\u00a0<code>Dockerfile<\/code>\u00a0with a Docker\u00a0image build definition. It&#8217;s really simple. Here&#8217;s Dockerfile for account service. We use OpenJDK as a base image. A JAR file from the target is added to the image and then run using the\u00a0<code>java -jar<\/code><em>\u00a0<\/em>command. Service is running on port <em>2222<\/em>,<em>\u00a0<\/em>which is exposed outside.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>FROM openjdk<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>MAINTAINER Piotr Minkowski &lt;piotr.minkowski@gmail.com&gt;<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>ADD target\/account-service.jar account-service.jar<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>ENTRYPOINT [\"java\", \"-jar\", \"\/account-service.jar\"]<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>EXPOSE 2222<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<p>We also had to set main class in the JAR manifest. We achieve it using <em>spring-boot-maven-plugin<\/em> in module\u00a0<code>pom.xml<\/code>. The fragment is visible below. We also set build <code>finalName<\/code><em>\u00a0<\/em>to cut off version number from target JAR file. The Dockerfile and Maven\u00a0build definition is pretty similar\u00a0for all other microservices.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre><span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">build<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>  <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">finalName<\/span><span class=\"cm-tag bracket\">&gt;<\/span>account-service<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">finalName<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>  <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">plugins<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">plugin<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">groupId<\/span><span class=\"cm-tag bracket\">&gt;<\/span>org.springframework.boot<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">groupId<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">artifactId<\/span><span class=\"cm-tag bracket\">&gt;<\/span>spring-boot-maven-plugin<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">artifactId<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">version<\/span><span class=\"cm-tag bracket\">&gt;<\/span>1.5.2.RELEASE<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">version<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">configuration<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">mainClass<\/span><span class=\"cm-tag bracket\">&gt;<\/span>pl.piomin.microservices.account.Application<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">mainClass<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">addResources<\/span><span class=\"cm-tag bracket\">&gt;<\/span>true<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">addResources<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">configuration<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">executions<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">execution<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>          <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">goals<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-tag bracket\">&lt;<\/span><span class=\"cm-tag\">goal<\/span><span class=\"cm-tag bracket\">&gt;<\/span>repackage<span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">goal<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>          <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">goals<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">execution<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>      <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">executions<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">plugin<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>  <span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">plugins<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre><span class=\"cm-tag bracket\">&lt;\/<\/span><span class=\"cm-tag\">build<\/span><span class=\"cm-tag bracket\">&gt;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<h2>Jenkins Pipelines<\/h2>\n<p>We use <a href=\"https:\/\/wiki.jenkins-ci.org\/display\/JENKINS\/Pipeline+Plugin\" target=\"_blank\" rel=\"nofollow noopener\">Pipeline Plugin<\/a> for building Continuous Delivery for our microservices.\u00a0<span id=\"result_box\" lang=\"en\">In addition to the standard plugins set on Jenkins,<\/span> we also need <a href=\"https:\/\/wiki.jenkins-ci.org\/display\/JENKINS\/CloudBees+Docker+Pipeline+Plugin\" target=\"_blank\" rel=\"nofollow noopener\">Docker Pipeline Plugin by CloudBees<\/a>. There are four pipelines defined, as you can see in the picture below.<\/p>\n<p><img decoding=\"async\" class=\"fr-fin fr-dib\" src=\"https:\/\/dzone.com\/storage\/temp\/4701294-jenkins-docker.png\" alt=\"Image title\" width=\"721\" \/><\/p>\n<p>Here&#8217;s the pipeline definition written in Groovy language for discovery\u00a0service. We have five stages of execution. Inside the Checkout stage, we are pulling changes for remote Git repository of the project. Then project is built with the MVN clean install command and the Maven version is read from\u00a0<code>pom.xml<\/code><span id=\"_tmp_pre_9\"><\/span>. In the Image stage, we build a Docker image from discovery service Dockerfile and then push that image to local registry. In the fourth step, we are running the built image with default port exposed and hostname visible for linked docker containers. Finally, the account pipeline is started with no wait option, which means that source pipeline is finished and won&#8217;t wait for account pipeline execution finish.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre><span class=\"cm-variable\">node<\/span> {<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    <span class=\"cm-variable\">withMaven<\/span>(<span class=\"cm-property\">maven:<\/span><span class=\"cm-string\">'maven'<\/span>) {<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Checkout'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">git<\/span> <span class=\"cm-property\">url:<\/span> <span class=\"cm-string\">'https:\/\/github.com\/piomin\/sample-spring-microservices.git'<\/span>, <span class=\"cm-property\">credentialsId:<\/span> <span class=\"cm-string\">'github-piomin'<\/span>, <span class=\"cm-property\">branch:<\/span> <span class=\"cm-string\">'master'<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Build'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">sh<\/span> <span class=\"cm-string\">'mvn clean install'<\/span><\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-keyword\">def<\/span> <span class=\"cm-variable\">pom<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">readMavenPom<\/span> <span class=\"cm-property\">file:<\/span><span class=\"cm-string\">'pom.xml'<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">print<\/span> <span class=\"cm-variable\">pom<\/span>.<span class=\"cm-property\">version<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">pom<\/span>.<span class=\"cm-property\">version<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Image'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">dir<\/span> (<span class=\"cm-string\">'discovery-service'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>                <span class=\"cm-keyword\">def<\/span> <span class=\"cm-variable\">app<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">docker<\/span>.<span class=\"cm-property\">build<\/span> <span class=\"cm-string\">\"localhost:5000\/discovery-service:${<\/span><span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span><span class=\"cm-string\">}\"<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>                <span class=\"cm-variable\">app<\/span>.<span class=\"cm-property\">push<\/span>()<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            }<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span> (<span class=\"cm-string\">'Run'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">docker<\/span>.<span class=\"cm-property\">image<\/span>(<span class=\"cm-string\">\"localhost:5000\/discovery-service:${<\/span><span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span><span class=\"cm-string\">}\"<\/span>).<span class=\"cm-property\">run<\/span>(<span class=\"cm-string\">'-p 8761:8761 -h discovery --name discovery'<\/span>)<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span> (<span class=\"cm-string\">'Final'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">build<\/span> <span class=\"cm-property\">job:<\/span> <span class=\"cm-string\">'account-service-pipeline'<\/span>, <span class=\"cm-property\">wait:<\/span> <span class=\"cm-atom\">false<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>}<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<p>Account pipeline is very similar. The main difference is inside the fourth stage where account service container is linked to discovery container. We need to link those containers\u00a0because\u00a0<code>account-service<\/code>\u00a0is registering itself in discovery server and must be able to connect it using hostname.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre><span class=\"cm-variable\">node<\/span> {<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    <span class=\"cm-variable\">withMaven<\/span>(<span class=\"cm-property\">maven:<\/span><span class=\"cm-string\">'maven'<\/span>) {<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Checkout'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">git<\/span> <span class=\"cm-property\">url:<\/span> <span class=\"cm-string\">'https:\/\/github.com\/piomin\/sample-spring-microservices.git'<\/span>, <span class=\"cm-property\">credentialsId:<\/span> <span class=\"cm-string\">'github-piomin'<\/span>, <span class=\"cm-property\">branch:<\/span> <span class=\"cm-string\">'master'<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Build'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">sh<\/span> <span class=\"cm-string\">'mvn clean install'<\/span><\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-keyword\">def<\/span> <span class=\"cm-variable\">pom<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">readMavenPom<\/span> <span class=\"cm-property\">file:<\/span><span class=\"cm-string\">'pom.xml'<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">print<\/span> <span class=\"cm-variable\">pom<\/span>.<span class=\"cm-property\">version<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">pom<\/span>.<span class=\"cm-property\">version<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span>(<span class=\"cm-string\">'Image'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">dir<\/span> (<span class=\"cm-string\">'account-service'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>                <span class=\"cm-keyword\">def<\/span> <span class=\"cm-variable\">app<\/span> <span class=\"cm-operator\">=<\/span> <span class=\"cm-variable\">docker<\/span>.<span class=\"cm-property\">build<\/span> <span class=\"cm-string\">\"localhost:5000\/account-service:${<\/span><span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span><span class=\"cm-string\">}\"<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>                <span class=\"cm-variable\">app<\/span>.<span class=\"cm-property\">push<\/span>()<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            }<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span> (<span class=\"cm-string\">'Run'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">docker<\/span>.<span class=\"cm-property\">image<\/span>(<span class=\"cm-string\">\"localhost:5000\/account-service:${<\/span><span class=\"cm-variable\">env<\/span>.<span class=\"cm-property\">version<\/span><span class=\"cm-string\">}\"<\/span>).<span class=\"cm-property\">run<\/span>(<span class=\"cm-string\">'-p 2222:2222 -h account --name account --link discovery'<\/span>)<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        <span class=\"cm-variable\">stage<\/span> (<span class=\"cm-string\">'Final'<\/span>) {<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>            <span class=\"cm-variable\">build<\/span> <span class=\"cm-property\">job:<\/span> <span class=\"cm-string\">'customer-service-pipeline'<\/span>, <span class=\"cm-property\">wait:<\/span> <span class=\"cm-atom\">false<\/span><\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>        }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>    }<\/pre>\n<\/div>\n<div><\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>}<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<p>Similar pipelines are also defined for customer and gateway service. They are available in main project\u00a0catalog on each microservice as a\u00a0<code>Jenkinsfile<\/code><span id=\"_tmp_pre_3\"><\/span>. Every image which is\u00a0built during pipeline execution is also\u00a0pushed to local Docker registry. To enable local registry on our host, we need to pull and\u00a0run Docker registry image and also use that registry address as an image name prefix while pulling or pushing. The local registry is exposed on its default <em>5000<\/em> port. You can see the list of pushed images to the\u00a0local registry by calling its REST API, for example, <em>http:\/\/localhost:5000\/v2\/_catalog<\/em>.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>docker run <span class=\"cm-attribute\">-d<\/span> <span class=\"cm-attribute\">--name<\/span> registry <span class=\"cm-attribute\">-p<\/span> <span class=\"cm-number\">5000<\/span>:5000 registry<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<h2>Testing<\/h2>\n<p>You should launch the\u00a0build on <code>discovery-service-pipeline<\/code>. This pipeline will not only run build for discovery\u00a0service but also\u00a0call start next\u00a0pipeline build (<code>account-service-pipeline<\/code>) at the end.<\/p>\n<p>The same rule is configured for <code>account-service-pipeline<\/code>\u00a0which calls<code>customer-service-pipeline<\/code>\u00a0and for <code>customer-service-pipeline<\/code>, which call<code>gateway-service-pipeline<\/code>.<\/p>\n<p>So, after all\u00a0of the pipelines finish, you can check the list of running docker containers by calling the\u00a0<code>docker ps<\/code><span id=\"_tmp_pre_5\">\u00a0<\/span>command. You should have seen five containers: local registry and our four microservices.<\/p>\n<p>You can also check the logs of each container by running command <code>docker logs<\/code>\u00a0\u2014 for example,<code>docker logs account<\/code><span id=\"_tmp_pre_7\"><\/span>. If everything works fine, you should be able to call a service like <em>http:\/\/localhost:2222\/accounts<\/em> or via the\u00a0Zuul gateway <em>http:\/\/localhost:8765\/account\/account<\/em>.<\/p>\n<div class=\"CodeMirror cm-s-default\">\n<div class=\"CodeMirror-scroll\">\n<div class=\"CodeMirror-sizer\">\n<div>\n<div class=\"CodeMirror-lines\">\n<div>\n<div class=\"CodeMirror-code\">\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>CONTAINER ID        IMAGE                                           COMMAND                  CREATED             STATUS              PORTS                    NAMES<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>fa3b9e408bb4        localhost:5000\/gateway-service:1.0-SNAPSHOT     \"java <span class=\"cm-negative\">-<\/span><span class=\"cm-negative\">jar \/gatewa...<\/span><span class=\"cm-negative\">\"<\/span><span class=\"cm-negative\">   About an hour ago   Up About an hour    0.0.0.0:8765<\/span><span class=\"cm-negative\">-<\/span>&gt;8765\/tcp   gateway<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>cc9e2b44fe44        localhost:5000\/customer-service:1.0-SNAPSHOT    \"java <span class=\"cm-negative\">-<\/span><span class=\"cm-negative\">jar \/custom...<\/span><span class=\"cm-negative\">\"<\/span><span class=\"cm-negative\">   About an hour ago   Up About an hour    0.0.0.0:3333<\/span><span class=\"cm-negative\">-<\/span>&gt;3333\/tcp   customer<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>49657f4531de        localhost:5000\/account-service:1.0-SNAPSHOT     \"java <span class=\"cm-negative\">-<\/span><span class=\"cm-negative\">jar \/accoun...<\/span><span class=\"cm-negative\">\"<\/span><span class=\"cm-negative\">   About an hour ago   Up About an hour    0.0.0.0:2222<\/span><span class=\"cm-negative\">-<\/span>&gt;2222\/tcp   account<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>fe07b8dfe96c        localhost:5000\/discovery-service:1.0-SNAPSHOT   \"java <span class=\"cm-negative\">-<\/span><span class=\"cm-negative\">jar \/discov...<\/span><span class=\"cm-negative\">\"<\/span><span class=\"cm-negative\">   About an hour ago   Up About an hour    0.0.0.0:8761<\/span><span class=\"cm-negative\">-<\/span>&gt;8761\/tcp   discovery<\/pre>\n<\/div>\n<div>\n<div class=\"CodeMirror-gutter-wrapper\"><\/div>\n<pre>f9a7691ddbba        registry                                        \"\/entrypoint.sh \/e...\"   About an hour ago   Up About an hour    0.0.0.0:5000-&gt;5000\/tcp   registry<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"CodeMirror-gutters\"><\/div>\n<\/div>\n<\/div>\n<h2>Conclusion<\/h2>\n<p>I have presented the basic sample of Continuous Delivery environment for microservices using Docker and Jenkins. You can easily find out the limitations of presented solution. For example, we have\u00a0linked Docker containers with each other to enable communication between them or all of the tools and microservices are running on the same machine.<\/p>\n<p>For a more advanced sample, we could use Jenkins slaves running on different machines or Docker containers (more <a href=\"https:\/\/piotrminkowski.wordpress.com\/2017\/03\/13\/jenkins-nodes-on-docker-containers\/\" target=\"_blank\" rel=\"nofollow noopener\">here<\/a>), tools like <a href=\"https:\/\/kubernetes.io\/\" target=\"_blank\" rel=\"nofollow noopener\">Kubernetes<\/a> for orchestration and\u00a0clustering, or maybe Docker-in-Docker containers for simulating multiple Docker machines. I hope that this article is\u00a0a fine introduction to microservices and Continuous Delivery and helps you to understand the basics of this idea. I think that you can expect more of my\u00a0advanced articles about this subject near the future.<\/p>\n<\/div>\n<\/div>\n<div class=\"article-bumper article-bumper-bottom ng-binding ng-scope\"><a href=\"https:\/\/dzone.com\/go?i=161129&amp;u=http%3A%2F%2Finfo.saucelabs.com%2Fpaper-the-devops-journey.html%3Futm_campaign%3Ddevopsjourney%2Bwp%26utm_medium%3Dtextlink%26utm_source%3Ddzone-devops%26utm_content%3Darticle\" target=\"_blank\" rel=\"nofollow noopener\">Discover how to optimize your DevOps workflows<\/a> with our cloud-based automated testing infrastructure, brought to you in partnership with <a href=\"https:\/\/dzone.com\/go?i=161129&amp;u=http%3A%2F%2Finfo.saucelabs.com%2Fpaper-the-devops-journey.html%3Futm_campaign%3Ddevopsjourney%2Bwp%26utm_medium%3Dtextlink%26utm_source%3Ddzone-devops%26utm_content%3Darticle\" target=\"_blank\" rel=\"nofollow noopener\">Sauce Labs<\/a>.<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Download \u201cThe DevOps Journey &#8211; From Waterfall to Continuous Delivery\u201d to learn\u00a0learn about the importance of integrating automated testing into [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-76","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/76","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=76"}],"version-history":[{"count":0,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/76\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=76"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=76"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=76"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}