由于项目中有一个备份到外部存储设备的需求,我们用的是docker部署环境
设备:树莓派4B
外接存储:U盘或者移动硬盘(移动硬盘可能因为电压问题不稳定)
模块:file (api接口,主要作用是文件上传下载,管理等)
docker-compose.yml
component_name:
container_name: component_name
image: image:release
restart: always
depends_on:
postgresql:
condition: service_healthy
privileged: true
volumes:
- /dev:/dev
- /home/xxxx/data:/data
environment:
SQL_DATABASE: file
SQL_HOST: postgresql
SQL_PORT: 5432
SQL_USER: xxxx
SQL_PASSWORD: xxxx
DATA_PATH: /data/
NOTIFY_AMQP_URL: "amqp://xxxx:xxxx@rabbitmq:5672"
NOTIFY_QUEUE_NAME: fileChangelogs
NOTIFY_AMQP_ENABLE: "on"
GIN_MODE: debug
SENTRY_DSN: https://xxxx
SENTRY_RELEASE: xxxx@1.0.0
SENTRY_ENVIRONMENT: release
RESERVED_SPACE: 40802189312
重点就在于
privileged: true
volumes:
- /dev:/dev
privileged 用于获得宿主机root权限,可以操作/dev设备
然后volumes 将宿主机的 /dev 挂载到 docker 镜像内的/dev,这样usb设备接入的时候,就可以在docker镜像内发现了。
下面就可以在应用内利用接口+shell脚本的方式来挂载usb设备了
挂载脚本
#!/bin/sh
NEW_USB_DEVICE=`ls /dev/ | grep sd..`
FS_TYPE=`blkid|grep /dev/sd..|awk -F'TYPE=' '{print $2}'|awk '{print $1}'|sed 's/"//g'`
echo "Check New Device"
if [ ! -z ${NEW_USB_DEVICE} ]; then
echo "Check FileSytem Type."
mkdir /usb-dir >/dev/null 2>&1
if [[ "${FS_TYPE}" =~ "ntfs" ]]; then
echo "Mounting NTFS...."
mount -t ntfs-3g /dev/${NEW_USB_DEVICE} /usb-dir
else
echo "Mounting ....."
mount /dev/${NEW_USB_DEVICE} /usb-dir || mount -t ntfs-3g /dev/${NEW_USB_DEVICE} /usb-dir
fi
else
echo "No USB_DEVICE"
exit 1
fi
MOUNT_INFO=$(df -h | grep "/dev/${NEW_USB_DEVICE}")
# check mounted device
echo "Check Mounted Device"
if [ ! -z "${MOUNT_INFO}" ]; then
USB_DEVICE=$(ls /dev/| grep sd..)
if [ ! -z $USB_DEVICE ]; then
echo "Mount ${USB_DEVICE} Successfully"
exit 0
else
umount /usb-dir
echo "Device Not Found"
exit 1
fi
else
echo "Mount ${USB_DEVICE} Failed"
exit 1
fi
执行接口(Gin框架)
// MountUsbDevice 检查USB外置设备是否准备就绪
// @Summary 检查USB外置设备是否准备就绪
// @Description 检查USB外置设备是否准备就绪
// @Tags Backup
// @Accept application/json
// @Produce application/json
// @Param userId query string true "用户id"
// @Success 200 {object} proto.Rsp{results=proto.BackupUSBDevice} "返回值"
// @Router /space/v1/api/backup/mount [POST]
func MountUsbDevice(c *gin.Context) {
defer c.Request.Body.Close()
ctx := bpctx.NewCtx(c)
//var rsp proto.Rsp
var backupUSBDevice proto.BackupUSBDevice
if ctx.GetUserId() != 1 {
ctx.SendErr(proto.CodeUserIdError, nil)
}
// 执行挂载检测脚本
var out bytes.Buffer
var info bytes.Buffer
getInfoCmd := exec.Command("sh", "/usr/bin/get_deviceinfo.sh")
getInfoCmd.Stdout = &info
infoErr := getInfoCmd.Run()
if infoErr != nil {
backupUSBDevice.DeviceName = "未知设备"
} else {
backupUSBDevice.DeviceName = info.String()
}
//执行挂载
mountCmd := exec.Command("sh", "/usr/bin/mount_usb.sh")
mountCmd.Stdout = &out
err := mountCmd.Run()
logger.LogI().Interface("stdout", out.String()).Msg("Mount Usb Device")
if err != nil {
ctx.SendErr(proto.CodeMountFailed, err)
return
} else {
ctx.SendOk(&backupUSBDevice)
return
}
}