menu E4b9a6's blog
rss_feed
E4b9a6's blog
有善始者实繁,能克终者盖寡。

使用Docker容器取代虚拟机作为远程开发的容器

作者:E4b9a6, 创建:2023-04-19, 字数:4988, 已阅:61, 最后更新:2023-04-19

这篇文章更新于 582 天前,文中部分信息可能失效,请自行甄别无效内容。

在Windows下使用远程开发是当下非常流行的开发方式,它带来了许多好处:

  • 原生Linux开发环境
  • 无缝跨平台开发
  • 统一的开发体验

远程服务器系统,我通常是选择 虚拟机虚拟Debian12 ,但虚拟机的不足之处:

  1. 文件与网络被隔离:由于虚拟系统与宿主系统是完全隔离的,这就导致在部分开发场景需要反复下载上传文件(如配置文件),涉及调试web时也要更改0.0.0.0才能访问
  2. 硬件资源切割:虚拟机需要规划好性能,提前划出硬盘、CPU、网络等资源作为独立的虚拟资源,尤其涉及到显卡训练等场景非常不便捷

而Docker的轻量级虚拟可以很好的弥补这2个缺点,与宿主机实现统一网络环境与文件系统

下面是实践一个 Debian 容器作为开发容器的实践

1. Debian 容器

开发容器实现的目标如下

  1. Host网络:采用 host 网络,无需映射端口方便web应用调试
  2. 持久化存储:对代码目录做持久化存储,和宿主机双向绑定,方便更改文件

为了方便迁移容器,此次采用 docker-compose.yaml 来构建

1.1. 镜像构建

Docker设计理念与虚拟机不同,一个容器是生命进程等于一个应用的生命进程,而不是虚拟机这种完全独立的操作系统

所以要给容器一个永久运行的应用,这里选用 SSH 服务,构建一个 Dockerfile 文件如下:

Docker
FROM debian:12.7

ENV TZ=Asia/Shanghai

# 更改apt源为清华源
RUN sed -i.bak 's|http://deb.debian.org|http://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources && \
    sed -i.bak 's|http://security.debian.org|http://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources

# Software install
RUN apt-get update && \
    apt-get install -y openssh-server vim wget git zsh curl unzip gcc make openssl && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

# SSH configuration
RUN mkdir -p /run/sshd && \
    ssh-keygen -A && \
    echo 'root:root' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
    sed -i 's/#Port 22/Port 30022/' /etc/ssh/sshd_config

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

容器说明:

  1. 更换到清华源并安装的基础服务如ssh、git等
  2. 初始化 root 用户的密码为 root
  3. 更改ssh服务的端口为30022

测试构建镜像:

Bash
sudo docker build -t debian:develop . --no-cache

1.2. 代码目录

为了方便宿主机器与容器共享代码目录,创建一个目录 codes 用于存放容器的代码文件

再将上面的 Dockerfile 也放入到目录中,再创建一个docker-compose.yaml文件,目录如下:

Bash
$ tree -L 2
.
├── codes
│   ├── golang
│   ├── nodejs
│   ├── python
│   └── web
├── Dockerfile
└── docker-compose.yaml

5 directories, 2 files

docker-compose.yaml文件的内容如下:

YAML
services:
  debian12:
    build: ./
    image: debian:develop
    container_name: debian-develop
    restart: always
    network_mode: host
    hostname: debian-develop
    volumes:
      - "./codes:/codes"
      - "/etc/localtime:/etc/localtime:ro"

启动容器

Bash
sudo docker-compose up

1.3. 连接

运行成功后,在宿主机使用ssh容器连接

Bash
ssh root@127.0.0.1 -p 30022

连接后可以根据需要自行进行系统设置了

1.4. 备份

容器比起虚拟机而言,更容易被删除,所以定时做冷备也是保持开发环境稳定重要的一环

以上面的容器为例,这里在做完初步的系统设置后,创建一个新的备份镜像

Bash
sudo docker commit debian12 debian_develop_backup_image

如果需要迁移,或者考虑冷备的话还可以将这个新的备份镜像保存为 tar 文件

Bash
sudo docker save -o debian_develop_backup_image.tar debian_develop_backup_image

迁移到其他具备 docker 环境的服务器上,使用load就可以将这个镜像重新导入

Bash
docker load -i debian_develop_backup_image.tar

1.5. GUI开发

实际开发时,会有一些程序需要显示 GUI 图形界面,这就需要借助 VcXsrvXming 等 X Server 程序

X Server 实现了远程服务器上运行GUI程序,并在本地计算机中显示其内容的功能

其工作原理如下:

借助这个技术,可以在远程开发时使用开发一些GUI程序,非常方便

实现步骤如下

  1. 安装运行 VcXsrv 程序,并依次检查 Multiple Windows-Start no client-Disable access control 三个选项都勾选了
  2. 使用任意SSH客户端连接远程服务器,要设置 启用X11转发 选项(如:ssh -x username@hostname
  3. 运行任意GUI程序即可在本地看到GUI内容

首先在本地Windows中安装 VcXsrv 程序

安装后打开,记得勾选下面这个选项免去访问控制,之后根据需要自行启用

接着使用任何ssh客户端,我用的是 tabby,打开具体ssh服务器设置,并勾选 X11转发 ,如下

登录服务器后,运行用于测试的 X11-apps GUI程序,如下:

Bash
sudo apt install x11-apps

# 执行 xclock 程序
xclock

接着运行xclock,效果如下

2. 一些实际问题

由于 Docker 镜像并非完整操作系统,在日常使用会出现不少小问题,以下是一些记录与修复

2.1. 光标输入错位

这是缺失中文编码的问题,输入 locale 可以检查,如下:

Bash
$ locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=zh_CN.UTF-8
LC_TIME=zh_CN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=zh_CN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
LC_TELEPHONE=zh_CN.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
LC_IDENTIFICATION=zh_CN.UTF-8
LC_ALL=

修复需要安装locales,如下:”

Bash
apt install -y locales

运行选择默认的语言编码

Bash
dpkg-reconfigure locales

在弹出的所有语言编码中选择你需要的默认语言编码,我这里选择的是120. en_US.UTF-8 UTF-8


[[replyMessage== null?"发表评论":"发表评论 @ " + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageResponse.total]])

还没有可以显示的留言...
gravatar
[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[getEnviron(messageItem.m_environ)]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[getEnviron(messageItem.m_environ)]]