[!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 容器。
本文内容到此为止,仅供参考;转载需注明出处。