A Yocto power user’s guide to tooling: Part II
All in on VS Code Dev Containers
This blog builds on top of Part I linked below:
Why a part II ?
Two things happened since I wrote part I,
- I finally managed to get QEMU running inside Docker (i.e. QEMU inside Docker, inside WSL, on Windows). It turned out to be pretty trivial to setup. I just had read the code comments in the Yocto runqemu script🤦🏻♂️. This invalidated my premise in part I of needing to re-create your local folder structure inside the Docker container.
- Seeing first-hand how people struggle with the Docker container setup I prescribed in part I. Supposedly it’s not very beginner friendly.
So, that lead me to give VS Code’s Dev Containers a shot in an attempt to make the setup n00b friendly. This feature effectively lets you run VS Code inside of a Docker container, much like how remote debugging with gdbserver works. Basically, VS Code UI is running on your host machine but it’s executing everything behind the scenes in a “remote” instance. I had previously dismissed it primarily because I couldn’t get QEMU working and also because it had left a bad taste in my mouth when I had used it in the past. But it turned out that my prejudice for Dev Containers was unjust; it is a thing of beauty when setup right!
The VS Code setup
A complete working repo is at:
I’ll go over the key files and concepts below:
1. Move settings to the Dev Container config file
In part I, I showed how to write a VS Code extensions configuration file to install recommended extensions and how to properly configure the Bitbake plugin settings via a workspace configuration file.
Now with Dev Containers, you can move all of that to a devcontainer.json file. The only reason to keep a workspace file is if you want to open/manage all of your Yocto layers through VS Code.
With this updated setup, the extensions are installed inside the Docker container. This is a pretty neat feature that helps minimize the extension bloat on VS Code that would otherwise slow it down when you use it for non-Yocto work as a general purpose editor.
Pro tip: you can set VS Code as the default editor for git.
2. Using Docker Compose
For bootstrapping a Yocto dev environment, I’d recommend using Docker Compose as oppose the typical Dev Container image configs approach. Docker Compose lets you use variables like ${HOME} for the mount paths, making the configs portable. e.g. https://github.com/ruvi-d/simplest-yocto-setup/blob/main-without-ai/docker-compose.yml
services:
crops-yocto:
image: crops/yocto:ubuntu-22.04-base
command: sleep infinity
volumes:
# Mount working dir
- .:/workspaces/simplest-yocto-setup
# Mount shared caches dir
- ${HOME}/yocto-caches:/workspaces/simplest-yocto-setup/caches
# Mount SSH credentials for git access
- ${HOME}/.ssh:/home/yoctouser/.ssh:ro
# Mount shell history files
- ${HOME}/.bash_history:/home/yoctouser/.bash_historyThe above Compose config replaces the following Docker command I shared in part I
docker run --volume=$(pwd):$(pwd) -u $(id -u):$(id -g) \
-v /etc/passwd:/etc/passwd:ro -v /etc/sudoers:/etc/sudoers \
-v ${HOME}/.ssh:${HOME}/.ssh \
-v /etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts \
-v ${HOME}/.gitconfig:${HOME}/.gitconfig \
-v ${HOME}/.bash_history:${HOME}/.bash_history \
--workdir=$(pwd) --interactive --tty --name my-yocto-builder \
crops/yocto:ubuntu-22.04-baseDev Containers takes care of passing through .gitconfig, so you don’t need to mount it. The VS Code documentation has more elaborate instructions to pass the Bash history and SSH git credentials, but I’d recommend the way I have done here. This way it “just works” for any new developer setting up your repo.
3. Launching a VS Code workspace inside a Dev Container
I concede that the biggest pain with Dev Containers is that it requires a two step process to launch.
Get Ruvinda Dhambarage’s stories in your inbox
Join Medium for free to get updates from this writer.
Step 1: Open VS Code in the workspace like you would normally do
Step 2: Hit F1 or ctrl+shift+p to bring up the command palette, type and select: “Dev Containers: Open Workspace in Container…”
4. Dev Container features
Dev Container features is a cool feature that let’s you add stuff like your favorite dev tools to a Docker Image. Without this, developing inside a Docker container can be pretty limiting as you wouldn’t have access to your preferred tools. Dev Container features lets you layer stuff on top of a Docker image without you having to maintain a customer image yourself.
In the simplest-yocto-setup demo project I linked above, I have added my favorite shell ZSH, along with the auto-suggestion plugin to the CROPS build image.
The list of available features can be found at: https://containers.dev/features. I’ve picked https://github.com/nils-geistmann/devcontainers-features/blob/main/src/zsh/README.md and added it via:
"features": {
"ghcr.io/nils-geistmann/devcontainers-features/zsh:0": {
"plugins" : "git zsh-autosuggestions"
}
},The above config enables the zsh-autosuggestions plugin but doesn’t actually download it. To do that I’ve used a postCreateCommand as follows:
"postCreateCommand": "git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions",To make the auto-suggestions actually useful, I have to also mounted my host machine’s ZSH history via the following Docker Compose config excerpt:
services:
crops-yocto:
volumes:
# Mount ZSH shell history files
- ${HOME}/.zsh_history:/home/yoctouser/.zsh_historyThen to wrap everything up, I’ve made ZSH my default terminal profile in the Dev Container via the following config in devcontainer.json:
"terminal.integrated.defaultProfile.linux": "zsh",Voila! You now got ZSH on the CROPS build image, with auto suggestions!
5. Building and running qemu
Bonus tip: if you typically build multiple machine configures, you can create multiple build directories to isolate these builds and have them be nicely managed via the Bitbake plugin. All you need to do is define “buildConfigurations” as shown below.
"bitbake.buildConfigurations": [
{
"name": "dogbonedark",
"pathToBuildFolder": "${workspaceFolder}/build"
},
{
"name": "stompduck",
"pathToBuildFolder": "${workspaceFolder}/build-st"
},
{
"name": "qemuarm",
"pathToBuildFolder": "${workspaceFolder}/build-qemuarm"
}
],Use KAS to create these build folders with the appropriate configurations. e.g.
AS_BUILD_DIR=build-qemuarm KAS_MACHINE=qemuarm kas checkoutNow, let me show how to switch to the qemuarm build configuration and launch QEMU via the command
build-qemuarm> bitbake kiss-image
build-qemuarm> runqemu qemuarm slirp nographic`slirp` is the magic arg that lets you run QEMU inside the CROPS container using usermode networking.
That’s all folks. I’m pretty happy with this updated more n00b friendly setup. Hope you find it useful!









