Straight from the command line, you can do the following with Docker:
DOCKER_HOST=ssh://user@host docker build -t image:tag .
And to save a bit of typing, you can set a context to save the remote host:
docker context create remote --docker "host=ssh://user@host"
and then use that remote context with:
docker -c remote build -t image:tag .
and if you want to run all of the commands with that context, then:
# switch to the remote context for all future commands
docker context use remote
# and to revert back to the default local context
docker context use default
This works well with a build, because the build context is sent to that remote server, and so there are no local filesystem mounts.
However, once you go to run the container, things get more complicated. All of the listening ports will be on the remote host, and volume mounts will be on the remote host filesystem. If you need these capabilities, then tunneling ports and ssh-fs may be the better option. The other option that comes to mind is remote plugins in the IDE that make all code changes on the remote host over ssh so development feels like it's local even when it isn't.