{"id":2164,"date":"2015-08-30T03:00:00","date_gmt":"2015-08-30T10:00:00","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2015\/08\/30\/containerized-ci-with-concourse-on-azure\/"},"modified":"2020-03-18T19:43:54","modified_gmt":"2020-03-19T02:43:54","slug":"containerized-ci-with-concourse-on-azure","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/containerized-ci-with-concourse-on-azure\/","title":{"rendered":"Containerized CI with Concourse on Azure"},"content":{"rendered":"<h3 id=\"whats-concourse\">What\u2019s Concourse?<\/h3>\n<p><a href=\"http:\/\/concourse.ci\">Concourse CI<\/a> is a unique CI application where the concept of Pipelines is first class throughout the entire process. Concourse allows you to create more complex build systems through a series of input and output resources with each step defined by a task manifest and running in its own container.<\/p>\n<p>The real advantages to Concourse are the out of the box support of containerized pipeline steps which prevents any kind of configuration pollution between steps as well as its ability to deploy highly scalable solutions suitable for large application development.<\/p>\n<h3 id=\"the-problem\">The Problem<\/h3>\n<p>You may have heard of the <a>recent announcement of Cloud Foundry Support on Microsoft Azure<\/a>. <a href=\"https:\/\/azure.microsoft.com\/en-us\/blog\/general-availability-of-cloud-foundry-and-preview-access-of-pivotal-cloud-foundry\/\">Cloud Foundry<\/a> is an open source PaaS that is deployed by a deployment management tool called <a href=\"https:\/\/bosh.cloudfoundry.org\/\">BOSH<\/a>. BOSH works by using Cloud Platform Integration (CPI) packages to handle the IaaS details of each cloud provider. In order to have Cloud Foundry on Azure, you need to be able to support BOSH deployments on Azure which requires an Azure CPI package.<\/p>\n<p>Since Cloud Foundry is used by some of the largest enterprises in the world, it\u2019s essential to support a Continuous Integration process for the CPI package. This ensures further code changes to the CPI won\u2019t regress future Cloud Foundry deployments on Azure.<\/p>\n<p>The kind of testing needed for the CPI package needs to be quite exhaustive and must be end to end. In order to do this, we need to support the following Continuous Integration Steps:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>Build the CPI Package<\/li>\n<li>Deploy the Initial Azure Infrastructure for BOSH<\/li>\n<li>Deploy the BOSH Director with the Azure CPI Package<\/li>\n<li>Run the BOSH Acceptance Test Suite Against the BOSH Director<\/li>\n<li>Publish the Passed CPI Build to a git Branch<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>We partnered with Pivotal, the maintainers of Cloud Foundry, to create a CI pipeline that can test the CPI\u2019s functionalities with high confidence. This enables the open source Cloud Foundry community with continuous updates for Cloud Foundry on Azure as well as support for enterprises who are using Cloud Foundry on Azure to deploy applications and services.<\/p>\n<h3 id=\"the-solution\">The Solution<\/h3>\n<p>Because the build process required is quite complex, with very distinct parts, we decided to use <a href=\"https:\/\/concourse.ci\">Concourse CI<\/a> to automate the build with a series of well-defined, containerized, and isolated steps. This isolation means that system changes made in one container won\u2019t \u201cpollute\u201d settings in another container allowing for a clean and well-known state at each build step.<\/p>\n<h4 id=\"concourse-resources\">Concourse Resources<\/h4>\n<p>Between each step, the state of the build is stored off into <a href=\"http:\/\/concourse.ci\/implementing-resources.html\">Concourse Resources<\/a>, which can be anything from a <a href=\"https:\/\/github.com\/concourse\/git-resource\">git repository<\/a>, a <a href=\"https:\/\/github.com\/concourse\/semver-resource\">semantic version number<\/a>, to an <a href=\"https:\/\/github.com\/concourse\/s3-resource\">S3 Bucket<\/a>. Resources are used as inputs and outputs between each step allowing each concourse <code class=\"highlighter-rouge\">Task<\/code> to \u201cconnect\u201d to one another by taking the output of one task and feeding it as the input to another. Concourse Resources implement an interface specification which allows for it to be used by Concourse CI.<\/p>\n<p>A Concourse deployment can run locally using Vagrant and can be deployed to any infrastructure that supports BOSH. In the spirit of dog-fooding, we deployed Concourse to Azure using the very same Azure CPI package we were testing. This allowed us to actually use the CPI as well as test it in an automated fashion.<\/p>\n<p>Concourse does a great job at visualizing your build pipeline using an easy-to-understand block diagram with resources and build tasks connected via input and output lines. This easily allows you to see the real-time status of your build and to re-run any discrete step.<\/p>\n<p>You can see the Bosh Azure CPI Release CI Pipeline below. It is composed of 6 discrete and isolated tasks.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-10-17-Containerized-CI-Concourse-Azure-ss1.gif\" alt=\"Animation of CI Pipleine\" \/><\/p>\n<p>Each black block with lines coming in and out is a Concourse Resource, and each green block is a <a href=\"http:\/\/concourse.ci\/running-tasks.html\">Concourse Task<\/a>. The entire pipeline is described by a YAML file, which describes each task as well as its input and output resources. If you\u2019re curious about the details of this pipeline as defined by its YAML, you can checkout the <a href=\"https:\/\/github.com\/Azure\/bosh-azure-cpi-release\/blob\/master\/ci\/pipeline.yml\">actual CI pipeline YAML file here<\/a>.<\/p>\n<h4 id=\"build-tasks\">Build Tasks<\/h4>\n<p>If you look closer at our CI pipeline definition, you will notice our <a href=\"https:\/\/github.com\/Azure\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/run-bats.yml#L3\">CI tasks refer to a Docker image<\/a>.<\/p>\n<h5 id=\"container\">Container<\/h5>\n<p>As we mentioned earlier, each build step is executed in its own container, specified by an image hosted in a Docker registry. Concourse actually runs containers with <a href=\"https:\/\/github.com\/cloudfoundry-incubator\/garden-linux\">garden-linux<\/a>, which is compatible with <a href=\"https:\/\/www.opencontainers.org\/\">Open Container Specification<\/a> images. For all intents and purposes, this is an implementation detail and your container will run exactly as you would expect it to run if you ran it with Docker.<\/p>\n<p>To understand details about that container, take a look at <a href=\"https:\/\/hub.docker.com\/r\/sedouard\/azure-cpi-release\/\">our image repository<\/a>.<\/p>\n<h5 id=\"build-task-definition\">Build task definition<\/h5>\n<p>Build tasks are defined by a simple YAML structure similar to this:<\/p>\n<pre><code class=\"language-YAML\">---\r\nplatform: linux\r\nimage: docker:\/\/\/sedouard\/azure-cpi-release\r\n**Inputs:**\r\n  - name: bosh-cpi-release\r\n  - name: version-semver\r\nrun:\r\n  path: bosh-cpi-release\/ci\/tasks\/build-candidate.sh\r\n\r\n<\/code><\/pre>\n<p>This definition contains several key components for this build task:<\/p>\n<ul>\n<li>Reference to the Docker image to use for this step<\/li>\n<li>Inputs to use that are described in the main pipeline\u2019s YAML file<\/li>\n<li>Reference to the script file to execute in this step<\/li>\n<\/ul>\n<p>Below are quick overviews of each build step, what it does, and what it produces. A link is provided to the actual definition in code for each step.<\/p>\n<h6 id=\"build-candidate\">Build-Candidate<\/h6>\n<p>Code <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/build-candidate.yml\">available on GitHub<\/a><\/p>\n<p><strong>Inputs:<\/strong><\/p>\n<ul>\n<li><strong>version-semver<\/strong> &#8211; The semantic version of this build<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from<\/li>\n<\/ul>\n<p><strong>What it does:<\/strong><\/p>\n<p>Builds the BOSH release candidate using a <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/build-candidate.sh\">series of standard steps<\/a> specific to creating a BOSH release.<\/p>\n<p><strong>Outputs:<\/strong><\/p>\n<ul>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball<\/li>\n<li><strong>version-semver<\/strong> &#8211; The same semantic version of the build passed as an input<\/li>\n<\/ul>\n<h6 id=\"azure-provision\">Azure-Provision<\/h6>\n<p>Code <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/azure-provision.yml\">available on GitHub<\/a><\/p>\n<p><strong>Inputs:<\/strong><\/p>\n<ul>\n<li><strong>version-semver<\/strong> &#8211; The semantic version of this build<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from<\/li>\n<\/ul>\n<p><strong>What it does:<\/strong><\/p>\n<p>Provisions the basic azure infrastructure required to deploy BOSH-managed infrastructure on Azure. This mainly includes a VNet, two subnets, a resource group, a storage account, and two public IP addresses. All the gritty details of how we extract the deployment information from Azure using the <a href=\"https:\/\/npmjs.org\/azure-cli\">CLI<\/a> can be found in this task\u2019s <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/azure-provision.sh\">shell script<\/a>.<\/p>\n<p><strong>Outputs:<\/strong><\/p>\n<ul>\n<li><strong>azure-exports<\/strong> &#8211; A generated script file that includes the public IP addresses to use for Cloud Foundry and the BOSH director. This also includes specific details on connecting to the created Azure Storage account<\/li>\n<\/ul>\n<h6 id=\"deploy-director\">Deploy-Director<\/h6>\n<p>Code <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/deploy.yml\">available on GitHub<\/a><\/p>\n<p><strong>Inputs:<\/strong><\/p>\n<ul>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball<\/li>\n<li><strong>version-semver<\/strong> &#8211; The semantic version of this build<\/li>\n<li><strong>azure-exports<\/strong> &#8211; A generated script file that includes the public IP addresses to use for Cloud Foundry and the BOSH director<\/li>\n<li><strong>bosh-init<\/strong> &#8211; The bosh-init tarball for Linux<\/li>\n<li><strong>bosh-release<\/strong> &#8211; The BOSH release tarball to use for the director<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from<\/li>\n<li><strong>ubuntu-director-state-file<\/strong> &#8211; A file that records the current deployment state of the director &#8211; to enable re-runs by deleting and re-provisoning the director on the same azure resource group deployment<\/li>\n<\/ul>\n<p><strong>What it does:<\/strong><\/p>\n<p>Uses the <code class=\"highlighter-rouge\">bosh-init<\/code> CLI to deploy a rendered <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/deploy.sh#L46\">manifest file template<\/a> that describes the virtual machines and networking infrastructure to have a BOSH director capable of deploying BOSH releases.<\/p>\n<p>The <code class=\"highlighter-rouge\">deploy-director<\/code> step uses the <code class=\"highlighter-rouge\">azure-exports<\/code> input file created as a result of the completion of the <code class=\"highlighter-rouge\">azure-provision<\/code> step. With the <code class=\"highlighter-rouge\">azure-exports<\/code> input file, the public IP address and storage account keys provisioned in the previous step is automatically injected. This information will be used to provision the BOSH director.<\/p>\n<p><strong>Outputs:<\/strong><\/p>\n<ul>\n<li><strong>ubuntu-director-state-file<\/strong> &#8211; The file that represents the current deployment state of the director. Used by any future re-runs of the <code class=\"highlighter-rouge\">Deploy-Director<\/code> step.<\/li>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball &#8211; passes this along from the input<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from &#8211; passes this along from inputs<\/li>\n<\/ul>\n<h6 id=\"run-bats\">Run-Bats<\/h6>\n<p>Code <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/run-bats.yml\">available on GitHub<\/a><\/p>\n<p><strong>Inputs:<\/strong><\/p>\n<ul>\n<li><strong>azure-exports<\/strong> &#8211; A generated script file that includes the public IP addresses to use for Cloud Foundry and the BOSH director<\/li>\n<li><strong>azure-ubuntu-stemcell<\/strong> &#8211; The base image to use for VMs of any BOSH deployment on Ubuntu. This includes the VM agent for Azure.<\/li>\n<li><strong>bosh<\/strong> &#8211; The official BOSH Repo &#8211; used to run BATs<\/li>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball for this build<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from<\/li>\n<\/ul>\n<p><strong>What it does:<\/strong><\/p>\n<p>Runs the standard set of BOSH Acceptance Tests (BATs) against the BOSH director. This runs a series of steps such as <code class=\"highlighter-rouge\">bosh deployment<\/code>, <code class=\"highlighter-rouge\">bosh deploy<\/code>, verification of the state of the BOSH director, and verification of deployments after each command. This task is triggered by the successful completion of the <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/deploy.yml\">Deploy-Director<\/a> task.<\/p>\n<p><strong>Outputs:<\/strong><\/p>\n<ul>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball &#8211; passed along from input<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from &#8211; passed along from input<\/li>\n<\/ul>\n<h6 id=\"promote-candidate\">Promote Candidate<\/h6>\n<p>Code <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/promote-candidate.yml\">available on GitHub<\/a><\/p>\n<p><strong>Inputs:<\/strong><\/p>\n<ul>\n<li><strong>bosh-cpi-dev-artifacts<\/strong> &#8211; The current BOSH release tarball &#8211; passes this along from the input<\/li>\n<li><strong>bosh-cpi-release-in<\/strong> &#8211; The git repository of the CPI to create the BOSH release from &#8211; passes this along from inputs<\/li>\n<\/ul>\n<p><strong>What it does:<\/strong><\/p>\n<p>Promote Candidate will be triggered by a successful completion of the <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/run-bats.yml\">Run-Bats<\/a> task. It will take the current target git branch within <code class=\"highlighter-rouge\">bosh-cpi-release-in<\/code>, deploy the promoted build of the CPI to S3, and publish the current state of the branch to a new release branch. You can check out the detailed steps in the <a href=\"https:\/\/github.com\/sedouard\/bosh-azure-cpi-release\/blob\/master\/ci\/tasks\/promote-candidate.sh\">shell script<\/a>.<\/p>\n<p><strong>Outputs:<\/strong><\/p>\n<ul>\n<li><strong>bosh-cpi-release-out<\/strong> &#8211; The promoted BOSH release package<\/li>\n<\/ul>\n<h2 id=\"a-complete-end-to-end-ci-system\">A Complete End to End CI System<\/h2>\n<p>The above steps comprise the full end-to-end pipeline steps that are required to validate the Azure CPI similarly to how an end user would use it.<\/p>\n<p>Pivotal will continue to use this pipeline to support the Azure CPI and BOSH deployments on Azure. If you\u2019re wondering how you can use BOSH to deploy Cloud Foundry on Azure, <a href=\"\/developerblog\/2015\/10\/28\/cloud-foundry-elastic-containerized-applications-on-azure\/\">you should head over to our post about that topic<\/a>.<\/p>\n<h2 id=\"getting-started-with-concourse-ci\">Getting Started with Concourse CI<\/h2>\n<p>The great thing about this collaboration is that <strong>you too<\/strong> can create a scalable, CI system that\u2019s completely open source. We have <a href=\"https:\/\/github.com\/concourse\/concourse\/pull\/174\">collaborated<\/a> with the Concourse CI maintainers to create <a href=\"https:\/\/github.com\/Azure\/azure-quickstart-templates\/tree\/master\/concourse-ci\">the Azure Documentation for Concourse CI<\/a>.<\/p>\n<p>These instructions will walk you through creating your own infrastructure, BOSH director, and deploying Concourse to Azure IaaS. You\u2019ll be able to scale this deployment with as many VMs as you need for your CI workload needs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Creating a CI pipeline to support the Azure CPI and BOSH deployments on Azure using Concourse CI to automate the build with a series of well-defined, containerized, and isolated steps.<\/p>\n","protected":false},"author":21345,"featured_media":12791,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[16],"tags":[60,118,128],"class_list":["post-2164","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-azure","tag-cloud-foundry","tag-concourse-ci"],"acf":[],"blog_post_summary":"<p>Creating a CI pipeline to support the Azure CPI and BOSH deployments on Azure using Concourse CI to automate the build with a series of well-defined, containerized, and isolated steps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21345"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2164"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2164\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/12791"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}