VSCode 远程开发-从头开始配置一个远程开发环境

最近折腾远程开发环境,从 jetbrains 的远程开发折腾到了 vscode 远程开发遇到了非常多的问题,在此记录下。

开发感受

首先说下 jetbrains 和 vscode 开发时两者之间的感受

jetbrains

我原本使用的开发环境几乎都是 jetbrains 家的产品,比如 PHP storm、goland、pycharm、web storm 这些,在开发体验上非常好,可以说是非常舒服,能够让你享受编程的乐趣;

它内置自带的语法提示非常的好,而且能够轻松识别你语言复杂的父子继承、抽象类、魔术方法映射之间的关系。简而言之,就是几乎 100%能够导出所有可用的方法供你调用,即使不需要看你框架的文档情况下也能够发现很多隐藏的方法和类用法,以 laravel 框架为例,它的框架非常大而全,而文档又非常的少很多细节用法都没有。而 phpstorm 能够轻松让你熟悉 laravel 框架的类之间关系,调用层级等。

另外也能够直接追踪出语言原生方法的一些源文件参考定义,包括语言的一些第三方扩展模块的方法和类源文件定义。

在 git 版本控制方面,jetbrains 的编辑器能够友好的实现所有本地分支的展示,远程分支展示,查看不同分支的代码,不同分支的历史 commit 代码对比。还有本地储藏代码不仅仅是使用 git 自带的储藏,他还有自带的一套储藏逻辑,在储藏还原上非常好用。除此在解决冲突时能够以三列的形式展示,左边本地,右边远程,中间合并后的代码供你参考展示与修改,并且有智能合并的功能,你往往只需要点击智能合并并且进行 review 一遍即可。

VS Code

当切换到 VS Code 之后呢遇到了很多的不快,大致如下:

在代码提示方面,可以说这个编辑器是一个文本编辑器,而不是一个工业化的 IDE 软件,它缺少对语义的理解,它只是一个文本编辑器。

表现出来就是,

  • 它不能够友好的进行代码提示,对缺失的类进行引用,或者你输入某个方法,它不能够自动完成并帮你引入这个类。

  • 由于它并不能够识别出类的所有方法,那么在在函数/变量定义跳转方面也支持很差。所有语法提示全靠插件。

  • 使用 git 管理版本时,交互体验极差,你不能够直观的查看所有的历史版本及某个版本或某个 commit 的代码详情,代码合并解决冲突的体验极差

  • 在处理版本 commit squash 压缩合并时,也很吃力,不能够将临时的多次 commit 合并成一次有意义的提交即使使用插件操作也很反直觉并且插件还需要付费!

  • 尽管 vscode 的很多基础 git 操作是支持的,但表现出来的 UI 交互体验极差,或者让你找不着隐藏的路径很深。

  • 在注释方面也不能够自动根据已经有的函数体进行更新补全,只能删除掉所有注释,然后重新生成新的注释。

简而言之的总觉,vscode 对代码的理解是文本,而 JB 家的 IDE 对代码是有语义分析的。JB 能够轻易的实现语法提示、函数之间跳转,参数提示,语法分析非常完美。

反观 VS Code 写代码像是盲写一样,像回到了早期用 notepad 写代码的感觉,只是稍微多了一点点提示,全凭记忆,几乎没有提示,执行时才知道结果,也不会告诉你这个方法废除了或者建议你使用更好的写法。

VS Code 整个开发体验过程需要你全程依赖插件来解决问题,你可能一大半的时间都花在了解决语法提示、插件不能用,插件冲突,版本冲突,安装什么插件好呢?之前好着,怎么突然不提示了,等等这类问题上。如果你想开箱即用,你就选择 JB 全家桶。

远程开发

那 VS Code 开发体验极差,我为什么还要选择呢?

答案就是因为 VS Code 在远程开发体验上支持很好,几乎是 VS Code 带领着行业使得远程开发更受欢迎,体验更好,所以它衍生出来的生态支持的功能和框架等等都是非常好用的。

而在这里,jetbrains 的远程开发体验可以说是极度难用,甚至对于新手无法跑通这个逻辑。折腾两天三也跑不起来。并且远程的 IDE 非常的耗费性能,动不动就卡死。

为什么要选择远程开发,本地开发不好吗?

当你拥有多台设备时,你就不能够将你的代码放到其中一台设备上,否则使用其他设备时就不能够轻易的进行开发工作,哪怕是简单的修改一行也因为没有环境无法执行或者提交代码等等。

而当拥有了一台核心的电脑负责远程开发工作时,你可以拿起任意一台手边称手的设备进行开发,无论是在家里还是在公司还是在任何地方,都能够轻松连接进行编辑代码。同时你手边的客户机配置又不需要那么高的配置,因为它只是起到一个屏幕和键盘的作用,为此不需要准备任何的开发环境,因为通过远程连接时开发环境都是一致的。

近些年来很多微软和 Google 的程序员都已经习惯使用远程开发,或者是任何的开放自由式办公环境,不需要拘泥于使用任何设备,当忘记带电脑时可以随时借一台笔记本接上扩展屏幕就可以进行远程开发。

当然这一切的前提都是你做的是偏后端服务的工作或者是网页端的开发,如果你是做具体的客户端程序开发,那么就不太适用于你。

dind

dind 是 docker in docker 的缩写,如果你有一个环境较好的物理主机以及操作系统,那么你或许可以省去这步,我是使用的是 unraid 的 nas 系统,它在最外层的操作系统上很多东西都不能够持久化保存,比如 ssh 密钥、git 配置等任何 ~/ 用户目录的信息。不止如此,其他目录也不可以。

首先使用 vsode 开发大部分你的代码都将在 docker 容器中运行,你可以想象,你有 10 个项目,每个项目都可以是一个独立的开发容器,所以 vscode 需要拥有控制 docker 的权限。

那么因为上述原因,unraid 环境下我的配置不能够持久化存储,我就需要将开发环境放到 docker 中,而进行模拟一个虚拟的操作系统,在虚拟的操作系统中安装一个 docker,然后供 vscode 进行控制。也就是 docker in docker。

网上有很多 dind 的镜像,有的很多年没更新,有的太大了,总之有着洁癖选择困难症很难下手。我开始也是用的别人的,后来折腾明白了,完全不需要使用别人的镜像,只要给 docker 容器 privileged 权限,那么你就可以在里面再创建一个 docker。

这是我目前的 dockerfile 配置

FROM debian:12

RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list
 
 
COPY --from=ochinchina/supervisord:latest /usr/local/bin/supervisord /usr/local/bin/supervisord


RUN apt-get update && apt-get install -y \
    bash \
    openssh-client \
    openssh-server \
    curl \
	wget \
	htop \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && mkdir -p /var/log/supervisor

RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh \
	&& wget -O /usr/bin/docker-compose https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-linux-x86_64 \
	&& chmod +x /usr/bin/docker-compose 

COPY files /
EXPOSE 22
ENTRYPOINT ["/docker-entrypoint.sh"]

简单概括下

  • 使用基于 debian12 的源,你可以有更大的操作空间。

  • 有需要的话可以更改其中 debian 源为清华源,加快安装速度。

  • 安装 supervisord,这是一个类 supervisor 的程序,只不过它不再是 python 版本,而是 golang 版本大单文件静态版本。又省去了 python 基础环境的空间。

  • 安装基础必备组件,最重要的就是 openssh-server 相关的库用于给你的 vscode 进行远程连接。

  • 通过一键脚本安装 docker,这是官方的。另外手动下载 docker-compose 静态版本。

  • 复制基础的配置到系统中,包含 supervisor 服务配置文件、ssh 初始化脚本等等。

详细可参考我的 github 仓库,dind

docker-compose.yml

version: "3"

services:
  dind:
    image: ellermister/dind 
    build: .
    privileged: true
    volumes:
      #- /mnt/user/appdata/dind/docker:/var/lib/docker
      - /mnt/disk4/appdata/mydind/docker:/var/lib/docker
      #- ./docker:/var/lib/docker
      - /mnt/user/projects/web:/web
      - ./ssh:/root/.ssh
      - ./vscode-server:/root/.vscode-server
      #- ./data:/var/lib/docker
    ports:
      - "2022:2022"
    #network_mode: host
    environment:
      USER: dind
      PASSWORD: dind

这里补充说道:

  • volumes 映射了你的 docker 存储路径和项目存储路径以及 ssh 路径等等。

  • 其中看我注释曾经的/mnt/user/appdata 路径而直接使用 disk4 硬盘,因为 unraid 缓存存在特别大的问题,如果你也是 unraid 这里建议你直接将 ssd 硬盘设为阵列盘,并且直接指定目录,不要套一层系统的模拟缓存层。

  • ssh 端口是 2022,你可以自由更改,因为原本 unraid 系统的 22 端口被占用了。

  • 网络不需要配置 host,使用 nat 即可,这时候就体现到了 vscode 强大之处,根本不需要手工端口映射,vscode 会自动打洞。

  • privileged 是必备的,赋予特殊操作权限。

  • 用户名和密码配置下就好。

启动的话就直接在 unraid 系统命令行对应的你的当前 dind 项目目录执行:

docker-compose up -d

如果你 unraid 没有 docker-compose 也没有插件,去下载一个二进制到这个目录 ./docker-compose 相对路径去执行也可以。

远程连接

当你配置好后,你就可以使用 VS Code 进行远程连接到这台虚拟系统中了。你在任何系统中无论是 windows 还是 mac、linux,只需要下载一个 vsode 就能够轻松进行连接,它不再要求你本地设备的性能。

安装远程开发基础插件

Remote - SSH - Visual Studio Marketplace

Dev Containers - Visual Studio Marketplace

当然你也可以选择安装远程开发套件包,直接在插件里搜索 remote 第一个就是,地址是这个

Remote Development - Visual Studio Marketplace

其中的 wsl 我们是不需要的,总之按照自己实际情况按需安装。

远程配置

认识远程开发核心操作区

点击上图中的 配置 ssh 按钮,将会在 vscode 中心操作区顶部弹出交互窗口,让你选择将要编辑的配置文件。一般我们选择当前用户目录下的。

然后你就可以像这样进行配置

Host 192.168.1.186
  HostName 192.168.1.186
  User root
  IdentityFile ~/.ssh/id_rsa

Host nas-dind
  HostName 192.168.1.220
  Port 2022
  User root
  IdentityFile ~/.ssh/id_rsa
 

不建议使用密码,如果你只是测试你这里也可以先不填写,具体连接时会让你输入。长期使用还是建议使用密钥进行连接。

密钥配置在 dind 容器里的 ~/.ssh/authorized_keys 文件里,我们上文也有映射路径,这些基础操作不再详说。

当你保存配置好后就可以看到类似我那样的窗口进行选择并且连接了。

图中是直接指向项目的,你打开对应的远程机器也可以,它会提示你进行创建项目,此时你的项目将创建在远程服务器。

当你创建好一个项目之后,你可以通过远程插件切换到 docker 容器端。

这是我已经创建并且正在运行的容器。

你可以通过这个按钮创建属于你这个项目的新的开发容器。弹出的交互窗口中你都可以尝试下,以此来熟悉下区别和不同。

一般我们常用于 Open current Folder in container 和 new dev container

当你的容器创建好后,你的项目根目录会自动创建 .devcontainer 目录,它默认只会有一个 devcontainer.json 文件,记录着当前容器使用的镜像以及一些基础的配置。

当你使用后会觉得镜像有一些残缺或者你想进行一些修改,你修改了 devcontainer.json 文件时,你可以使用快捷键重构镜像。

ctrl+shift+p 呼出命令输入框,输入 reconta 就能够索引出来,选择 Rebuild Container 就会自动重构。掌握了 VSCODE 快捷键后能够大大提升你的编程体验。

容器开发

为什么要使用使用容器开发,直接使用远程的环境安装开发环境不好吗?

  • 首先你远程的操作系统不能够轻易的安装一些复杂的环境,如果存在一些其他软件或者环境就会冲突,为了不污染外部操作系统,外部操作系统最好能够最小化安装在迁移时也能够更轻松。

  • 其次将开发环境放到 docker 容器中,你可以随时轻易的进行增改,改变环境,并且拥有一套对应的配置在多人协作中非常实用。能够快速实现容器部署和减少重复的环境设置步骤。

  • 越来越多的开源项目都会携带一份 .devcontainer 来供你快速配置开发环境,这也是 vscode 社区推动起来的,一切都将让你的开发体验变得更简单。

上文简述了下如何创建一个基础的容器以及配置在哪里。

这里简单介绍下我个人的一个开发环境配置

// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/php
{
	"name": "PHP",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	// "image": "mcr.microsoft.com/devcontainers/php:1-8.2-bullseye",
	"service": "dev",
	"workspaceFolder": "/workspaces",
	"dockerComposeFile": "docker-compose.yml",
	"customizations": {
		"vscode": {
			"extensions": [
				"DEVSENSE.phptools-vscode",
				"kokororin.vscode-phpfmt",
				"Vue.volar",
				"mhutchie.git-graph",
				"amiralizadeh9480.laravel-extra-intellisense",
				"DEVSENSE.profiler-php-vscode",
				"DEVSENSE.intelli-php-vscode",
				"ms-vscode.vscode-typescript-next"
			]
		}
	},

	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Configure tool-specific properties.
	// "customizations": {},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	"forwardPorts": [8080]

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html"

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}

说下重点:

  • 不再使用固定的镜像,使用 docker-compose.yml 进行部署。

  • 工作目录使用 /workspaces 默认标准的开发环境路径。

  • 自定义了一堆的 vscode 扩展插件,将在容器构建后启动时会自动安装。

  • remoteUser 这个远程用户比较重要,就是你容器中实际执行的用户,我们直接使用 root,减少开发时的权限问题。

  • forwardPorts 这些其他等等配置几乎不用动默认即可,不影响你程序实际监听的端口。

更多配置参考这里:https://containers.dev/implementors/json_reference/ 或者 vscode 官网文档也有。

docker-compose.yml

version: '3'
services:
  dev:
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - ${SSH_DIR:-~/.ssh}:/root/.ssh
      - ..:/workspaces:cached
    command: /bin/sh -c "while sleep 1000; do :; done"

说明

  • 最重要的就是 ssh 的路径建议直接映射到容器内部,否则你的 git 都没有密钥进行远程连接很麻烦。

  • 设置工作路径和设置 command 循环睡眠使得不要让容器自动退出。

端口映射

最强大最重要的功能来了,端口映射,vscode 会自动将你远程环境中的程序监听的端口进行映射到你本地,哪怕有多层 nat 它也能够穿透。本质是通过 ssh 映射的。

无论是你处于远程基础 ssh 环境下,还是远程开发容器中都可以找到这个端口面板进行配置。

当你启动一个程序时,它会自动进行监听,无需你任何配置,当然你可以去修改端口等等。

你在本地浏览器可以直接以 127.0.0.1:8000 进行访问,而无需指定远程的服务器 IP 和端口。这种拟本地化的开发体验真的很棒。

总结

到此你的 vscode 基本开发环境就认识的差不多了,后面将针对 php 开发时,推荐安装的插件进行说明,来提升 vscode 糟糕的语法提示体验。也将会介绍一些常用的基础快捷键来提升你的开发效率。

Comments