背景:基于 CentOS 7 系统的 Airflow 调度平台,部署一个定时任务,每天需要向 Windows 共享文件夹中生成 Excel 数据文件。Windows 共享文件夹地址为 \\share-fold\\data
,可通过 ping
获取到其对应 IP 为 1.1.1.1
,当前用户在 Winows 资源管理可直接打开该共享文件夹。
如果我们是在 Windows 系统上部署定时任务,在 Python 脚本中可以使用 os.system("net use \\1.1.1.1\\data")
,然后通过 shutil.copy
的方式将本地文件复制到共享文件夹中。由于 Windows 自带的调度系统并不好用,也无法搭建 Airflow 平台,所以很多自动化任务都是借助于 Linux 下 Airflow 进行调度的。但 Linux 下如何操作 Windows 共享文件夹,本篇文章做一个系统介绍。
1. Linux操作WINs共享文件夹原理
Linux 文件系统下并不会有 Windows 共享文件夹,也无法通过 Terminal 进入,且 Linux 系统的账号和 Windows 系统的账号是独立的,也就是说 Windows 账号具备访问共享的权限,但不意味着 Linux 用户(相同账户名)就可以直接访问。
实现 Linux 用户操作 Windows 共享文件夹的方法:通过挂载的方式,将 Windows 共享文件夹作为磁盘,挂载到 Linux 指定目录下,然后 Linux 端在指定目录下操作都会同步到 Windows 共享文件夹中,比如创建一个新的文件。
2. 必须条件
首先需要确保在 Windows 端权限问题:
- 所使用的账户可以在资源管理器中输入共享地址可以正常打开,即具备访问权限
- 所使用的账户在该共享文件夹中可以可以创建、删除、移动文件
其次,我们来看 CentOS 端所需要具备的条件:
- CentOS 的系统版本至少为 7 以上(实测 CentOS 6 及 6 以下的系统版本,某些共享文件夹始终无法挂载上,且没有任何办法解决该问题)
- CentOS 用户具备
sudo
权限,因为mount
命令只能在具备 root 权限用户使用。 - 确保 CentOS 下存在指定挂载的文件夹,如果 CentOS 下指定路径不存在,挂载命令并不会帮你创建文件夹。
- 已经安装
cifs-utils
组件,未安装的话,挂载命令之后会提示写保护(write-protected)提示,即无法向文件夹中写入文件。如未安装,请终端下执行下面代码$ sudo yum install cifs-utils -y
2. 挂载Windows共享
使用mount
命令来挂载共享文件夹,其中//1.1.1.1/data
为共享文件夹的地址,/home/yumingmin/data
为 CentOS 下的目录,如成功挂载的话,//1.1.1.1/data 将会全部显示在/home/yumingmin/data
目录下。 ```bash $ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin
查看一下是否挂载成功
$ mount -l //1.1.1.1/data on /home/yumingmin/data type cifs (rw,relatime,vers=default,cache=strict,username=yumingmin,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=1.1.1.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
正常的话,执行上述代码后,就可以看到共享已经被成功挂载了。如果出现 `host is down` 的错误,那么有可能是协议版本不匹配,可以加上 `vers=2.0` 或者 `vers=3.0` 尝试一下,但并不能保证一定可以解决问题。
```bash
$ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin,vers=2.0
# 或者
$ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin,vers=3.0
值得注意的时,我们看到 mount -l
结果出现了 file_mode=0755,dir_mode=0755
,显然这个只有 root 账号才有写入权限,非 root 账号并没有写入权限。
我们先尝试用非 root 账号尝试生成一个文件,显示 Permission denied
错误,权限不够。切换到 root 用户下,执行上述操作,是可以成功执行的。
$ touch ~/data/402.txt
touch: cannot touch ‘/home/yumingmin/data/402.txt’: Permission denied
让我们来看一下该文件夹的相关属性,其 owner 都是 root 用户,且权限为 755。
$ ls -la |grep data
drwxr-xr-x 2 root root 4096 Nov 5 14:33 data
这种模式下,我们唯一可做的操作:在非挂载目录下创建一个文件,然后通过 sudo
权限复制或者移动到挂载目录下,显然这不是我们想要的预期效果。
$ touch ~/data2/402.txt
$ sudo mv ~/data2/402.txt ~/data
2.1 失败的尝试:更改文件夹属性
既然所挂载的目录权限有问题,那我们先来更改一下文件夹的相关属性,来让非 root 用户有写入权限。
# 添加写入权限
$ sudo chmod -R 777 ~/data
$ ls -la |grep data
drwxr-xr-x 2 root root 4096 Nov 5 14:33 data
# 更改文件夹 owner
$ sudo chown yumingmin:yumingmin ~/data
$ ls -la |grep data
drwxr-xr-x 2 root root 4096 Nov 5 14:33 data
显然,我们尝试了添加写入权限和更改文件夹 owner 的方式,都没有对文件夹权限产生影响。即使是切换到 root 用户下执行,也是一样的结果。所以,此路不通。
2.2 解决方法:挂载时就添加权限
我们可以设置 dir_mode
和 file_mode
参数,在挂载时就将权限进行设置:
$ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/downloads/data \
-o username=yumingmin,password=yumingmin,vers=3.0,dir_mode=0777,file_mode=0777
$ mount -l
//1.1.1.1/data on /home/yumingmin/data type cifs (rw,relatime,vers=default,cache=strict,username=yumingmin,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=1.1.1.1,file_mode=0777,dir_mode=0777,soft,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
$ ls -la |grep data
drwxrwxrwx 2 root root 4096 Nov 5 14:33 data
$ ls -la ~/data
total 50108
drwxrwxrwx 2 root root 4096 Nov 5 14:33 .
drwxrwxr-x 4 yumingmin yumingmin 4096 Nov 5 13:25 ..
-rwxrwxrwx 1 root root 778000 Jul 16 2020 401.txt
可以看到 dir_mode
和 file_mode
参数的值都是 0777 了,且文件夹及其子文件的权限都是 777。我们重新执行下创建文件的操作,可以看到成功生成文件了,大功告成😉。
$ touch ~/data/402.txt
$ ls -la ~/data
total 50108
drwxrwxrwx 2 root root 4096 Nov 5 14:33 .
drwxrwxr-x 4 yumingmin yumingmin 4096 Nov 5 13:25 ..
-rwxrwxrwx 1 root root 778000 Jul 16 2020 401.txt
-rwxrwxrwx 1 root root 778000 Jul 16 2020 402.txt
3. 卸载WINs共享
卸载 WINs 共享就比较简单了,使用 umount
命令来卸载共享文件夹的挂载,当然也是需要 root
权限下执行。值得注意的是,我们卸载的目录是 /home/yumingmin/data
,而非 //1.1.1.1/data
。
$ sudo umount /home/yumingmin/data
3.1 报错:target is busy
如果挂载出现 target is busy
的错误,无法卸载共享,大概率是你在挂载的共享文件夹下执行的该操作,只要退出去,再执行卸载操作即可。
3.2 报错:device is busy
如果挂载出现 device is busy
的错误,无法卸载共享,可以强制卸载:
$ sudo umount -f /home/yumingmin/data