Published on

Using Drone CI to Build a Jekyll Site and Deploy to Docker Swarm



CICD Pipelines! ❤️

In this post I will show you how to setup a cicd pipeline using drone to build a jekyll site and deploy to docker swarm.

Environment Overview

Jekyll's Codebase: Our code will be hosted on Github (I will demonstrate how to set it up from scratch)

Secret Store: Our secrets such as ssh key, swarm host address etc will be stored in drones secrets manager

Docker Swarm: Docker Swarm has Traefik as a HTTP Loadbalancer

Drone Server and Agent: If you dont have drone, you can setup drone server and agent on docker or have a look at


* Whenever a push to master is receive on github, the pipeline will be triggered
* The content from our github repository will be cloned to the agent on a container
* Jekyll will build and the output will be transferred to docker swarm using rsync
* The docker-compose.yml will be transferred to the docker swarm host using scp
* A docker stack deploy is ran via ssh

Install Jekyll Locally

Install Jekyll locally, as we will use it to create the initial site. I am using a mac, so I will be using brew. For other operating systems, have a look at this post.

I will be demonstrating with a weightloss blog as an example.

Install jekyll:

$ brew install jekyll

Go ahead and create a new site which will host the data for your jekyll site:

$ jekyll new blog-weightloss

Create a Github Repository

First we need to create an empty github repository, in my example it was Once you create the repo change into the directory created by the jekyll new command:

$ cd blog-weightloss

Now initialize git, set the remote, add the jekyll data and push to github:

$ git init
$ git remote add origin # <== change to your repository
$ git add .
$ git commit -m "first commit"
$ git push origin master

You should see your data on your github repository.

Create Secrets on Drone

Logon to the Drone UI, sync repositories, activate the new repository and head over to settings where you will find the secrets section.

Add the following secrets:

Secret Name: swarm_host
Secret Value: ip address of your swarm

Secret Name: swarm_key
Secret Value: contents of your private ssh key

Secret Name: swarm_user
Secret Value: the user that is allowed to ssh

You should see the following:


Add the Drone Config

Drone looks from a .drone.yml file in the root directory for instructions on how to do its tasks. Lets go ahead and declare our pipeline:

$ vim .drone.yml

And populate the drone config:

    image: jekyll/jekyll:latest
      - touch Gemfile.lock
      - chmod a+w Gemfile.lock
      - chown -R jekyll:jekyll /drone
      - gem update --system
      - gem install bundler
      - bundle install
      - bundle exec jekyll build

    image: drillster/drone-rsync
      from_secret: swarm_host
      from_secret: swarm_key
      from_secret: swarm_user
    source: ./*
    target: ~/
    recursive: true
    delete: true
      branch: [master]
      event: [push]

    image: appleboy/drone-scp
      from_secret: swarm_host
      from_secret: swarm_user
      from_secret: swarm_key
    target: /root/
      - docker-compose.yml
      branch: [master]
      event: [push]

    image: appleboy/drone-ssh
      from_secret: swarm_host
      from_secret: swarm_user
      from_secret: swarm_key
    port: 22
      - docker stack deploy --prune -c /root/ apps
      branch: [master]
      event: [push]


If you want to be notified about your builds, you can add a slack notification step as the last step.

To do that, create a new webhook integration, you can follow this post for a step by step guide. After you have the webhook, go to secrets and create a slack_webhook secret.

Then apply the notification step as shown below:

    image: plugins/slack
      from_secret: slack_webhook
    channel: system_events
    template: >
      {{#success build.status}}
        [DRONE CI]: *{{ uppercase build.status }}* : {{ repo.owner }}/{{ }}
        ({{ build.branch }} - {{ truncate build.sha 8 }} | {{ }})

        [DRONE CI]: *{{ uppercase build.status }}* : {{ repo.owner }}/{{ }}
        ({{ build.branch }} - {{ truncate build.sha 8 }} | {{ }})

Based on the status, you should get a notification similar like this:


Add the Docker Compose

Next we need to declare our docker compose file which is needed to deploy our jekyll service to the swarm:

$ vim docker-compose.yml

And populate this info (just change the values for your own environment/settings):

version: '3.5'

    image: ruanbekker/jekyll:contrast
    command: jekyll serve --watch --force_polling --verbose
      - appnet
      - /root/
      mode: replicated
      replicas: 1
        - "traefik.backend.loadbalancer.sticky=false"
        - "traefik.backend.loadbalancer.swarm=true"
        - "traefik.backend=myweightlossblog"
        - ""
        - "traefik.entrypoints=https"
        - "traefik.frontend.passHostHeader=true"
        - ","
        - "traefik.port=4000"
        parallelism: 2
        delay: 10s
        condition: on-failure
          - node.role == manager
    external: true

Push to Github

Now we need to push our .drone.yml and docker-compose.yml to github. Since the repository is activated on drone, any push to master will trigger the pipeline, so after this push we should go to drone to look at our pipeline running.

Add the untracked files and push to github:

$ git add .drone.yml
$ git add docker-compose.yml
$ git commit -m "add drone and docker config"
$ git push origin master

As you head over to your drone ui, you should see your pipeline output which will look more or less like this (just look how pretty it is! :D )


Test Jekyll

If your deployment has completed you should be able to access your application on the configured domain. A screenshot of my response when accessing Jekyll:


Absolutely Amazingness! I really love drone!

Thank You

Thanks for reading, if you like my content, feel free to check out my website, and subscrube to my newsletter or follow me at @ruanbekker on Twitter.