Jericho's blog

Deploying my blog with ansible

ansible server_stuff 2023-10-08 01:36:31.49474814 +0000

I've recently been making an effort to migrate my server stack to use ansible to manage everything. So I wanted to see if I could compile and deploy my blog using just ansible. (spoiler: I can)

Overview

Turns out if you approach it the correct way, it's pretty easy. First I made a Dockerfile which first installs cobalt, then builds my site, and finally uses nginx to actually serve the static files. After that, I used ansible to clone my blog's repo , build the docker image, and deploy it.

Creating the Dockerfile

I broke my Dockerfile into 2 sections. The first section (builder) installs cobalt and builds my blog.

FROM rust:1.73 AS builder

RUN cargo install cobalt-bin
COPY . /src
WORKDIR /src
RUN cobalt build

The second section copies the built files from the builder section, and uses nginx to serve the content.

FROM nginx
COPY --from=builder /src/_site /usr/share/nginx/html

In the end, I wound end with this dockerfile.

Using ansible

Now that I had an easy way to build a docker image, I just needed to automate that build process. Since I host my repos on GitLab I could've set up a seperate CI/CD pipeline that would push my docker image to GitLab's container registry. However as my docker image would also include all my static content, I don't really want to push the image to any registry if I can avoid it.

Since I'm already using ansible to deploy my existing services, I decided I should just try to use ansible. It ended up being simpler than expected.

Build the image

Building the docker image basically just boils down to two steps. First, I clone my blog repo to get the content and Dockerfile. Second, build the image.

Cloning my repo was very simple thanks to the ansible.builtin.git module.

- name: Pull blog repo
  ansible.builtin.git:
    dest: "your_dest_dir"
    repo: "ssh://git@your.git/repo/url"
    clone: true
    accept_hostkey: true
    single_branch: true
    version: master
  register: _blog
  • dest sets where to clone the repo to. I chose to use a sub-directory of a directory where I store various config files for my other services, but you could also clone it into a temporary directory
  • repo is the URL to your git repo. I'd recommend using a ssh:// URL instead of https://, especially if your repo is private
  • clone just tells ansible that you want to clone the repo if there's not a repo at that dest
  • accept_hostkey just tells ansible/SSH to be fine with whatever SSH hostkey the repo returns. This is useful if you're deploying to a new server that hasn't connected to your git provider before, but could potentially be dangerous
  • single_branch tells ansible to only clone one branch which saves time and bandwith versus downloading the whole repo
  • version tells anisble which branch to clone

Then building the image was accomplished thanks to the community.docker.docker_image module.


- name: Build docker image
  community.docker.docker_image:
    build:
      path: "your_dest_dir"
      pull: true
    name: blog
    force_source: "{{ _blog.changed }}"
    source: build
    tag: latest

  • build.path should be the same as the dest option before
  • build.pull tells ansible to pull the latest images for each image in your Dockerfile. You can feel free to disable that though
  • name will be the name of the docker image
  • source forces ansible to build the image instead of pulling it or loading it from a local file
  • force_source is needed as otherwise ansible will only build the image if it doesn't exist
  • tag sets the image tag. It defaults to latest so you can omit that option

Deployment

Then finally I deploy my blog as a normal docker container thanks to the community.docker.docker_container module.

- name: Deploy blog
  community.docker.docker_container:
    name: blog
    image: blog:latest