Skip to content

Instantly share code, notes, and snippets.

@eulersson
Last active April 29, 2024 05:15
Show Gist options
  • Save eulersson/2682fdcc1773b39d882f859a7ca8edb2 to your computer and use it in GitHub Desktop.
Save eulersson/2682fdcc1773b39d882f859a7ca8edb2 to your computer and use it in GitHub Desktop.
Abandoned Neovim Remote Development Workflows

This documents shows all my attempts to develop containers that are supposed to run on a Raspberry Pi in my home network. In the end I decided to simply represent the architecture with Docker Compose and run VS Code Dev Containers:

https://github.com/eulersson/taconez/wiki/4.-Development-Workflow

Discarded Tools for Remote Development

Discarded Alternative 1: lsyncd

Lsyncd (Live Syncing Daemon) synchronizes local directories with remote targets.

In my case it would be handy to keep the current project folder in sync with the various Raspberry Pis without having to run rsync to all of them or scp.

It uses rsync and ssh under the hood every time it detects a filesystem event.

I discarded it because the mantainer himself said it is not reliable on macOS:

the osx events interface of Lsyncd is generally very outdated, and as far as I know unmaintained, unless someone finds willing to do that, and best rewrite it all together to use FSEvents insted of that experiment I did back then to directly access the internal buffer, I'd advice against using it, or removing it from Lsyncd altogether.

Source: lsyncd/lsyncd#204 (comment)

Discarded Alternative 2: Distant + distant.nvim

Installing a distant service on the Raspberry Pi and connecting to it via Neovim is possible. You would be able to browse through the remote files from Neovim and open them up with your local Neovim resources.

PROS:

  • Good for connecting to resources that might be outside of the network.
  • The communication is efficient and fast because it goes through custom TCP distant protocol between the distant client and distant server.
  • It's encrypted.

CONS:

  • I couldn't get the language server features working, it seemed to rely on me installing all the intellisense tooling on the Raspberry Pi, which I prefer not because the compute power of my computer is better than the Pi.
  • Code would not reside in my powerful computer.
  • I would have to sync from that Raspberry Pi to the rest of them.

Container Development Overview

I struggled to have it setup properly, but it could be paired with remote development to help with the case of sshfs or NFS, where the files are entirely remote but the container is built locally with the remote files that are synched with sshfs or NFS.

Network Volume Approach Overview

A volume could be bound on the host machine (macOS) and Raspberry Pi could mount it with NFS or SMB. When outside the home LAN then an OpenVPN solution should be set up which is outside of the scope of this guide.

An alternative to the NFS + OpenVPN would be something like sshfs.

PROS:

  • Transparent to navigate the mounted remote volume.
  • Intellisense (LSP) would work since it resides on the host.

CONS:

  • When outside home LAN you need to use VPN to access home LAN resources.

I also evaluated other workflows such as lsyncd, distant and distant.nvim but each had caveats. I explain why I discarded them in Discarded Tools.

Create a Sharing User & Group on the macOS Host

When NFS shares we want a specific user remotedevuser with a specific remotedevgroup group to be used when writing on that share from the client. That user only needs to exist on the host server. When you mount the share, the client's user (e.g. myraspberrypiuser) will be mapped to remotedevuser.

# See what user IDs and group IDs exist so you don't pick an existing one:
dscl . -list /Users UniqueID
dscl . -list /Groups PrimaryGroupID

# Create user:
sudo dscl . -create /Users/remotedevuser
sudo dscl . -create /Users/remotedevuser UniqueID 301

# Create group:
sudo dscl . -create /Groups/remotedevgroup
sudo dscl . -create /Groups/remotedevgroup gid 301
sudo dscl . -create /Groups/remotedevgroup PrimaryGroupID 301
sudo dscl . -append /Groups/remotedevgroup GroupMembership eulersson
sudo dscl . -append /Groups/remotedevgroup GroupMembership remotedevuser

# Make the default's remotedevuser primary group be remotedevgroup:
sudo dscl . -create /Users/remotedevuser PrimaryGroupID 301

# Check it's all good:
sudo dscl . -read /Groups/remotedevgroup GroupMembership
GroupMembership: eulersson remotedevuser

Sources:

Change Project Folder Permissions on the macOS Host

Change the owning group of the /Users/eulersson/Devel/taconez project folder from eulersson:eulersson to eulersson:remotedevgroup so all users from remotedevgroup can write, edit, read, delete contents on that folder.

# Change the owning group:
sudo chown -R eulersson:remotedevgroup /Users/eulersson/Devel/taconez

# Ensure group users can write as well as read:
sudo chmod -R g+w /Users/eulersson/Devel/taconez

Set NFS Share on the macOS Host

We will now export the project folder as an NFS share.

Open up /etc/exports on the macOS (which acts as NFS server):

/Users/eulersson/Devel/taconez -network 192.168.1.0 -mask 255.255.255.0 -mapall remotedevuser

[!NOTE]

192.168.1.0/24 with your home LAN network range. If you want to be conservative it could be setup as read-only instead of read-write (by adding the -ro flag), that way if the Raspberry Pi goes nuts and starts corrupting files it would not affect the host's folder, but I guess it's not critical if the code is versioned with git.

Check the share is being exported correctly:

eulersson@macbook:~ $ sudo nfsd restart

# Should not error. If it's good it does not output.
eulersson@macbook:~ $ sudo nfsd checkexports

More information on the /etc/exports format on its manual: man exports.

If you are out of home use a VPN to connect to your home LAN.

Sources:

Mounting the NFS Share from the Raspberry Pi

Then on the Raspberry Pi mount the volume (192.168.1.22 is the IP of the MacBook that runs the NFS service):

sudo mkdir -p /mnt/nfs/development
sudo mount --types nfs --verbose 192.168.1.22:/Users/eulersson/Devel/taconez /mnt/nfs/development

You can check it mounted correctly with df -h or by listing the mounted folder ls /mnt/nfs/taconez.

When you are done unmount the volume on the client:

taconez@raspberrypi $:~ umount /mnt/nfs/taconez --lazy

And stop exporting it from the server by removing the line we added on /etc/exports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment