My aging laptop does not get on with the HomeAssistant devcontainer development environment - it’s a SurfacePro 7 with the i5-1035G4 and 16GB RAM but as much as I like the touch screen, the mobile i5 chip seems underpowered. As an aside, compared to an iPad the SurfacePro doesn’t really work for me as tablet either.
As a result, I was after a lighter way to develop simply dashboards and custom modules for HomeAssistant without using the “production” install.
Somehow I stumbled across DevSpace and it fits the bill perfectly. As an introduction, DevSpace is a very lightweight, client-only, open-source developer tool for Kubernetes. DevSpace is a Cloud Native Computing Foundation (CNCF) sandbox project contributed by Loft Labs
DevSpace runs as a single binary CLI tool directly on your computer and ideally, you use it straight from the terminal within your IDE. DevSpace does not require a server-side component as it communicates directly to your Kubernetes cluster using your kube-context, just like kubectl.
There is a great Getting Started guide for DevSpace on their website. Rather than repeating that guide here, I’m going to describe the setting up the environment for HomeAssistant, inside Kubernetes.
First, we need to download DevSpace. There are a few options. I’m using yarn to install inside a Windows WSL image. VS Code is my primary development IDE.
yarn global add devspace
We can use this folder to synchronise a HomeAssistant dashboard project development container, but this could be any code. To use an existing project, clone a git repo instead
mkdir -p ~/battery-card/src
mkdir -p ~/battery-card/dist
# or: cd ~ && git clone https://git.example.com/battery-card
cd ~/battery-card
Use DevSpace CLI and follow the wizard.
devspace init
The outcome will be a yaml configuration file. During the wizard, we will want to select:
8123
as the port the application is listening onThe wizard will create two files. devspace.yaml
which is the main configuration file and devspace_start.sh
which is the default entry script for the container. We are only going to use devspace.yaml
.
devspace.yaml
configurationI’ll first share the final configuration and then break this configuration down. I’m not touching the pipelines
, images
or commands
sections so consider this a proof of concept post!
version: v2beta1
name: homeassistant
# This is a list of `pipelines` that DevSpace can execute (you can define your own)
pipelines:
# This is the pipeline for the main command: `devspace dev` (or `devspace run-pipeline dev`)
dev:
run: |-
run_dependencies --all # 1. Deploy any projects this project needs (see "dependencies")
ensure_pull_secrets --all # 2. Ensure pull secrets
create_deployments --all # 3. Deploy Helm charts and manifests specfied as "deployments"
start_dev app # 4. Start dev mode "app" (see "dev" section)
# You can run this pipeline via `devspace deploy` (or `devspace run-pipeline deploy`)
deploy:
run: |-
run_dependencies --all # 1. Deploy any projects this project needs (see "dependencies")
ensure_pull_secrets --all # 2. Ensure pull secrets
build_images --all -t $(git describe --always) # 3. Build, tag (git commit hash) and push all images (see "images")
create_deployments --all # 4. Deploy Helm charts and manifests specfied as "deployments"
# This is a list of `images` that DevSpace can build for this project
# We recommend to skip image building during development (devspace dev) as much as possible
images:
app:
image: username/app
dockerfile: ./Dockerfile
# This is a list of `deployments` that DevSpace can create for this project
deployments:
app:
# This deployment uses `helm` but you can also define `kubectl` deployments or kustomizations
helm:
# We are deploying this project with the Helm chart you provided
chart:
name: component-chart
repo: https://charts.devspace.sh
# Under `values` we can define the values for this Helm chart used during `helm install/upgrade`
# You may also use `valuesFiles` to load values from files, e.g. valuesFiles: ["values.yaml"]
values:
containers:
- image: username/app
volumeMounts:
- containerPath: /config
volume:
name: hass-config-dev
service:
ports:
- port: 8123
volumes:
- name: hass-config-dev
storageClassName: ceph-filesystem
size: 1Gi
# This is a list of `dev` containers that are based on the containers created by your deployments
dev:
app:
# Search for the container that runs this image
imageSelector: username/app
# Replace the container image with this dev-optimized image (allows to skip image building during development)
devImage: ghcr.io/home-assistant/home-assistant:2024.11
# Sync files between the local filesystem and the development container
sync:
- path: ./dist:/config/www/battery-card
# Open a terminal and use the following command to start it
terminal:
command: /bin/bash
# https://www.devspace.sh/docs/configuration/dev/modifications/entrypoint
disableReplace: true
# Inject a lightweight SSH server into the container (so your IDE can connect to the remote dev env)
ssh:
enabled: true
# Make the following commands from my local machine available inside the dev container
# proxyCommands:
# - command: devspace
# - command: kubectl
# - command: helm
# - gitCredentials: true
# Forward the following ports to be able access your application via localhost
ports:
- port: "8123"
# Open the following URLs once they return an HTTP status code other than 502 or 503
open:
- url: http://localhost:8123
# Use the `commands` section to define repeatable dev workflows for this project
commands:
migrate-db:
command: |-
echo 'This is a cross-platform, shared command that can be used to codify any kind of dev task.'
echo 'Anyone using this project can invoke it via "devspace run migrate-db"'
The deployments
section in devspace.yaml defines Helm charts, Kubernetes manifests and Kustomizations that can be deployed using the create_deployments
function which will be executed when we call devspace dev
. This will create one deployment called app. There are only a couple of things to mention:
PVC
into the container to give persistent storage. For many development environments this might not be needed but here it provides a place to persist the HomeAssistant configuration.8123
. Eventually we will be able to access this from http://localhost:8123
.# This is a list of `deployments` that DevSpace can create for this project
deployments:
app:
# This deployment uses `helm` but you can also define `kubectl` deployments or kustomizations
helm:
# We are deploying this project with the Helm chart you provided
chart:
name: component-chart
repo: https://charts.devspace.sh
# Under `values` we can define the values for this Helm chart used during `helm install/upgrade`
# You may also use `valuesFiles` to load values from files, e.g. valuesFiles: ["values.yaml"]
values:
containers:
- image: username/app
volumeMounts:
- containerPath: /config
volume:
name: hass-config-dev
service:
ports:
- port: 8123
volumes:
- name: hass-config-dev
storageClassName: ceph-filesystem
size: 1Gi
The dev
section defines containers that are central to the DevSpace-based development experience. A dev container serves as a remote work environment that is connected to the local machine via port forwarding, file sync, etc.
There are a few highlights here:
devImage
specifies the base container for the development environment. loft provide some default images but we can actually use anything we want here. Before I understood some of the other options in this section I thought I might need to create a custom image but that isn’t the case. We can just use one of the standard home-assistant published images.sync
defines the folders to synchronise between the local filesystem and the development container. More on this in a bitcommand
defines the entry point for the container. The default will be the devspace_start.sh
script, but we can change this to give a bash
prompt.One thing to note here - if you enable the terminal
for this dev container, DevSpace will assume that you manually want to start your application using the terminal session and it automatically changes the container entrypoint
to sleep. To disable the automatic modifications of the entrypoint for terminal-enabled dev containers, we need to add disableReplace: true
under the terminal
settings.
# This is a list of `dev` containers that are based on the containers created by your deployments
dev:
app:
# Search for the container that runs this image
imageSelector: username/app
# Replace the container image with this dev-optimized image (allows to skip image building during development)
devImage: ghcr.io/home-assistant/home-assistant:2024.11
# Sync files between the local filesystem and the development container
sync:
- path: ./dist:/config/www/battery-card
# Open a terminal and use the following command to start it
terminal:
command: /bin/bash
# https://www.devspace.sh/docs/configuration/dev/modifications/entrypoint
disableReplace: true
# Inject a lightweight SSH server into the container (so your IDE can connect to the remote dev env)
ssh:
enabled: true
# Make the following commands from my local machine available inside the dev container
# proxyCommands:
# - command: devspace
# - command: kubectl
# - command: helm
# - gitCredentials: true
# Forward the following ports to be able access your application via localhost
ports:
- port: "8123"
# Open the following URLs once they return an HTTP status code other than 502 or 503
open:
- url: http://localhost:8123
DevSpace will detect available clusters for us to select from. We also need to tell DevSpace which namespace to use.
devspace use context # to select the right Kubernetes cluster
devspace use namespace devspace # will be automatically created during deployment
To spin up the dev container we just run:
devspace dev
If needed, this will create the namespace defined above (devspace
) and deploy the application containers. Files from ./dist
will also be synchronised to /config/www/battery-card
and port 8123
will be forwarded from localhost
to the container.
We can access this new HomeAssistant instance at http://localhost:8123
.
This post is already quite long so I am not going go into too much detail about the HomeAssistant dashboard. I’ve been following the tutorial at https://github.com/home-assistant-tutorials/09.toggle-card-lit . In our project directory on localhost we need to install lit
so we run:
# Change to the folder if not there already
cd ~/battery-card
npm install --save-dev parcel
npm install lit
A full install of these two modules is over 300MB. Luckily, we don’t actually need ot synchronise everything with the dev container. lit will combine the source files from ./src
into ./dist
. We actually only need to synchronise ./dist
with the container which (in my case) will be two files! The rest of the node_modules
install can stay on the local machine.
At this point we are ready to develop - everything we need is up and running.
Hope this is useful, thanks for reading!