So.

For my 50th note, I though I’d finally spend some time trying to figure out how to deploy this blog automatically instead of manually running an Ansible script every time. After an hour or so, I came up with a pretty simple solution.

Have you heard of Bitbucket Pipelines? It’s a pretty great CI/CD pipeline by Atlassian that’s integrated into Bitbucket. The idea is very simple. You just add a bitbucket-pipelines.yml file in the root of your git repo, place some deployment instructions in it, and Bitbucket will launch a new Docker container on the next push and run those instructions. These instructions could be pretty much anything, from running test cases to deploying code to remote servers, etc.

Pipelines has a very basic feature set, but they’re pretty useful. Here’s some of the basic stuff we’ll be using:

So let’s get started.

Enabling Pipelines in Bitbucket

First, go to the Settings page of your repo in Bitbucket. The link should be somewhere on the left sidebar. Once there, find Settings under the Pipelines section in the sub-menu that opens up. On the new page, you’ll find just one button which says Enable Pipelines. Let’s activate that.

Enabling Bitbucket Pipelines for your repository.
Enlarge Enabling Bitbucket Pipelines for your repository.

Setting Environment Variables

Next, head to the Environment variables section in the same sub-menu. Here you can add key-value pairs that are going to be available for use in the Docker container using the $ symbol. Let’s define a variable with the name PRODUCTION_HOST and the value of the domain/IP of the machine we want to deploy our code on. Make sure to check Secure to ensure the variable is encrypted. Hit Add when you’re done.

Setting the environment variables for bitbucket-pipelines.yml file.
Enlarge Setting the environment variables for bitbucket-pipelines.yml file.

Configuring SSH Keys

Let’s head to the SSH Keys section. The link is in the same sub-menu. On this page we’ll do two things: create a new SSH key-pair to use for deployment, and add the host address and fingerprint of our target machine so we can deploy securely. The process is pretty straight-forward. You can use the interface to generate a new key-pair. Bitbucket will place the new private key in the container it launches for deployment, and you should place the public key on the remote machine. That way we’ll be able to securely establish an SSH connection between our Docker container and the remote machine without any additional configuration in the container itself. Also, add the host address of the target machine in the Host address section below. It will fetch the fingerprint of the target machine and load it in the known_hosts file in the container, to verify that the container knows the target machine. Note that the domain/IP should be the same as the one you defined in PRODUCTION_HOST variable above, since that’s the variable we’ll use to establish a connection.

Creating the bitbucket-pipelines.yml file

Once the above configuration is done, go ahead and create a bitbucket-pipelines.yml file in the root of your git repo. Place the following content in it:

image: jekyll/builder:latest

pipelines:
  default:
    - step:
        script:
          - jekyll build
          - rsync -a _site/ root@$PRODUCTION_HOST:/var/www/ --exclude=bitbucket-pipelines.yml --exclude=deploy --exclude=Vagrantfile --chown=www-data:www-data

Save the file and commit, but don’t push yet. Let’s go over the file before we do that.

Pipelines has syntax available for running different commands on the push of different branches. So depending on whether staging, production, or feature_x branch was push-ed, you could run different commands and deploy in different ways. Since we haven’t specified anything, the above file will run commands when we push any and all branches.

Watching It Work

Once the above is done, push your branch to Bitbucket. Head to the Pipelines link of your repo in the sub-menu, and you should see it all in action. Once successfully deployed, you’ll see a page like this:

Watching the magic happen. A successful deployment using Bitbucket Pipelines.
Enlarge Watching the magic happen. A successful deployment using Bitbucket Pipelines.

And that’s it! What we just did was automate the build and deploy process of our website. Pipelines has a lot of other interesting options, and can do a lot more than the simple task we accomplished. Please remember that Pipelines offers 50 minutes of build time on the free account, but even after that its not very expensive. Pipelines is a good way to get a CI/CD setup for free and have an easier life by letting Bitbucket take care of deployments for you. Pipelines will also send you emails when deployments fail.

I’m writing this note in Evernote right now. I’ll be commit-ing and push-ing it soon. If you’re reading this right now, it means it all went fine. For some reason I’m getting a message-in-a-bottle feeling right now. Fingers crossed 😃

Resources