Using NFS for Development on Mac OS with a Bare-Metal Linux Docker Host Bind Mount

This post describes how to develop on a relatively weak MacBook Air (without the M1 chip ;->) with Mac OS and let the containers run natively on a relatively strong bare-metal Intel NUC with Manjaro Linux (connected via the DOCKER_HOST ENV VAR) on the same local network.

Setup

More technically speaking this means to have an NFS export on your Mac OS (e.g. exporting your application folders in which you are working with your code editor) and on the other side an NFS mount on your Linux machine with the Docker daemon there running the actual containers. Then use for docker run (DOCKER_HOST ENV VAR in this shell set to Manjaro host address or connection string) the -v flag for a so-called bind mount (which is in fact an NFS mount in the Linux Docker Host passed in from the Mac OS NFS export) so that your Mac folder - with its ongoing changes - is immediately visible in the Docker container on the Linux machine - here the Intel NUC with Manjaro as kind of an home server (although it is as well a desktop system).

As it turns out it is surprisingly easy to use NFS on (FreeBSD based) Mac OS - also without the so-called NFS Manager (which is nevertheless a great program ... and it of course can be used as well if you want e.g. more control, comfort or volume).

Mac OS (permanent export):

# create an export
sudo nano /etc/exports
    # add something like the following
    /Users/homer/repos/Applications -mapall=-2:-2 -ro localhost nuc

# restart
sudo nfsd restart

# optionally check the result
nfsd checkexports
showmount -e
    # example result
    Exports list on localhost:
    /Users/homer/repos/Applications     localhost nuc

Manjaro Linux (manual temporary mount):

# based on https://wiki.archlinux.org/index.php/NFS#Manual_mounting
# see there also for more permanent solutions, e.g. via fstab 
# (but consider well which system will always be on/available)
sudo pacman -Syu
sudo pacman -Syu nfs-utils

# test if export is reachable
showmount -e 192.168.178.30     # on Ubuntu also '-a' worked 
    # example result
    Export list for 192.168.178.30:
    /Users/homer/repos/Applications localhost,nuc

# create a mount point and manually mount it according to your needs
sudo mkdir /mnt/Applications
sudo mount -t nfs -o proto=tcp,port=2049 192.168.178.30:/Users/homer/repos/Applications /mnt/Applications

# check if Mac folders are visible in Linux
ls -al /mnt/Applications/

Docker Run Example

# e.g. mount your 'app1' folder to '/opt/app1' within the container
docker run <other_options> -v /mnt/Applications/app1:/opt/app1 <image>:<tag>

# flow for e.g. app1 directory (originally located on Mac OS)
# Mac:
# /Users/homer/repos/Applications/app1
#         ↓
# Manjaro (Docker Host):
# /mnt/Applications/app1
#         ↓
# Docker Container: 
# /opt/app1

Summary

Of course this might be a very special setup: The far more usual setup for using (Docker) containers in software development is of course to have the Docker daemon running "somehow locally" on your development machine - either on Linux natively or on Mac or Windows inside a virtual machine. However, there are cases where you might want to use also for software development a remote machine - e.g. for performance reasons on a stronger bare-metal machine or to have a native Docker container experience without the virtual machine in between.

For all people who would like to use such a "remote" (on the same local network) machine as e.g. a bare-metal home server with native Linux and Docker this blog post proposes (one possible) solution to the problem.

Fun fact on the side: Here it is totally twisted around regarding terminology on what is the server and what is the client: For Docker Manjaro is the server as it provides the Docker daemon which is used in Mac OS - via the DOCKER_HOST environment variable. For NFS it is Mac OS which is the server as it provides the NFS export which is then used by Manjaro as client. And from the container perspective it is then Manjaro which is the server for the bind mount.

Further information

https://daten-und-bass.io/blog/using-socket-forwarding-for-docker-engine-and-compose/
https://medium.com/better-programming/docker-tips-access-the-docker-daemon-via-ssh-97cd6b44a53/
https://docs.docker.com/storage/bind-mounts/
https://en.wikipedia.org/wiki/Network_File_System/
https://www.bresink.com/osx/NFSManager-de.html/
https://wiki.archlinux.org/index.php/NFS#Manual_mounting/