0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

由浅到深搭建远端容器开发环境

我快闭嘴 来源:玩转VS Code 作者:玩转VS Code 2022-09-27 10:03 次阅读

前言


使用C++作为主要开发语言的程序猿们应该会认同搭建开发环境是一件烦人的事情。为了编译一个程序不仅需要下载各种依赖包,还可能面临本地系统不兼容、编译器版本不一致、包版本冲突等各种问题。笔者在运营iLogtail开源社区的过程中发现开发和调试环境问题也是成员问的最多的问题之一,那么有没有一种方法可以彻底解决这一问题呢?

有。容器技术使应用在各种环境可以一键部署,一致执行,同样的原理也适用于开发环境部署。利用 VSCode 的 Remote-Development 插件就可以使整个开发环境运行在远程容器中。使用这种方式不但可以直接使用一致的环境开发编译,而且还自然实现了多个开发环境的隔离。下面让就我们由浅到深搭建这样的远端容器开发环境。

原理简介


为什么要远程+容器?远程解决的是开发机资源问题和代码安全问题,本地电脑CPU和内存比较有限,为了提高编译、测试效率一般都会准备一台专门用于开发测试的机器,而部分公司为了防止代码外泄,只允许内部开发机访问代码库。容器解决的是开发环境一致性问题。两者结合起来便能构建最理想的开发环境。

在使用 Remote-Development 插件时,插件会ssh连接到远程开发机,然后根据配置直接启动或是铸造开发环境镜像后启动开发环境容器。启动时将开发机的Workspace目录作为源挂载到容器中。开发环境容器启动后,插件会自动安装VS Code Server,并安装配置指定的VS Code插件。一旦容器内的VS Code Server启动后,本地的VS Code就会直接与容器内的VS Code Server建立通信。容器内可以访问Workspace所有文件,并且修改不会因容器退出而丢失。容器开发环境可以使用的VS Code插件,在Workspace的devcontainer.json配置中指定,下文会有详细描述。

为了提高启动速度并保留容器内插件的配置,开发容器内的/vscode目录其实挂载了一个docker volume,不会自动随docker退出而回收,因此从第二次连接容器开发环境开始,无需重新安装VS Code Server、插件等,启动速度大大提高。

1a0fbaac-3df7-11ed-9e49-dac502259ad0.png

环境准备

要使VS Code可以远程连接开发机,最好使用ssh密钥建立本地电脑和开发机的信任关系。要使用容器进行开发,开发机上必须安装Docker。这两步相关教程网上较多,在这里就不再赘述。

需要注意的是,要使VS Code通过ssh连上开发机并通过docker启动开发环境容器,建立信任关系的账户必须具备docker使用权限。如果使用root账户,那么自然具备。如果非root则可以使用任意一种方式使账户获得docker使用权限:

  1. 将用户加入docker组。参考Post-installation steps for Linux(https://docs.docker.com/engine/install/linux-postinstall)。
    sudo usermod -aG docker $USER

  2. 将docker.sock权限修改为777(不太推荐,除非上述方法无法奏效)。
    sudo chmod 777 /var/run/docker.sock

下面假设开发机使用的是Linux系统,并且与本地电脑已经建立好信任关系,而且安装并具备Docker访问权限。

安装插件

在VS Code的Marketplace中搜索“Remote Development”安装插件。

1a259020-3df7-11ed-9e49-dac502259ad0.png

安装完成后,会发现多出了3个子插件。

  • Remote - Containers:连接容器开发

  • Remote - SSH:连接ssh远程开发

  • Remote - WSL:连接WSL(Windows Linux子系统)开发

使用镜像开发

使用 Remote Development 插件最直接的方式就是利用现成的编译镜像启动开发容器。这里以使用C++和Go语言编写、依赖环境相对复杂的开源项目iLogtail数据采集器项目为例,说明如何利用 Remote Development 插件进行远程容器开发。

1. 创建Remote Development配置

在iLogtail Workspace的顶层目录创建.devcontainer目录,并在里面创建devcontainer.json文件。

1a31e546-3df7-11ed-9e49-dac502259ad0.png

配置文件的内容如下:

{  "image": "sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail-build-linux:latest",  "customizations": {    "vscode": {      "extensions": [        "golang.Go",        "ms-vscode.cpptools-extension-pack"      ]    }  }}

其中,image字段是Remote Development插件启动开发环境的镜像地址,customizations.vscode.extensions指定了开发环境的插件。部分插件介绍如下,开发者也可以按照自己的习惯进行修改。

插件名

用途

golang.Go

Go开发必备插件

ms-vscode.cpptools-extension-pack

C++开发必备插件

2. 在容器中打开代码库

使用Shift + Command + P(Mac)或Ctrl + Shift + P(Win)打开命令面板,输入reopen,选择Remote-Containers: Reopen in Container

1a537d32-3df7-11ed-9e49-dac502259ad0.png

或者若出现如下图提示,则可以直接点击在容器中重新打开。

1a677da0-3df7-11ed-9e49-dac502259ad0.png

首次打开时会比较慢,因为要下载镜像并安装插件,后面再次打开时速度会很快。按照提示进行镜像Build。

完成上述步骤后,我们已经可以使用VS Code进行代码编辑,并在其中进行代码编译。

注:如果以前拉取过编译镜像,可能需要触发Remote-Containers: Rebuild Container重新构建。

3. 在容器中进行开发

开发容器启动后,我们已经可以在VS Code中浏览Workspace代码了。但是随便打开一个文件,满眼都是错误提示,代码的跳转功能也不能正常工作。这是因为C++开发环境的includePath没有被正确配置。

1a84db2a-3df7-11ed-9e49-dac502259ad0.png

打开命令面板,输入C++ config,选择C/C++: Edit Configurations(UI)

1ab3965e-3df7-11ed-9e49-dac502259ad0.png

找到Include path,输入镜像内依赖库的路径。

1ad62926-3df7-11ed-9e49-dac502259ad0.png

再回来看代码时,错误提示都消失了,并且函数定义跳转正常。

4. 在容器中进行编译

打开新Terminal(找不到的可以在命令面板中输入Terminal,选择新开一个)

1b014b56-3df7-11ed-9e49-dac502259ad0.png

  • 编译iLogtail Go插件

make vendor       # 若需要更新插件依赖库
make plugin_local # 每次更新插件代码后从这里开始

1b152fb8-3df7-11ed-9e49-dac502259ad0.png

  • 编译iLogtail C++代码

mkdir -p core/build # 若之前没有建过cd core/buildcmake .. # 若增删文件,修改CMakeLists.txt后需要重新执行make -sj$(nproc)    # 每次更新core代码后从这里开始

1b285142-3df7-11ed-9e49-dac502259ad0.png1b4aeb58-3df7-11ed-9e49-dac502259ad0.png

5. 获取编译产出

由于VS Code是直接将代码库目录挂载到镜像内的,因此主机上可以直接访问镜像内的编译产出。

1b683b72-3df7-11ed-9e49-dac502259ad0.png

到这里,如果要求不高的话就可以结束了,但细心的读者一定发现了一个问题,容器内生成的文件在主机上都是root权限,必须执行sudo chown -R $USER .进行修复。如果社区的成员开发机没有sudo权限怎么办?作为iLogtail社区核心贡献者,当然不能把这样的坑留给队友了。

使用Dockerfile开发

那有没有办法做到容器内权限自动适配主机呢?这样的问题当然不会难倒VS Code了。Remote Development 插件支持使用 Dockerfile 在容器中进行开发,即在启动开发容器前先使用docker build一个开发镜像,这给了修正容器内账户权限的机会。

修正的原理如下:

  1. 在Remote Development 插件 docker build 前将开发机的账户名、账户ID、组名和组ID暴露给 docker。

  2. docker build时利用这些账户信息修正容器执行账户和容器内文件权限。

接下来我们进行实际操作。

1. 修改.devcontainer.json配置文件

在配置文件中,将image部分修改为build部分,使用Dockerfile启动开发容器。同时,加入initializeCommand,在build镜像前,将账户信息暴露给docker。

{  "build": {    "dockerfile": "Dockerfile",    "args": {      "USERNAME": "${localEnv:USER}"    }  },  "initializeCommand": ".devcontainer/gen_env.sh",  "customizations": {    "vscode": {      "extensions": [        "golang.Go",        "ms-vscode.cpptools-extension-pack"      ]    }  }}

2. 创建Dockerfile

以编译镜像作为基础镜像,编写Dockerfile对镜像内账户和文件权限进行修正。

FROM sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail-build-linux:latest
ARG USERNAME=adminUSER root
# Create the userCOPY .env /tmp/.envRUN source /tmp/.env && rm /tmp/.env;     if getent passwd $USERNAME; then userdel -f $USERNAME; fi;     if [ $HOST_OS = "Linux" ]; then     if getent group $GROUPNAME; then groupdel $GROUPNAME; fi;     groupadd --gid $GROUP_GID $GROUPNAME;     fi;     useradd --uid $USER_UID --gid $GROUP_GID -m $USERNAME;     echo $USERNAME ALL=(root) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME;     chmod 0440 /etc/sudoers.d/$USERNAME;     chown -R $USERNAME:$GROUPNAME /root/go /opt/logtail $(eval echo ~$USERNAME);     chmod 755 $(eval echo ~$USERNAME);
USER $USERNAME

COPY .env /tmp/.env将主机的账户信息通过文件形式复制到容器中。

接下来的几行根据这些信息在容器内创建对应的账户。

echo $USERNAME ALL=(root) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME;授予该用户sudo权限。

chmodchown的几行对文件权限进行修正,使新建的用户有权限读写对应目录。其中对HOME(~$USERNAME)目录的修正必须在这里进行,否则会导致VS Code Sever没有权限安装,导致插件启动失败。

3. 创建脚本暴露主机账户信息

gen_env.sh脚本内容如下。该脚本对开发机为Mac系统也做了兼容。

set -ueset -o pipefail
if uname -s | grep Linux; then  echo -e "HOST_OS=Linux
USERNAME=$USER
USER_UID=$(id -u $USER)
GROUPNAME=$(id -gn $USER)
GROUP_GID=$(id -g $USER)" > .devcontainer/.env;else  echo "HOST_OS=Darwin
USERNAME=$USER
USER_UID=$(id -u $USER)
GROUPNAME=root
GROUP_GID=0" > .devcontainer/.env;  fi

前3步完成后,Workspace中的配置目录应该有这样3个文件:

1b8a8c40-3df7-11ed-9e49-dac502259ad0.png

4. 运行观察效果

使用Shift + Command + P(Mac)或Ctrl + Shift + P(Win)打开命令面板,输入reopen,选择Remote-Containers: Rebuild Container

1bb2d2cc-3df7-11ed-9e49-dac502259ad0.png

在容器内重新执行id命令查看账户信息,可以看到与开发机一致。

1bd57688-3df7-11ed-9e49-dac502259ad0.png

在容器内重新执行之前的编译命令。然后会到开发机上查看生成的文件权限,可以看到容器内生成的文件,在开发机上都已经变成正确的权限了。

1beeb288-3df7-11ed-9e49-dac502259ad0.png

在容器内调试

除了编译代码,开发环境另一个重要功能是进行本地调试。打开一个iLogtail插件的单元测试文件,设置断电然后点击“debug test”。

1c057734-3df7-11ed-9e49-dac502259ad0.png

什么?Failed to launch: could not launch process: fork/fork/exec ...: operation not permitted,出错了!

1c27724e-3df7-11ed-9e49-dac502259ad0.png

查阅资料,原来是docker默认的安全策略使用Secure computing mode (seccomp)仅允许白名单系统调用,debug所需的系统调用被拒绝了。我们尝试在配置文件中添加一行"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],禁用该功能。

{  "build": {    "dockerfile": "Dockerfile",    "args": {      "USERNAME": "${localEnv:USER}"    }  },  "initializeCommand": ".devcontainer/gen_env.sh",  "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],  "customizations": {    "vscode": {      "extensions": [        "golang.Go",        "ms-vscode.cpptools-extension-pack",        "DavidAnson.vscode-markdownlint"      ]    }  }}

Rebuild Container后,再次尝试调试功能。It works!

1c4b020e-3df7-11ed-9e49-dac502259ad0.png

总结

至此,我们已经可以happy地通过VS Code的Remote Development插件在远程容器内开发了。并且使用的编译镜像和插件配置文件都是可移植,可重复的,CI到代码库后可以供任何开发者使用。文章中提到的代码都可以到iLogtaill的GitHub仓库(https://github.com/alibaba/ilogtail)获取。

Remote Development插件还有很多的功能没有在本篇文章中使用到,感兴趣的读者可以根据文末参考资料进一步研究探索。

审核编辑:汤梓红


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 容器
    +关注

    关注

    0

    文章

    481

    浏览量

    21876
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72892
  • 开发环境
    +关注

    关注

    1

    文章

    202

    浏览量

    16457

原文标题:一招解决开发环境问题 —— 远程容器开发指南

文章出处:【微信号:玩转VS Code,微信公众号:玩转VS Code】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    教你如何搭建Xilinx开发环境

    教你如何搭建Xilinx开发环境本教程将向你介绍如何搭建Xilinx开发环境,需要具备什么样的条
    发表于 02-29 09:23

    请大家推荐一本好的labview书?适合入门,层次浅到

    请大家推荐一本好的labview书?适合入门,层次浅到
    发表于 06-15 09:01

    adrod 开发环境搭建及基本使用

    ,Google以Apache免费开源许可证的授权方式,发布了Android的源代码。         2.关于Android开发环境搭建          1.环境变量
    发表于 07-09 08:35

    嵌入式linux开发环境该如何去搭建

    嵌入式linux开发环境搭建(Docker版,基于iTop 4412开发板)文章目录嵌入式linux开发
    发表于 11-04 08:09

    开发环境搭建教程

    android Windows系统下开发环境搭建
    发表于 03-22 17:42 0次下载

    搭建C语言开发环境(Windows平台)汇总

    本文给大家汇总了5种在WIN平台下搭建C语言开发环境的方法,包括在Windows平台配置GNU环境,使用Sublime Test开发C语言程
    的头像 发表于 02-01 10:03 3439次阅读

    php开发环境搭建和使用

    本文主要介绍的是php开发环境搭建和使用。apache在默认情况下不会处理php页面,Apache处理php页面的步骤:即:php开发环境
    的头像 发表于 02-01 15:26 3167次阅读
    php<b class='flag-5'>开发</b><b class='flag-5'>环境</b>的<b class='flag-5'>搭建</b>和使用

    arm的开发环境有哪些_使用Eclipse搭建ARM架构MCU开发环境

    本文主要介绍了关于arm的开发环境有哪些以及使用Eclipse搭建ARM架构MCU开发环境。Eclipse是一个框架,通过安装不同的插件组件
    的头像 发表于 02-01 16:19 1.9w次阅读

    如何搭建鸿蒙开发环境

    开发某一个平台的程序,那么首先要搭建出本地开发环境,那么如何搭建鸿蒙开发
    的头像 发表于 02-24 11:25 3219次阅读
    如何<b class='flag-5'>搭建</b>鸿蒙<b class='flag-5'>开发</b><b class='flag-5'>环境</b>

    嵌入式linux开发环境搭建(Docker版,基于iTop 4412开发板)

    嵌入式linux开发环境搭建(Docker版,基于iTop 4412开发板)文章目录嵌入式linux开发
    发表于 11-01 16:57 0次下载
    嵌入式linux<b class='flag-5'>开发</b><b class='flag-5'>环境</b><b class='flag-5'>搭建</b>(Docker版,基于iTop 4412<b class='flag-5'>开发</b>板)

    Digispark开发环境搭建

    Digispark开发环境搭建
    发表于 11-15 20:51 16次下载
    Digispark<b class='flag-5'>开发</b><b class='flag-5'>环境</b><b class='flag-5'>搭建</b>

    使用 rust 开发 stm32:开发环境搭建

    使用 rust 开发 stm32:开发环境搭建
    发表于 11-18 19:36 51次下载
    使用 rust <b class='flag-5'>开发</b> stm32:<b class='flag-5'>开发</b><b class='flag-5'>环境</b><b class='flag-5'>搭建</b>

    NXP freescale 开发环境搭建

    NXP freescale 开发环境搭建
    发表于 12-03 16:21 13次下载
    NXP freescale <b class='flag-5'>开发</b><b class='flag-5'>环境</b><b class='flag-5'>搭建</b>

    STM32 搭建开发环境

    STM32 搭建开发环境
    发表于 12-08 14:36 19次下载
    STM32 <b class='flag-5'>搭建</b><b class='flag-5'>开发</b><b class='flag-5'>环境</b>

    1. 瑞萨RA系列MCU 开发环境搭建

    开发环境搭建
    的头像 发表于 11-30 15:40 1083次阅读
    1. 瑞萨RA系列MCU <b class='flag-5'>开发</b><b class='flag-5'>环境</b><b class='flag-5'>搭建</b>