Open13

neovim + container

goropikarigoropikari

neovim remote の実験

Dockerfile

FROM ubuntu:22.04

RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y curl

COPY install.sh /install.sh
RUN bash install.sh

install.sh

#!/bin/bash

updaterc() {
    echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
    if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
        echo -e "$1" >> /etc/bash.bashrc
    fi
    if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
        echo -e "$1" >> /etc/zsh/zshrc
    fi
}

set -e

apt-get update
apt-get install -y curl

NVIM_VERSION=${VERSION:-"stable"}
curl -LO https://github.com/neovim/neovim/releases/download/${NVIM_VERSION}/nvim.appimage
chmod +x nvim.appimage
rm -rf /opt/nvim
mkdir -p /opt/nvim
mv nvim.appimage /opt/nvim/
cd /opt/nvim
./nvim.appimage --appimage-extract

NEOVIM_HOME=/opt/nvim/squashfs-root/usr
ln -s $NEOVIM_HOME/bin/nvim /usr/bin/
docker build -t neovim .
docker run -p 22222:22222 --rm -it neovim bash -c 'nvim --headless --listen 0.0.0.0:22222'
nvim --remote-ui --server localhost:22222
goropikarigoropikari

socket 経由でつなぐ

CONTAINER=neovim-container
docker run -d --name $CONTAINER neovim bash -c 'sleep infinity'
docker exec -u root $CONTAINER bash -c 'rm -rf /neovim_sock'
docker exec -u root $CONTAINER bash -c 'mkdir /neovim_sock'
docker exec -u root $CONTAINER bash -c 'chmod 777 /neovim_sock'
docker exec $CONTAINER bash -c 'nvim --headless --listen /neovim_sock/nvim.sock &'

LOCAL_NVIM_SOCK=$(mktemp /tmp/neovim-local-container-XXXXXX.sock)
sudo mount --bind $(docker inspect $CONTAINER | jq -r .[].GraphDriver.Data.MergedDir)/neovim_sock/nvim.sock $LOCAL_NVIM_SOCK

nvim --remote-ui --server $LOCAL_NVIM_SOCK
goropikarigoropikari

vscode remote container で立ち上がっている↓のプロセスを殺したら ssh が使えなくなったので、これが ssh-auth-sock を forward しているらしい

/home/vscode/.vscode-server/bin/xxxxxxxxx/node /tmp/vscode-remote-containers-server-yyyyyyyy.js

remote container で接続した前後の docker inspect の差

diff before.json after.json
32c32,39
<         "ExecIDs": null,
---
>         "ExecIDs": [
>             "c2645359e63aaf0947e00462c55bda3388048bed0c0b6543e8559b37a54497f5",
>             "03dc72315b73f203796aa6c387d295030e074d6d8f3e77d0063fff57d93347ce",
>             "44aa26efa64a54280259d04fbafd9e3ebb3367f62c958aaeee8f463f92bd2e80",
>             "691ed8f6536860eba692454b42b17022f1619f47dcc4a50659e4a25f7d467f20",
>             "a9138cad957b7b2dfc56a316579bb16b8f58d1617d08c75ed8e5710c7b709fd4",
>             "7f0eb81958796f23918a27dffc47e1a8e7324f77fe2ec879cbf278f2fb092720"
>         ],
goropikarigoropikari
docker run --rm --name neovim neovim bash -c 'nvim --headless --listen 0.0.0.0:8889'
docker exec neovim nvim --headless --listen 0.0.0.0:8890
IP_ADDRESS=$(docker inspect neovim | jq -r .[].NetworkSettings.Networks.[].IPAddress)
docker run --rm -p 8888:8888 alpine/socat tcp-listen:8888,fork tcp-connect:${IP_ADDRESS}:8889

# socat 経由でつなぐ
nvim --remote-ui --server localhost:8888

# 直接つなぐ。port forward せずとも ip address 直指定すればつながる
nvim --remote-ui --server ${IP_ADDRESS}:8890
goropikarigoropikari
docker network create hoge-network
docker run --rm --network=hoge-network --name neovim neovim bash -c 'nvim --headless --listen 0.0.0.0:8889'

IP_ADDRESS=$(docker inspect neovim | jq -r .[].NetworkSettings.Networks.[].IPAddress)
nvim --remote-ui --server ${IP_ADDRESS}:8889
goropikarigoropikari
# terminal 1
SOCK_DIR=/tmp/devcontainer_ssh_sock
mkdir -p ${SOCK_DIR}
docker run --rm -it --name neovim -v ${SOCK_DIR}:${SOCK_DIR} neovim bash
sudo apt-get update && sudo apt-get install -y openssh-client

# terminal 2
SOCK_DIR=/tmp/devcontainer_ssh_sock
IP_ADDRESS=$(docker inspect neovim | jq -r .[].NetworkSettings.Networks.[].IPAddress)
socat ${SSH_AUTH_SOCK} unix-listen:${SOCK_DIR}/test_ssh.sock,fork

コンテナ内

$ ssh -T git@github.com
Hi goropikari! You've successfully authenticated, but GitHub does not provide shell access.
goropikarigoropikari

socat で ssh sock を forward

# terminal 1
docker run --rm -it -d --name neovim neovim sleep infinity
GATEWAY=$(docker inspect neovim | jq -r .[].NetworkSettings.Networks.[].Gateway)
docker exec -it neovim bash -c "sudo apt-get update && sudo apt-get install -y socat"
docker exec neovim socat unix-listen:/tmp/test_ssh.sock,fork tcp-connect:${GATEWAY}:8888

# terminal 2
socat ${SSH_AUTH_SOCK} tcp-listen:8888,fork

# terminal 3
docker exec -it -e SSH_AUTH_SOCK=/tmp/test_ssh.sock neovim bash
ssh -T git@github.com
docker network create hoge-network
docker run --rm -it -d --network=hoge-network --name neovim neovim sleep infinity
GATEWAY=$(docker inspect neovim | jq -r .[].NetworkSettings.Networks.[].Gateway)
docker exec -it neovim bash -c "sudo apt-get update && sudo apt-get install -y socat"
docker exec neovim socat unix-listen:/tmp/test_ssh.sock,fork tcp-connect:${GATEWAY}:8888

# terminal 2
socat ${SSH_AUTH_SOCK} tcp-listen:8888,fork

# terminal 3
docker exec -it -e SSH_AUTH_SOCK=/tmp/test_ssh.sock neovim bash
ssh -T git@github.com
goropikarigoropikari

devcontainer cli で port forward する場合は appPort を使うと書いてあったが、docker compose だと forward されなかった。
source code を見た感じだと Dockerfile か image を直指定した場合しか port forward できないようだった。(devcontainer cli v0.58)
https://github.com/devcontainers/cli/blob/c1c8b08263c6dca7cd79c97a2d0bc581fcef4f6c/example-usage/workspace/.devcontainer/devcontainer.json#L43-L55

port forward はできないが直接つなぎに行けば ssh できた
https://github.com/goropikari/devccli/tree/2f9ccb189b4dca81f67548aac3a825b7f5877759/dockerComposeExternalNetwork