<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eddie Webbinaro</title>
    <description>The latest articles on DEV Community by Eddie Webbinaro (@eddiewebb).</description>
    <link>https://dev.to/eddiewebb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F111199%2Fbb7682bc-be91-483d-bc41-611462c5131a.jpeg</url>
      <title>DEV Community: Eddie Webbinaro</title>
      <link>https://dev.to/eddiewebb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eddiewebb"/>
    <language>en</language>
    <item>
      <title>Kubernetes deployments with Cloudflare</title>
      <dc:creator>Eddie Webbinaro</dc:creator>
      <pubDate>Mon, 15 Oct 2018 13:35:00 +0000</pubDate>
      <link>https://dev.to/circleci/kubernetes-deployments-with-cloudflare-4gjm</link>
      <guid>https://dev.to/circleci/kubernetes-deployments-with-cloudflare-4gjm</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is the second in a series that covers multi-cloud deployment. The first post, “&lt;a href="https://dev.to/circleci/dockerizing-java-apps-with-circleci-and-jib-2af8"&gt;Dockerizing Java apps with CircleCI and Jib&lt;/a&gt;,” addressed using Google’s Jib project to simplify wrapping a Java application in Docker. This post covers multi-cloud deployment behind a global load balancer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the first &lt;a href="https://dev.to/circleci/dockerizing-java-apps-with-circleci-and-jib-2af8"&gt;post&lt;/a&gt;, we talked about building containerized applications and published a simple Java Spring Boot application with Google’s Jib. That process is efficient at building and assembling our application, but we did not address distribution. In this post, we will look at a method of deploying our Docker application to Kubernetes and enabling global access with Cloudflare’s domain name system (DNS) and proxy services.&lt;/p&gt;

&lt;p&gt;We will be using several technologies in this blog, and a basic understanding of CircleCI is required. If you are new to CircleCI, we have &lt;a href="https://circleci.com/docs/2.0/basics/"&gt;introductory content&lt;/a&gt; to help you get started.&lt;/p&gt;

&lt;p&gt;The code used in this post lives in a sample repository on Github. You can reference &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s"&gt;https://github.com/eddiewebb/circleci-multi-cloud-k8s&lt;/a&gt; for full code samples, or to follow along. Here is the workflow that we will be building:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NNmpzPzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i8b8sdqd6lnyowdjldh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NNmpzPzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i8b8sdqd6lnyowdjldh9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Credential management
&lt;/h2&gt;

&lt;p&gt;I brought credential management to the top of this post on deployments because it is fundamental to a successful &lt;a href="https://circleci.com/continuous-integration/"&gt;CI/CD&lt;/a&gt; pipeline. Before we start pushing our configuration, we are going to set up our access to Docker Hub (optional), Google Cloud Platform (GCP) and Cloudflare.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticating with Docker Hub
&lt;/h3&gt;

&lt;p&gt;My sample workflow uses Docker Hub as the registry for our containerized application. As an alternative, you can push them to Google or Amazon's registries. How you authenticate will depend on your application. This sample app uses Maven encryption to authenticate Google Jib's connection with Docker Hub, as described in our first &lt;a href="https://dev.to/circleci/dockerizing-java-apps-with-circleci-and-jib-2af8"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticating with Google Cloud Platform
&lt;/h3&gt;

&lt;p&gt;GCP is the IaaS provider we chose to host our Kubernetes cluster. To get started authenticating with GCP, you will need to create a service user key as described in the &lt;a href="https://cloud.google.com/iam/docs/creating-managing-service-account-keys"&gt;Google docs&lt;/a&gt;. Choose the new &lt;code&gt;.json&lt;/code&gt; format when it prompts you to download a key. You will also need to assign roles to the service account. To successfully create a cluster and deployment, your service account will need ‘Kubernetes Engine Cluster Admin’ and ‘Kubernetes Engine Developer.’ Those roles can be granted on the main identity and access management (IAM) tab in Google’s console.&lt;/p&gt;

&lt;p&gt;The key file contains sensitive information. We never want to check sensitive information into the source code. In order to expose it to our workflow, we will encode the file as a string, and save it as an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; ~/Downloads/account-12345-abcdef1234.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the output and save it as an environment variable in the CircleCI project configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NcWTFICh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/woakyy0p0bemd4bm5cl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NcWTFICh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/woakyy0p0bemd4bm5cl8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Later, when we need that within our deployment job, we can decode it back to a file with base64 again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GCP_KEY_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; gcp_key.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I feel it necessary to issue the standard precaution: base64 is not encryption, it adds no security nor true obfuscation of the sensitive values. We use base64 as a means to turn a file into a string. &lt;strong&gt;It is paramount that you treat the base64 value with the same level of protection as the key file itself.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticating with Cloudflare
&lt;/h3&gt;

&lt;p&gt;One of the last steps in our deployment is the use of Cloudflare to route traffic for &lt;a href="https://justademo.online"&gt;justademo.online&lt;/a&gt; back to our various clusters. We need a Cloudflare API key, a DNS zone, and an email address. Since these are all simple strings they can be added as is.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CLOUDFLARE_API_KEY&lt;/code&gt; - Can be found in profile and domain dashboard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLOUDFLARE_DNS_ZONE&lt;/code&gt; - Can be found on domain dashboard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLOUDFLARE_EMAIL&lt;/code&gt; - Email used to create Cloudflare account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploying Docker containers to Kubernetes with CircleCI
&lt;/h2&gt;

&lt;p&gt;I found Google Cloud's Kubernetes support intuitive and easy to get started. Their &lt;code&gt;gcloud&lt;/code&gt; command line interface (CLI) even provides a means to inject the required configuration into Kubernetes &lt;code&gt;kubectl&lt;/code&gt; CLI. There are many providers out there and, although not covered in this blog post, the &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s"&gt;sample code&lt;/a&gt; does include a deployment to Amazon Web Services (AWS) using &lt;code&gt;kops&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the command line tools
&lt;/h3&gt;

&lt;p&gt;CircleCI favors deterministic and explicit configuration over plugins. That enables us to control the environment and versions used right within our configuration. The first thing we will do is install our CLI tools:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tHOxasT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5tsc0zcs2o71gttbiuge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tHOxasT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5tsc0zcs2o71gttbiuge.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; 
  Remember: You can copy text from our 
    &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s/blob/master/.circleci/config.yml"&gt;sample project's&lt;/a&gt; configuration.
  
&lt;/p&gt;

&lt;p&gt;Because the steps above install the CLI on each build, it does add ~10-15 seconds to our job. For tools that you use often, it is worth your time to &lt;a href="https://circleci.com/docs/2.0/custom-images/"&gt;package your own custom Docker images&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;gcloud&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; tools installed, we can begin creating our cluster and deployment. The general flow in GCP’s Kubernetes environment is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a cluster that defines the number and size of VMs to run our workload.&lt;/li&gt;
&lt;li&gt;Create a deployment that defines the &lt;a href="https://circleci.com/docs/2.0/custom-images/"&gt;container image&lt;/a&gt; to use as our workload.&lt;/li&gt;
&lt;li&gt;Create a load balancer service that maps an IP and port to our cluster.
 &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before &lt;code&gt;gcloud&lt;/code&gt; will do any of that, we need to provide it with credentials and project information. This is the step where we "rehydrate" our GCP key into a readable file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lNatl59u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/plz3haciqzwa8jb0qpv7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lNatl59u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/plz3haciqzwa8jb0qpv7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Running your first deployment
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;gcloud&lt;/code&gt; CLI now has access to our service account. We will use that access to create our cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters create circleci-k8s-demo &lt;span class="nt"&gt;--num-nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should block until the cluster creation succeeds. That allows us to provide our container image as a workload. The &lt;code&gt;gcloud&lt;/code&gt; CLI will also save the required permissions into &lt;code&gt;kubectl&lt;/code&gt; automatically for us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run circleci-k8s-demo &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOCKER_IMAGE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;DOCKER_IMAGE&lt;/code&gt; defines the full coordinates of our container in standard registry format. If you followed our &lt;a href="https://circleci.com/blog/dockerizing-java-apps-with-circleci-and-jib/"&gt;previous post&lt;/a&gt; on versioning Java containers with Jib, the &lt;code&gt;DOCKER_IMAGE&lt;/code&gt; would be: &lt;code&gt;eddiewebb/circleci-k8s-demo:0.0.1-b8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike the create cluster command, the command to create or update the deployment is asynchronous. We need to run some basic smoke tests against our cluster. We use the rollout status command to wait for a successful deployment. This command is perfect because it waits for the final status, and will exit with a 0 on a successful deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout status deployment/circleci-k8s-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our container is now running on several nodes, with various IPs, on port 8080. Before we move on from GCP, the last thing to do is set up the local load balancer to send traffic from a single IP to all of the containers in the cluster. We use &lt;code&gt;kubectl&lt;/code&gt;'s &lt;code&gt;expose&lt;/code&gt; command for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl expose deployment circleci-k8s-demo &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="nt"&gt;--port&lt;/span&gt; 80 &lt;span class="nt"&gt;--target-port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just to make sure everything is started and routing successfully, we can run a primitive health check:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fv8MoRYF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jvnt7pre69bhlf4nmdr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fv8MoRYF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jvnt7pre69bhlf4nmdr6.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may notice in the Smoke Test job above, we do not know the IP address that Google will assign ahead of time. In a production environment, you would likely choose to purchase and allocate a reserved IP, instead of using a floating IP. You can see an example of that in our &lt;a href="https://circleci.com/docs/2.0/deployment-integrations/#aws"&gt;AWS deployment&lt;/a&gt; that is part of the &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s/blob/master/.circleci/config.yml"&gt;sample project&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing your domain with Cloudflare
&lt;/h3&gt;

&lt;p&gt;Each cloud provider exposes ways to get your dynamic cluster IP assigned to a known domain name. I want to demonstrate how we might serve our application from multiple cloud providers and dynamically address distribution and load. In addition to providing a straightforward API to manage our DNS, Cloudflare allows us to route traffic through their proxy for additional caching and protections. Additionally, since this is running in its own step, we need to grab the &lt;code&gt;CLUSTER_IP&lt;/code&gt; from &lt;code&gt;kubectl&lt;/code&gt; again. We will then use that IP in a &lt;code&gt;POST&lt;/code&gt; call to Cloudflare's DNS:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DHoCtH3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/lwckx4v98e2bos80t7lv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DHoCtH3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/lwckx4v98e2bos80t7lv.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Because we want to use this sub-domain in our load balancers later, it is important that we leave "proxying" disabled.&lt;/p&gt;

&lt;p&gt;That will map the GCP cluster to a subdomain. This subdomain will be used by our global load balancer to distribute traffic among multiple cloud providers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wD1fLxiq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/atpqr7bl17fm44tr96k8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wD1fLxiq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/atpqr7bl17fm44tr96k8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! Did it work? If you have followed along, you will have a live sub-domain similar to &lt;a href="http://k8sgcp.justademo.online/"&gt;k8sgcp.justademo.online&lt;/a&gt; routing through Cloudflare to your Kubernetes cluster in Google Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating existing Kubernetes deployments on GCP with CircleCI
&lt;/h2&gt;

&lt;p&gt;Our example above created everything fresh. If you tried to rerun that deployment, it would fail! Google will not create a cluster, deployment, or service that already exists. To make our workflow behave properly, we have to augment our original solution to consider the current state.&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;describe&lt;/code&gt; commands to determine if our stack already exists, and run the appropriate update commands instead. &lt;/p&gt;

&lt;p&gt;Create cluster OR get credentials:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0k6mRF6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/j0t6lw4w0vf7fwjshg98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0k6mRF6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/j0t6lw4w0vf7fwjshg98.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run deployment OR update the image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R8562Gy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6gbv3smph8qixeloek37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R8562Gy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6gbv3smph8qixeloek37.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s"&gt;sample project&lt;/a&gt; uses logic that will create or update all aspects, depending on the current state.&lt;/p&gt;

&lt;p&gt;Alternately, and for more robust deployments, you will want to explore the use of Kubernetes deployment definitions that can be defined and applied, capturing the configuration as a &lt;code&gt;.yml&lt;/code&gt; file. More information can be found in the &lt;a href="https://kubernetes.io/docs/tasks/run-application/run-stateless-application-deployment/"&gt;Kubernetes examples&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding AWS deployments
&lt;/h2&gt;

&lt;p&gt;AWS provides several options for deploying containers, including Fargate, ECS, and building your own cluster from EC2 instances. You can look at the &lt;code&gt;deploy-AWS&lt;/code&gt; job within our &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s/blob/master/.circleci/config.yml"&gt;sample project&lt;/a&gt; to explore one approach. We used the &lt;code&gt;kops&lt;/code&gt; &lt;a href="https://github.com/kubernetes/kops"&gt;project&lt;/a&gt; to provision a cluster from EC2 and Elastic Load Balancers (ELB) to route traffic to that cluster. &lt;/p&gt;

&lt;p&gt;What is germane to the topic in this blog post is that we now have the same application running across multiple cloud providers. Next we will implement a global load balancer to distribute traffic among them and setup our DNS. Setting up DNS will be a little different due to &lt;code&gt;kops&lt;/code&gt; creating an ELB for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tie it together with Cloudflare
&lt;/h2&gt;

&lt;p&gt;As with Cloudflare’s DNS service, their Traffic service exposes a full API for managing the load balancer configuration. This makes it straightforward for us to automate that task in CircleCI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a load balancer in Cloudflare
&lt;/h3&gt;

&lt;p&gt;I opted not to script this part since it truly is a one-time thing. Create a load balancer that is associated with the primary domain you want sitting in front of all your clouds:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lnJaOUHB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vluwus0g5qvwt6iq9r83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lnJaOUHB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vluwus0g5qvwt6iq9r83.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to create at least one origin pool. If you have already run a deployment, you can specify the sub-domain we created above for our GCP cluster:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T-H_PGP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ux97ya5keixx76g9hvbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T-H_PGP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ux97ya5keixx76g9hvbv.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will also be asked to define a health monitor. I chose a simple &lt;code&gt;GET&lt;/code&gt; to a &lt;code&gt;/build-info&lt;/code&gt; endpoint on the application, expecting a 200 response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M8_tttn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/g0kjdq4mz1ddaqdc73q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8_tttn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/g0kjdq4mz1ddaqdc73q3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your initial load balancer and GCP origin pool are created, we can move on to scripting the AWS integration that updates a second origin pool with the dynamic AWS ELB created on each deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating our Cloudflare origin pools on deployment
&lt;/h3&gt;

&lt;p&gt;As mentioned above, when using &lt;code&gt;kops&lt;/code&gt; in AWS it will create an ELB routed to the Kubernetes cluster automatically. Rather than setting up an AWS domain in Cloudflare, we will just use the one provided by Amazon. We will need to pass that along to Cloudflare. The ELB's name can be obtained using &lt;code&gt;kubectl get service&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mbXy0tj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9hzcm9n5ick5tx7nhijt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mbXy0tj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9hzcm9n5ick5tx7nhijt.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the ELB may not be immediately ready, we wrap that logic in a loop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t4mFdnIq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y12b9gblsis7qkhf2mwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t4mFdnIq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y12b9gblsis7qkhf2mwz.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result should be two healthy origin pools, running in separate cloud providers, all behind a single domain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a7UFXoJx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1k8dt2crfsor6lg22gbx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a7UFXoJx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1k8dt2crfsor6lg22gbx.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are using proxying and SSL enforcement on our top-level domain, so go ahead and check out &lt;a href="https://justademo.online"&gt;https://justademo.online/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This post explored the creation of a Docker application and deployment across multiple cloud providers. We used Google's native support for Kubernetes cluster, while in AWS we created our cluster from scratch. Finally, we used Cloudflare as a global load balancer and DNS provider, allowing us to achieve a multi-cloud deployment that is transparent to our end users. Please check out the &lt;a href="https://github.com/eddiewebb/circleci-multi-cloud-k8s"&gt;sample project&lt;/a&gt; with full sample code for everything covered in this post.&lt;/p&gt;

&lt;p&gt;Happy shipping!&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>tutorial</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Dockerizing Java apps with CircleCI and Jib</title>
      <dc:creator>Eddie Webbinaro</dc:creator>
      <pubDate>Tue, 02 Oct 2018 20:14:00 +0000</pubDate>
      <link>https://dev.to/circleci/dockerizing-java-apps-with-circleci-and-jib-2af8</link>
      <guid>https://dev.to/circleci/dockerizing-java-apps-with-circleci-and-jib-2af8</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is the first in a series that includes multi-cloud deployment behind a global DNS. It was originally posted on CircleCI's &lt;a href="https://circleci.com/blog/dockerizing-java-apps-with-circleci-and-jib/"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The evolution of deployment platforms and orchestration engines has been a tremendous accelerant for application and infrastructure teams alike. Clear boundaries and well defined interfaces between the layers of our technology stack means we can rapidly iterate and deploy with repeatable results. For many teams, Docker has become a key ingredient in this architecture, allowing for deployment to platforms like Kubernetes.&lt;/p&gt;

&lt;p&gt;Wrapping an application in Docker is a powerful way to enforce the correct dependencies and operating system. Unfortunately, it requires additional knowledge to properly configure and package the container images. In this blog post, I’ll discuss the use of Jib, an open source project from Google, which aims to simplify that effort for Java applications.&lt;/p&gt;

&lt;p&gt;We will be using several technologies in this blog and a basic understanding of CircleCI is required. If you’re new to CircleCI, we have &lt;a href="https://circleci.com/docs/2.0/basics/"&gt;introductory content&lt;/a&gt; to help you get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Jib?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Jib builds Docker and &lt;a href="https://github.com/opencontainers/image-spec"&gt;OCI&lt;/a&gt; images for your Java applications and is available as a plugin for &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin"&gt;Maven&lt;/a&gt; and &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin"&gt;Gradle&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Jib has a few interesting value propositions. They are described in more detail on their &lt;a href="https://github.com/GoogleContainerTools/jib"&gt;project page&lt;/a&gt;. Namely, it reduces the complexity and time required to turn a stand-alone Java application into a fully-portable Docker image. Our sample application is a Spring Starter web app, but the project supports any Java based application with great support for any required customizations. In addition to the core libraries, the team is sharing plugins for Maven and Gradle to integrate seamlessly into your existing build process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow along with this demo, you need an account with a Docker registry. I’ll be using Docker Hub, but many others are supported including Artifactory, Nexus, and GCR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our sample application
&lt;/h2&gt;

&lt;p&gt;I’m using a sample Java application from &lt;a href="http://start.spring.io/"&gt;Spring Initializer&lt;/a&gt;. I have shared the full project at &lt;a href="https://github.com/eddiewebb/circleci-jib-demo"&gt;https://github.com/eddiewebb/circleci-jib-demo&lt;/a&gt; if you just want to jump into the code or follow along. Before moving forward, confirm your application runs locally. For Spring Boot applications, this is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample project and blog post use the Maven plugin, but as noted above, Gradle is fully supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Jib
&lt;/h2&gt;

&lt;p&gt;Jib reduces the boilerplate configuration needed by setting some reasonable defaults that include a base distroless image. Jib will even infer the appropriate class to use as an entrypoint when starting your application.&lt;/p&gt;

&lt;p&gt;If you want to test locally, you can build right into your Docker daemon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean compile com.google.cloud.tools:jib-maven-plugin:0.9.7:dockerBuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OI59gbDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kq63q7k5u29euwsyi0tq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OI59gbDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kq63q7k5u29euwsyi0tq.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can spin it up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 8080:8080 java-jib-demo:0.0.1-SNAPSHOT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;8080&lt;/code&gt; is the default port for Spring Boot applications. It may vary based on your starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing Jib images to a registry
&lt;/h2&gt;

&lt;p&gt;One of the perks of using Jib is that we actually don’t need a Docker daemon. We can build and publish an image directly to a public/private registry. Since registries require authentication, let’s setup our Maven project to use our Docker Hub credentials. (Docker Hub is the default registry, see &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#configuration"&gt;Configuration Guide&lt;/a&gt; if you are using an alternate).&lt;/p&gt;

&lt;p&gt;In your Maven’s &lt;code&gt;settings.xml&lt;/code&gt; (typically found in &lt;code&gt;&amp;lt;HOME&amp;gt;/.m2/settings.xml&lt;/code&gt;), define a server block for the Docker Hub registry that includes your Docker username and password:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--absj0wv5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sbvbmx2yypsdxr93yqh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--absj0wv5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sbvbmx2yypsdxr93yqh9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting passwords in clear-text is never a good idea and certainly not something we want in our code repository. In the “Enabling CircleCI Deployments” section below, we will setup Maven Encryption.&lt;/p&gt;

&lt;p&gt;With credentials configured, the only other information you need to provide is the resulting Docker image name to use by passing &lt;code&gt;-Dimage&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let’s give is shot by saving the created image locally. For that we will use the &lt;code&gt;jib:build&lt;/code&gt; target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean compile com.google.cloud.tools:jib-maven-plugin:0.9.7:build &lt;span class="nt"&gt;-Dimage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eddiewebb/hello-spring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IQT32aIm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sai5pp7s86jdwbe8sweh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IQT32aIm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sai5pp7s86jdwbe8sweh.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the build completes, you will find a brand new image sitting in your registry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QKTwUsGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e7qdnormw0inkgv7rlw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QKTwUsGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e7qdnormw0inkgv7rlw6.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Jib
&lt;/h2&gt;

&lt;p&gt;With anything beyond trivial applications, you will need to make modifications to the generated image. Fortunately, Jib provides several &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#configuration"&gt;configuration parameters&lt;/a&gt; that can be dropped right into your &lt;code&gt;pom.xml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To keep some discipline around our versioning, we can’t release every image with the default “latest” tag. Using the &lt;code&gt;&amp;lt;to&amp;gt;&lt;/code&gt; element of our configuration we can fully specify the location and tagging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eMsGIGyT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/q0v457emjw7grhodbzyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eMsGIGyT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/q0v457emjw7grhodbzyl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The property &lt;code&gt;build.number&lt;/code&gt; is something we will pass in that correlates to the CircleCI build identifier. Add a default value to keep local development simple, i.e., &lt;code&gt;000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vL_tNnu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/btt23ziaeczfqoethyxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vL_tNnu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/btt23ziaeczfqoethyxi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice several other properties including the commit hash and workflow ID. These are just a few of the &lt;a href="https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables"&gt;environment variables made available to every CircleCI job&lt;/a&gt;. We will use them as additional properties that we pass into the application to display important build information from a running application. In order to set these values within the JVM, we will use another configuration block, &lt;code&gt;&amp;lt;jvmFlags&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DVk5YYmx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sn2d4y9frqo89onihpzj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DVk5YYmx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sn2d4y9frqo89onihpzj.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find additional configuration parameters explained on the project page.&lt;/p&gt;

&lt;p&gt;Let’s validate our configuration one last time before configuring CircleCI.&lt;/p&gt;

&lt;p&gt;Now, visit &lt;a href="http://localhost:8080/build-info"&gt;http://localhost:8080/build-info&lt;/a&gt; and you will see how the demo application exposes the additional JVM flags we passed in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ0XMFH5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/nfxnubrqisowvjgmfc7d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ0XMFH5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/nfxnubrqisowvjgmfc7d.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s use CircleCI to automate this process for repeatable and deterministic builds, enabling end-to-end traceability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypting Maven credentials
&lt;/h2&gt;

&lt;p&gt;The first thing to address is credential management. We’re not going to check any sensitive credentials into source code, but our CircleCI builds will need access to them. There are a few ways to solve this, and my example uses a combination of &lt;a href="https://maven.apache.org/guides/mini/guide-encryption.html"&gt;Maven Encryption&lt;/a&gt; and CircleCI Environment Variables.&lt;/p&gt;

&lt;p&gt;Encrypt a “master” password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nt"&gt;--encrypt-master-password&lt;/span&gt;
Master password: &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;type&lt;/span&gt;&lt;span class="sh"&gt; some random but lengthy string as input&amp;gt;&amp;gt;
{sqtg2346i10Hf2Z1u9bYgyDxooiIa6AXlBY92E5x+2dvqsCU7kI+iM9b8lI42Thh}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the results in a file named settings-security.xml in your Maven home directory, i.e. &lt;code&gt;~/.m2/settings-security.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aV_kkm2g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4dbbhonlzuo9bb25qzyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aV_kkm2g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4dbbhonlzuo9bb25qzyv.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Encrypt your Docker Registry password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nt"&gt;--encrypt-password&lt;/span&gt;
Password: &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;your&lt;/span&gt;&lt;span class="sh"&gt; Docker registry credentials&amp;gt;&amp;gt;
{9Z0In9ZySLsH7re5LlnGsvstLmfGfHL+7vi92maAXGiZ4oBP1iGwdoXR7QElP3TU}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update your settings.xml with the generated cipher:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EKzew0tV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y8qe7ga39xxchicqw3wr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EKzew0tV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y8qe7ga39xxchicqw3wr.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point you can run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean compile jib:build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;again to confirm the encrypted credentials are working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up CircleCI
&lt;/h2&gt;

&lt;p&gt;Add your project to CircleCI by visiting &lt;a href="https://circleci.com/dashboard"&gt;https://circleci.com/dashboard&lt;/a&gt; and following the prompts to “Start Building” your project’s repository.&lt;/p&gt;

&lt;p&gt;The first build will fail since we haven’t finished configuring the project. To get it passing, you will need to visit the project’s configuration page and add a variable named &lt;code&gt;maven_security_master&lt;/code&gt; that contains your master password from the previous steps. That variable is used by our &lt;a href="https://github.com/eddiewebb/circleci-jib-demo/blob/master/.circleci/config.yml#L56"&gt;&lt;code&gt;.circleci/config.yml&lt;/code&gt;&lt;/a&gt; to recreate the critical &lt;code&gt;settings-security.xml&lt;/code&gt; file in our builds.&lt;/p&gt;

&lt;p&gt;You will also want to copy your &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; to the projects &lt;code&gt;.mvn/wrapper/&lt;/code&gt; folder. It is important that both the &lt;code&gt;settings.xml&lt;/code&gt; and master password are made available to CircleCI to properly upload.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;settings.xml&lt;/code&gt; file in place, commit and push your latest changes to your repository. CircleCI should start building and successfully publish your Docker image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j-rFRuKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f93qdkblhrbk4ec5smp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j-rFRuKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f93qdkblhrbk4ec5smp9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once published, if you run our newly generated image you will see all the values we passed from CircleCI’s build environment exposed on the &lt;code&gt;/build-info&lt;/code&gt; url, giving your application end-to-end traceability!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NKUzYXMF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8yr3wda1x8i26nprcbku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKUzYXMF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8yr3wda1x8i26nprcbku.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’d like to take your CircleCI workflow to the next level, and start deploying your containerized application to ECS or Kubernetes, be sure to checkout our next blog post in the series and watch our previously recorded webinar with our Solutions Engineer Chris Black - &lt;a href="https://www.youtube.com/watch?v=eZxKs1mrxTM"&gt;Docker Deployments 102&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>github</category>
      <category>circleci</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
