Continuous Integration (CI) is often used in conjunction with test-driven development (TDD); however, CI servers often bring their own set of challenges: they are usually “snowflakes”, uniquely configured machines that are difficult to upgrade, re-configure, or re-install. [snowflakes]
In this blog post, we describe deploying a publicly-accessible, lean (1GB RAM, 1 vCPU, 15GB disk) Concourse CI server using a 350-line manifest. Upgrades/re-configurations/re-installs are as simple as editing a file and typing one command (bosh-init).
We must confess to sleight-of-hand: although we describe deploying a CI server, the worker is too lean to run any but the smallest tests. The deployed CI Server we describe can’t run large tests.
We will address that shortcoming in a future blog post where we describe the manual provisioning of local workers. The process isn’t difficult, but including it would have made the blog post undesirably long.
After we have completed this step, we have the information we need to populate our BOSH deployment’s manifest:
Although we created an AWS Security Group in the previous step, it doesn’t suit our purposes—we need to open the ports for HTTP (80) and HTTPS (443). We create a concourse Security Group via the Amazon AWS Console:
add the following rules:
|Type of Traffic||Protocol||Port Range||Source IP CIDR||Notes|
|SSH (22)||TCP (6)||22||0.0.0.0/0||debugging, agents|
|HTTP (80)||TCP (6)||80||0.0.0.0/0||redirect|
|HTTPS (443)||TCP (6)||443||0.0.0.0/0||web|
|Custom TCP Rule||TCP (6)||2222||0.0.0.0/0||agents|
|Custom TCP Rule||TCP (6)||6868||0.0.0.0/0||bosh-init|
We decide to use HTTPS to communicate with our Concourse server, for we will need to authenticate against the webserver when we configure our CI (when we transmit our credentials over the Internet we want them to be encrypted).
We purchase valid SSL certificates for our server [Let’s Encrypt] . Using a self-signed certificate is also an option.
We use the following command to create our key and CSR. Note that you should substitute your information where appropriate, especially for the CN (Common Name), i.e. don’t use ci.blabbertabber.com.
openssl req -new \ -keyout ci.blabbertabber.com.key \ -out ci.blabbertabber.com.csr \ -newkey rsa:4096 -sha256 -nodes \ -subj '/C=US/ST=California/L=San Francisco/O=blabbertabber.com/OU=/CN=ci.blabbertabber.com/emailAddressemail@example.com'
We submit the CSR to our vendor, authorize the issuance of the certificate, and receive our certificate, which we will place in our manifest (along with the key and the CA certificate chain).
We configure a DNS A record for our concourse server to point to our AWS Elastic IP. We have the following line in our blabbertabber.com zone file:
ci.blabbertabber.com. A 188.8.131.52
We create a private ssh key for our remote worker:
ssh-keygen -P '' -f ~/.ssh/worker_key
We will use the public key in the next step, when we create our BOSH manifest.
We create the BOSH manifest for our Concourse server by doing the following:
For those interested, our sample Concourse manifest was derived from Concourse’s official sample bosh-init manifest and modified as follows:
We install bosh-init by following these instructions.
We use bosh-init to deploy Concourse using the manifest we created in the previous step. In the following example, our manifest is named concourse-aws.yml:
bosh-init deploy concourse-aws.yml ... Finished deploying (00:12:15) Stopping registry... Finished (00:00:00) Cleaning up rendered CPI jobs... Finished (00:00:00)
A deployment takes ~12 minutes.This gist contains the complete output of the bosh-init deployment.
We browse to https://ci.blabbertabber.com.
We download the
fly CLI by clicking on the Apple icon (assuming that your workstation is an OS X machine) and move it into place:
install ~/Downloads/fly /usr/local/bin
We follow Concourse’s Getting Started
instructions to create our first pipeline. We
tags [ "micro" ] to the sample Concourse pipeline
so that the job is run on our “micro” worker (in
our BOSH manifest, we tag the worker that
is colocated on our t2.micro Concourse
server “micro” so that we can steer small jobs
cat > hello-world.yml <<EOF jobs: - name: hello-world plan: - task: say-hello config: platform: linux image: "docker:///ubuntu" tags: [ "micro" ] run: path: echo args: ["Hello, world!"] EOF
We configure the pipeline (remember to substitute the username and password in the manifest, jobs.properties.atc.basic_auth_username and jobs.properties.atc.basic_auth_password, for “user:password” below):
fly -t "https://user:firstname.lastname@example.org" set-pipeline -p really-cool-pipeline -c hello-world.yml
You can see the gist of the output here.
Type y when prompted to apply the configuration.
Refresh https://ci.blabbertabber.com to see our newly-created pipeline:
Next we unpause the job
We kick off our job:
We see that the job completes successfully by the pea-green color. We click “>_ say-hello” to see the output:
We have demonstrated with the ease with which one can deploy a CI server using a combination of Concourse and bosh-init, a deployment which takes less than a quarter hour from start (no disk, no OS) to finish (a publicly-accessible, up-and-running CI server) and which is easily re-deployed.
We recognize that our deployment is incomplete, that it lacks the workers necessary to run jobs of any consequence. We will describe how to manually provision workers in our next blog post.
One of the benefits of the Concourse/bosh-init combination is that Concourse stores its state on a persistent disk, so that re-deploying the CI server (e.g. new OS, new Concourse) won’t cause the loss of the pipeline configuration or build history.
The yearly cost of running a Concourse server is $80.34. Note that this does not include the cost of the worker. Had we chosen to implement the recommended m3.large EC2 instance for a worker, it would have increased our yearly cost by $713.54 [m3.large] .
Here are our costs:
|Expense||Vendor||Cost||Cost / year|
|ci.blabbertabber.com cert||cheapsslshop.com||$14.85 3-year [inexpensive-SSL]||$4.95|
|EC2 t2.micro instance||Amazon AWS||$0.0086 / hour [t2.micro]||$75.39|
[snowflakes] Even the most innocuous changes to a CI server can be fraught with anxiety: two years ago when we were migrating one of our development team’s Jenkins CI server VM from one datastore to another (a very low-risk operation), we needed to have several meetings with the Team’s product manager and the anchor before they were willing to allow us to proceed with the migration.
[AWS Tooling] We appreciate that creating the AWS infrastructure (VPC, Elastic IP, Key Pair) is tedious and a bit of a clickfest. We’re working to make this much easier, soon. Per Rob Dimsdale, “the MEGA team is actively working on tooling to improve the user-experience of creating the AWS stack for Concourse, but we’re not ready for public consumption of that tooling just yet.” Stay tuned.
[Let’s Encrypt] Let’s Encrypt is a “free, automated, and open” Certificate Authority which issues valid SSL certificates free of charge. We are eagerly awaiting its launch, which hopefully will happen within the next few weeks.
[inexpensive-SSL] One shouldn’t pay more than $25 for a 3-year certificate. We used SSLSHOP to purchase our Comodo Positive SSL, but there are many good SSL vendors, and we don’t endorse one over the other.