0. 背景知识

在C++开发中常遇到一些系统底层的问题,例如,即使同为Unix环境,在网络开发中,macOS与Ubuntu也存在头文件、接口的不同,这时必须要在目标系统环境中开发。一般来说,可行的解决方案有这么几种:

  1. 直接在目标系统开发;
  2. SSH+SFTP到远端主机;
  3. 在本机开启虚拟机,SSH+SFTP到本地虚拟机;
  4. 使用Docker在本地搭建开发环境,SSH+SFTP连接。

其实2/3/4在本质上相同,区别在于3/4位于本地环境,而2需要经过网络路由(无论是内网还是外网)。而在macOS与Windows下,Docker的原理也是启动一个虚拟机,因而3/4本质也是相同的,区别在于Docker可以使用Dockerfile来初始化镜像,而且移植较为方便。因此本文拟探讨一下使用Docker的C++开发环境的配置。

1. Docker镜像配置

我们使用docker-compose + Dockerfile的方式进行配置,优点在于可移植性强,且修改配置较为方便,无需每次启动时都使用很长的docker run -d --name xxx --port......的命令。

假设你的项目存放于本地文件夹/home/user/projects/,那么你需要创建一个/home/user/projects/.devcontainer/以放置Dockerfiledocker-compose.yml。配置中使用的是相对路径,因而如果有放在其它文件夹的项目,只需要将.devcontainer/拷贝过去即可,无需修改配置文件。

在Dockerfile中,以ubuntu:18.04为基础镜像,首先添加阿里云镜像(不需要的可以去掉),然后安装一些开发中会用到的包,最后添加一个部署用户并赋予sudo权限:

FROM ubuntu:18.04
ENV USER=deploy
ENV PASSWD=deploy
ENV WORKDIR=projects

# 替换为阿里云镜像,如不需要可以去掉本部分
RUN printf '\n\
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse \n\
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse \n\
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse \n\
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse \n\
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse \n\
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse \n\
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse \n\
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse \n\
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse \n\
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse' > /etc/apt/sources.list

# 安装开发环境必要的包
RUN apt-get update \
  && apt-get install -y ssh openssh-server build-essential \
    gcc g++ gdb gdbserver cmake \
    # 无需libboost可以去掉下一行
    libboost-dev \
    # net-tools 提供了ifconfig
    net-tools tar rsync \
    # 无需python3可以去掉下一行
    python3 python3-pip \
    sudo git\
  && apt-get clean

# 添加用户并配置密码
RUN useradd -m ${USER} && yes ${PASSWD} | passwd ${USER}

# 赋予sudo权限并允许无密码sudo
RUN echo ${USER}' ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN chmod 644 /etc/sudoers

CMD ["/usr/sbin/sshd", "-D"]

USER ${USER}
RUN mkdir -p /home/${USER}/${WORKDIR}/
ENV LC_ALL C.UTF-8

接下来是对docker-compose的配置,有几个比较重要的地方在文件中以注释形式标注了出来:

version: "3.4"

x-defaults: &default
  restart: unless-stopped
# 使用当前目录的 Dockerfile 来构建 docker 镜像
  build: .
  volumes:
# 本文件存放于.devcontainer/中,因而此处要把上级目录(源代码目录)挂载到工作目录
    - ..:/home/deploy/projects/

services:
  projects-dev:
    <<: *default
    container_name: projects-dev
    hostname: "projects"
# 如果在Dockerfile中修改过用户名,此处也要对应修改用户名和工作目录
    user: deploy
    working_dir: /home/deploy/projects
# 修改安全配置,以运行gdb server
    security_opt:
      - seccomp:unconfined
    cap_add:
      - SYS_PTRACE
# 开启 ssh 服务,这样 clion 就能通过 ssh 连接进来了
# 同时通过 tailf 命令保持 container 不要退出的状态
    command:
      bash -c "sudo service ssh restart && tail -f /dev/null"
# 此处将容器的22端口映射到主机的2222上,且仅对本机开放
    ports: 
      - "127.0.0.1:2222:22"

如果是在CLion中使用,Docker配置即可到此结束;如果在VSCode中使用,则还要进行下一步配置,见第3节。

2. CLion配置

在CLion中,并没有直接连接到Docker开发的功能。尽管CLion提供了Docker插件,但那不是为了这种场景使用的。因此,我们需要使用在Terminal中启动容器,然后使用CLion的远程Toolchains开发。

Terminal中,假定你在/home/user/projects/目录下,运行:

docker-compose -f .devcontainer/docker-compose.yml up -d

可以使用docker ps检查运行状态,只要STATUS一栏显示不是Restarting (1) 21 seconds ago类似的错误即说明成功启动,接下来可以开始使用CLion进行开发。

此处以muduo网络库为例进行编译和测试,假设已经将该项目git clone https://github.com/chenshuo/muduo.git./muduo/目录。

CLion中需要修改三处配置,位于 Preferences - Build, Execution, Deployment下的:

  1. Toolchains
  2. CMake
  3. Deployment

下面分别进行说明。

(1) Toolchains

Remote-Toolchains.png

在此处添加一个配置(无需设为默认),用户名与密码均为deploy,地址为localhost,端口为2222,其余配置均由CLion自动检测。

(2) CMake

Remote-CMake.png

如果无需在本地编译,可以直接修改当前配置的Toolchain,使用上一步的配置。如果需要在本地编译、或者连接到多个Remote,就增加对应的配置即可。

(3) Deployment

首先在Connection中配置好连接。注意:不要修改图中两个蓝框,否则CMake会不可用

Remote-Deploy1.png

其次,添加目录映射,如图所示,你可以直接点远程端的查看目录按钮选择,无须手动输入:

Remote-Deploy2.png

最后,因为我们使用的是目录挂载,因此并不需要由CMake接管文件同步,所以在Excluded Paths中直接将项目文件夹全部排除掉:

Remote-Deploy3.png

这样我们就完成了项目的配置,可以使用CMake进行Build了。同样,也可以在代码中加入断点进行变量监控等操作:

Remote-Debug.png

提示:Muduo网络库CMakeFiles.txt部分配置有问题,直接Build可能会出错。本文不涉及这部分的修复工作,因此遇到时可以在CLion右上角的Build config中加入环境变量:MUDUO_BUILD_EXAMPLES=false以跳过出错部分的编译。

3. VSCode配置

VSCode远程连接Docker开发环境需要安装Remote - Containers (by Microsoft) 插件,但其实更推荐直接安装Remote Development (by Microsoft) 插件组合包。

在VSCode中配置相对简单,只是需要在.devcontainer目录中添加一个额外的文件:devcontainer.json,文件内容如下,实际配置中有出入的地方也需要随之修改。

{
    "name": "Project Develop Env",
    "dockerComposeFile": "docker-compose.yml",
    "service": "projects-dev",
    "workspaceFolder": "/home/deploy/projects/",
    
    // Set *default* container specific settings.json values on container create.
    "settings": { 
        "terminal.integrated.shell.linux": "/bin/bash"
    },

    // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
    "remoteUser": "deploy"
}

.devcontainer文件夹放置在项目目录下(推荐放在与根CMakeFiles.txt相同目录中),点击窗口最左下角的远程连接图标,选择Open folder in Container,VSCode将自动识别并加载项目文件。

Remote-VSCode.png

远程Debug时,需要在VSCode中远程安装C++插件、CMake插件,在源代码中加入断点,在CMake插件中对应的Target上点击右键选择Debug即可。

Remote-VSCode-Debug.png

4. 总结

本文介绍了在CLion与VSCode中分别配置Docker下C++开发环境的方法。需要注意的是,CLion允许任意工作目录,然而VSCode存在CMake插件的限制需要一些手动配置的步骤(如果工作路径没有CMakeLists.txt则需要手动指定源代码路径,本文没有详细说明)。

本文以Muduo网络库为例进行测试,实验了配置环境的可行性。当然,在应用中也需要根据不同的配置对上述文件进行修改,相信对各位来说不是难事,就不再赘述了。

本文的最终配置文件已发布在Github:Remote-Development-on-Docker

参考文献

  1. Using Docker with CLion
  2. Clion 如何使用 Docker 作为开发环境
  3. Developing inside a Container using Visual Studio Code Remote Development
最后修改:2024 年 04 月 17 日
如果觉得我的文章对你有用,请随意赞赏