Develop in Containers with VSCodium

With the increasing popularity of immutable Linux operating systems, such as Fedora Silverblue or openSUSE Aeon (MicroOS), the software developer's workflow increasingly demands the use of containers for software development. It is no longer practical or even possible to install either the development toolchain or the code editor directly on the host operating system using traditional methods.

Instead, applications like code editors are now installed in a sandbox via Flatpak, and they have limited access to the host operating system. Similarly, build tools and compilers are installed inside containers. Because Flatpak and containers isolate applications and build environments from the host operating system, it is easy to set up multiple build environments without having to install any additional software on the host operating system. But the sandboxing and isolation complicate the interaction between the source code, compilers, and code editors.

A screenshot of the VSCodium text editor showing Rust code built and executed inside a Podman container

In this article, I explore a way to develop Rust programs in a Podman container from a Flatpak version of the VSCodium editor on Fedora Linux version 38.

Created
June 9, 2023

References

I used information from these articles:

  1. https://raduzaharia.medium.com/using-the-vscode-flatpak-distribution-a275d59ff1c7
  2. https://www.garron.me/en/linux/sshd-no-hostkeys-available-exiting.html

Install VSCodium

In this guide, I use the Flatpak version of the VSCodium code editor from Flathub. Note that VSCodium is also available as a traditional package from the VSCodium official website if you can't use Flatpak for any reason.

If you have the Flathub repository enabled, install VSCodium:

flatpak install flathub com.vscodium.codium

Flathub also offers the Code - OSS editor that should work in the same way. But I strongly recommend using VSCodium instead. The Flatpak version of Code - OSS tends to be outdated. Moreover, the "Open Remote - SSH" extension only supports VSCodium and fails to automatically install the remote extension host in the target container if Code - OSS is used.

Note that I don't use Visual Studio Code (VS Code) in this guide. Although VS Code is based on an open-source codebase, the program that is published on the Microsoft website for download is proprietary and closed-source. Both VSCodium and Code - OSS are open-source software built from the open-source codebase of VS Code. They provide almost the same functionality as VS Code. VS Code adds telemetry collection, access to Microsoft's extension store, and possibly other changes.

Prepare a Project Directory

I don't want to store project files inside the container because I want to be able to destroy containers without losing my projects. Create a directory on the host OS that will be shared with the container. I create a Rust directory inside my home directory that will store my Rust projects.

mkdir ~/Rust

I have an example Rust project named "exercise" in the Rust directory.

A screenshot of the Files window showing source files of a Rust project

Set Up a Container

Now I create a new container inside of which I will set up the Rust build environment. I use Podman to create containers. You can take a look at the Toolbox and Distrobox tools if you want to easily set up containers for more complex scenarios such as GUI application development.

Create a Container

Use Podman to create and start a new container that uses the latest Fedora Linux container image:

podman run -it --name Rust -v ~/Rust/:/Rust:z -p [::1]:20202:22 fedora

This command creates a new container named Rust that is based on the default Fedora Linux container image. The -i and -t switches attach an interactive console to the container so that we can run commands in the container. The ~/Rust folder from the host OS is made available in the container as /Rust. The :z suffix sets up the necessary SELinux labels on the files so that the container can access them. Port 22 from the container is mapped to port 20202 on the host OS for SSH access that we will set up. The port is bound only to localhost (the ::1 IP address). Those who still need IPv4 can write 127.0.0.1 instead of [::1]. If the IP address was omitted, the port would be bound to all IP addresses on the host, and anyone on the network could connect to the container!

To start the created container in the future, use this command:

podman start -ai Rust

Note that although root is the default user inside the container, you don't have to worry about doing accidental damage to the host OS. The Podman container is unprivileged and runs with the permissions of the user that started the container.

Install Updates in the Container

Run this command inside the container to install any available updates:

dnf --refresh upgrade

Install Development Tools in the Container

I want to install Rust inside the container. You can set up anything you want (C++, Go, …).

dnf install gcc
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The container can now create and build my Rust project:

A screenshot of the Terminal with a Podman container showing that it can build a Rust project

Install Other Required Packages

The VSCodium SSH extension will expect the which command to be present in the container. Install it now inside the container:

dnf install which

Set Up SSH Connection to the Container

Microsoft has a proprietary VS Code extension that can connect to containers directly. That extension is proprietary and not available in the extension marketplace that VSCodium and Code - OSS editors use. Instead, I will use a free extension that can connect VSCodium to the Rust container via SSH. Therefore, I need to set up an SSH server inside the container.

Install the SSH server inside the container:

dnf install openssh-server

Edit the SSH server configuration to allow the login as the root user:

vi /etc/ssh/sshd_config

Add the following lines:

Port 22
PermitRootLogin yes

Generate host keys in the container:

/usr/libexec/openssh/sshd-keygen rsa
/usr/libexec/openssh/sshd-keygen ecdsa
/usr/libexec/openssh/sshd-keygen ed25519

An alternative way to generate the keys:

ssh-keygen -A

Set the root password in the container. By default, the root account is locked. Install the passwd program and use it to create a new password:

sudo dnf install passwd
passwd root

Start the SSH server in the container (the -D parameter tells it to run in the foreground):

/usr/sbin/sshd -D

The -d parameter can help with debugging if needed:

/usr/sbin/sshd -D -d

Test the SSH Connection From the Host

Test that the host OS can connect to the container via SSH:

ssh -p 20202 root@localhost

Set Up Key-Based SSH Authentication (Optional)

If you don't want to enter the password every time you connect to the container via SSH, you can either set an empty password for the root user in the container or set up a key-based SSH authentication. I don't recommend having passwordless access to the container because other users on the host OS could SSH into the container. So I use key-based authentication instead.

First, create an SSH key on the host OS if the key doesn't exist already:

ssh-keygen -t ed25519

Copy the public part of the key from the host OS to the container:

ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 20202 root@localhost

In the container, disable password authentication for the root user because it is no longer needed:

passwd -l root

From the host OS, test that you can connect to the container via SSH without a password:

ssh -p 20202 root@localhost

Connect to the Container from VSCodium

In VSCodium, Install the "Open Remote - SSH" extension published by jeanp413.

A screenshot of the VSCodium panel with the Open Remote - SSH extension highlighted

Configure the details of the SSH connection in the extension settings. Because the extension fails to resolve the localhost hostname into an IPv6 address, I specify the IPv6 address explicitly as the HostName value. The configuration then looks like this:

Host rust
    HostName ::1
    User root
    Port 20202

Finally, connect to the configured SSH target.

A screenshot of VSCodium showing the configuration of the Open Remote - SSH extension and a highlighted button to create a connection

Install Any Additional Extensions

Install any extensions that will help you with your project. For Rust, I install:

The Result

If everything went well, you can write, build, run, and debug code in the container directly from VSCodium. Tasks triggered in the editor will be executed in the container.

It's time to celebrate!

A screenshot of VSCodium showing Rust code compiled in a container