Budiman JoJo

Life Journey of My Geeky Needs.

How I GitOps Home Assistant Configurations

2021-11-04 4 min read Kubernetes Linux Self Hosted Budimanjojo

home assistant gitops

I always love the idea of GitOps, where everything I have in a git repo represents the current state of my application. But not everything are made for GitOps, so we have to sort of “make it work”. In this post, I will show you how I manage to GitOps my Home Assistant configurations. Spoiler, this is hacky and messy at the same time, so please bear this in mind before continuing.

My Setup

I deployed my Home Assistant in a Kubernetes cluster that I manage using Flux. The /config directory is stored in a Rook Ceph provisioned PVC. The yaml files can be seen here. Another thing to keep in mind is that I use the official Home Assistant container image which has git installed in the container by default. This is important because you will need that command in your container.

Concept

Actually this wasn’t what I have in mind before. I was thinking about using a Git hooks that will push the changes into my Home Assistant and do a restart call of my HAss deployment using kubectl. This was the only way I have in mind to achieve this, and it looks weird. Until alex told me how he did it in k8s-at-home Discord channel (this is a great place to discuss everything Kubernetes, come join us!).

So here’s how I ended up doing. Instead of pushing the changes into the container, I make an automation in Home Assistant to pull the changes instead. This can be achieve using the webhook automation trigger. You might ask what trigger the webhook to Home Assistant, and the answer is Github. Using this awesome Github Action, I can send a webhook to Home Assistant whenever I push a commit into Github.

Detailed Steps

Before doing anything, I “exec” into the Home Assistant container and setup the remote repo in the /config directory. After that, everything else should be done outside of the container. In my repository, I have this workflow:

name: Deploy Config

on:
  push:
    branches: [ '*' ]

jobs:
  deploy_config:
    runs-on: ubuntu-latest
    steps:
      - uses: joelwmale/[email protected]
        with:
          url: ${{ secrets.HASS_WEBHOOK_URL }}/update_config
          body: '{}'

The url is a Github secret which should be http(s)://<your-hass-domain>/api/webhook/<webhook_id>, notice that I have update_config as the webhook id. What the above workflow does is it will send a webhook to your Home Assistant whenever you do a push event to your repository.

In my Home Assistant, I create an automation like this:

- id: update_config_github_push_event
  alias: Update Configuration on Github Push Event

  trigger:
  - platform: webhook
    webhook_id: update_config

  action:
  - service: shell_command.update_config
  - service: homeassistant.restart

The update_config shell_command is in configuration.yaml:

shell_command:
  update_config: cd /config && git pull

Simple, isn’t it? Everything is quite straightforward. The automation will be triggered whenever it receives a webhook and the actions are doing a git pull and restart itself afterwards.

Configuration Checker

You might ask, how do I make sure everything will work before pushing everything to Github and hope it doesn’t break anything? Fortunately, there are some Github actions available for you to use that can do this. One of them is this. But unfortunately I can’t get them working in my setup because of custom integrations that I’m using (I gave up here). Basically, you will need to have a dummy secrets.yaml or environment variables containing the secrets you declare inside your configuration.yaml file. And you will also need to make sure custom_components directory is tracked by your git repo, in which mine doesn’t.

Restarts Are Annoying

Sometimes I don’t want to trigger the automation, i.e when I update a README or when there’s a typo. Luckily this can be done without adding anything. All you need to do is adding [skip ci] to your commit message you push to Github. This tells Github to skip the workflows which will not send the webhook to Home Assistant.

What About Secrets?

Normally in Home Assistant you declare secrets in a file called secrets.yaml and you call them using !secret in your config file. But in a git repository you don’t want people to look at your secrets. You can either not pushing the secrets.yaml file entirely or you can use something like this (thanks to alex again) in your config file:

key: !env_var the_secret_value

So, instead of using !secret, I use !env_var and declare the environment variables using Kubernetes manifest. As I’m using Flux to manage my Kubernetes secrets, I can put the encrypted secret the GitOps way which you can find here.

Closing

So this is how I GitOps my Home Assistant using a simple automation. There are still a lot of caveats, like I can’t make sure whether the container started successfully or not. But at least I managed to get what I wanted, which is having GitOps like experience in my Home Assistant configuration. Please leave any idea or feedback in the comment section if you have anything to share with me. Thank you 🙂