铊代码网
Published on 2024-11-03 / 50 Visits
5
0

ActixWeb - 远程SSH开发+Docker 容器

[!NOTE] 导读
本文内容基于 Docker 和容器,实现远程SSH开发、自动同步到容器、自动运行项目。
建议先阅读 ActixWeb - 新手入门指南 - 博客小站 - 铊代码网
转载请注明原文出处!

清单:

  • 主机:Windows
  • 服务器:Vmware 运行 Ubuntu 22.04 LTS;
  • 环境:Docker 容器;
  • 语言:Rust
  • 开发框架:ActixWeb

作者的电脑系统是 Windows,基于 Ubuntu + Docker 容器进行本地开发。

远程 SSH 开发

  • 工具:VsCode
  • 插件:remote-ssh

免费的 VsCode,足够用了。在安装插件后,左侧菜单会出现新的图标——远程资源管理器。

进入后,点击“SSH”这一行的+符号(新建远程),输入:user@192.168.100.100 -A,此时建议将配置文件放在 C:\Users\user\.ssh\config,然后输入 user 对应的密码即可连接。

修改远程连接的配置,例如端口号:

Host 192.168.100.100

  HostName 192.168.100.100

  User user

  Port 22

经验小贴士:远程连接是无法直接使用 root 账号,但实际上,服务器的文件多数是 root 权限控制。

因此,可以使用“密钥认证”来实现 root 访问。

密钥认证

在服务器生成密钥后,将密钥放在主机上,例如:C:\Users\user\.ssh\key\backend.id_rsa,文件内容是你的密钥内容。

在+符号旁的 ⚙️(打开SSH配置文件),修改配置:

Host 192.168.100.100

  HostName 192.168.100.100

  User root

  Port 22

  IdentityFile "C:\Users\user\.ssh\key\backend.id_rsa"

  ForwardAgent yes

此时,点击 → 连接将使用“密钥认证”,连接的身份是 root

实时同步

成功连接远程后,你可以访问项目目录并进行开发。

实际上,远程连接无法访问到“存储卷”内。因此,需要将项目放在允许远程访问的路径下,并实时(单向)同步到“存储卷”内,并实现自动重启服务。

作者的项目信息:

  • 开发目录:/home/user/project/backend
  • 容器名称:backend
  • 存储卷名:driver-backend

/home/user/project/ 新建脚本 sync.sh

#!/bin/bash

SOURCE="/home/user/project/backend"
TARGET="/var/lib/docker/volumes/backend/_data/index"

while inotifywait -r -e modify,create,delete,move $SRC; do
    rsync -av --delete $SOURCE/ $TARGET/
done

执行脚本 ./sync.sh,此时将实时单向同步。

注意了,“开发目录”不需要依赖目录 target/,因为“运行项目”的操作是放在容器内执行,因此需要排除 target/ 以避免在实时同步时被删除。

修改 sync.sh 脚本,支持排除(目标路径下的)目录:

#!/bin/bash

SOURCE="/home/user/project/backend"
TARGET="/var/lib/docker/volumes/backend/_data/index"
IGNORED_DIR="target"

# 使用 rsync 进行初始同步
rsync -av --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"

# 使用 inotifywait 监听源目录下的变化
inotifywait -mr -e modify,move,create,delete --exclude "\.$IGNORED_DIR" "$SOURCE" | while read path action file; do
    # 当文件发生变化时,执行 rsync 同步
    rsync -av --delete --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"
done

终止脚本并重新运行 ./sync.sh

自动运行项目

在服务器启动时,会自动启动容器,在容器启动时,会自动启动项目。

使用脚本实现“自动启动项目”,在存储卷 driver-backend 下新建脚本 /var/lib/docker/volumes/backend/_data/start.sh

#!/bin/bash

cd /www/index #容器内的项目目录
cargo run

作者的“容器”、“存储卷”的关系是:“存储卷”指向“容器”的 /www。因此,修改“容器”的 Command 并添加 '/www/start.sh'

在启动“容器”后,查看“容器”的日志会发现,自动执行了命令:

    Building [=======================> ] 152/153: backend(bin)                                                            
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.88s
     Running `target/debug/backend`

接下来,可以验证项目的功能了。

自动重启服务

为什么需要“自动重启服务”?

当修改了项目代码,也实现了实时同步到“容器”里,但修改内容未生效!!!

这是因为 cargo run 不会重新加载,也不会监听项目内容的变化。当然,重启一次“容器”就可以了。

但实际上,开发项目时修改代码是非常频繁的操作,那么,如何优雅的“自动重启”呢?

修改 sync.sh 脚本,在一定时间(秒数)内,仅重启一次服务:

#!/bin/bash

SOURCE="/home/user/project/backend"
TARGET="/var/lib/docker/volumes/backend/_data/index"
IGNORED_DIR="target"
THROTTLE_DELAY=5  # 设置秒数
TIMER_PID=0
CONTAINER_NAME="backend"  # 替换为你的容器名称或ID

# 使用 rsync 进行初始同步
rsync -av --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"

# 定义一个函数来处理同步和启动项目
do_sync_and_start() {
    if [ $TIMER_PID -ne 0 ]; then
        kill $TIMER_PID 2>/dev/null
        TIMER_PID=0
    fi

    # 执行 rsync 同步
    rsync -av --delete --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"
    # 在容器中执行 start.sh
    # docker exec -i $CONTAINER_NAME /bin/bash -c "/www/start.sh"
    docker restart $CONTAINER_NAME
}

# 定义一个函数来设置定时器
set_timer() {
    if [ $TIMER_PID -ne 0 ]; then
        kill $TIMER_PID 2>/dev/null
    fi
    sleep $THROTTLE_DELAY && do_sync_and_start &
    TIMER_PID=$!
}

# 处理中断信号
trap 'kill $TIMER_PID 2>/dev/null; exit 0' SIGINT SIGTERM

# 使用 inotifywait 监听源目录下的变化
inotifywait -mr -e modify,move,create,delete --exclude "\.$IGNORED_DIR" "$SOURCE" | while read -r path action file; do
    # 当文件发生变化时,设置定时器
    set_timer
done

这是完成的、最终版的代码,在修改路径、容器名称后可以直接使用。

进阶-自动重启服务

每次修改项目代码,会重启容器——这样的做法,是不是有些浪费了?前端项目在开发时支持“热更新”,那么 rust 支持吗?

使用 cargo-watch ,在项目源代码发生改变时自动运行 Cargo 命令。

修改:/home/user/project/sync.sh ,仅实现实时单向同步即可:

#!/bin/bash

SOURCE="/home/user/project/backend"
TARGET="/var/lib/docker/volumes/backend/_data/index"
IGNORED_DIR="target"

# 使用 rsync 进行初始同步
rsync -av --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"

# 使用 inotifywait 监听源目录下的变化
inotifywait -mr -e modify,move,create,delete --exclude "\.$IGNORED_DIR" "$SOURCE" | while read path action file; do
    # 当文件发生变化时,执行 rsync 同步
    rsync -av --delete --exclude "$IGNORED_DIR/" "$SOURCE/" "$TARGET/"
done

修改:/var/lib/docker/volumes/backend/_data/start.sh

#!/bin/bash

# 检查 cargo-watch 是否已安装
if ! command -v cargo-watch &> /dev/null
then
    echo "cargo-watch 未安装,开始安装..."
    cargo +stable install cargo-watch
else
    echo "cargo-watch 已安装,继续执行命令..."
fi

cd /www/index
cargo watch -x run

这是完成的、最终版的代码,在修改路径后可以直接使用。

此时,在开发项目的时候,实现了自动(单向)同步项目到存储卷、自动重启项目的服务,而不是重启 docker 容器。


本文内容到此为止,仅供参考;转载需注明出处。


Comment