本文的内容是之前三篇内容的结合:
《Docker for Windows 自动共享本机文件的脚本示例》
http://blog.csdn.net/hu_zhenghui/article/details/79087151
《从一台 Windows 10 上访问另一台 Windows 10上创建的Docker虚拟机》
http://blog.csdn.net/hu_zhenghui/article/details/79142123
《从Windows 10共享文件夹给Docker虚拟机中的Docker的神奇bug》
http://blog.csdn.net/hu_zhenghui/article/details/79165268
脚本的功能和之前区别不大,结构有了较大变化,脚本做了参数化,以便于使用。
本脚本也不限制从一台 Windows 10 上共享文件夹给另一台 Windows 10 上的 Docker 虚拟机中的Docker。
也可以是从一台 Windows 10 上共享文件夹给另一台 Mac OXS 上的 Docker 虚拟机中的Docker。
或者是从一台 Windows 10 上共享文件夹给另一台 Linux 上运行的 Docker。
最后一种情况是本文的核心内容。
强调虚拟机的原因在于,借助自动共享 Windows 10 上的文件夹,让 Docker 运行中改变的状态都保留在这个文件夹中,运行后 Docker 进程和所在的虚拟机都恢复原样,也就是把 Docker 当成本身不持有状态的函数调用。

# 自动共享 Windows 的文件夹到 Docker 主机
## git clone https://github.com/huzhenghui/share-windows-folder-to-docker
## share-windows-folder-to-docker/share-windows-folder-to-docker.ps1
## Docker for Windows 使用 Hyper-V,而 Hyper-V 自身并没有包含设备驱动方式的文件共享,因此只能使用 Windows 自带的 SMB 文件共享,SMB 也称 CIFS
## Docker for Windows 的客户端可以使用图形界面设置文件共享,不过技术实现方式也是 SMB,而且自动创建的文件共享对于局域网是开放的,未免有安全隐患
# 本脚本用于使用 Docker-Machine 命令可以访问到的 Docker 主机
## 可以用于使用 Docker-Machine 命令在本机 Hyper-V 中创建的 Docker 虚拟机中共享文件,也就是 Host Windows - Guest Linux - Docker
## 也可以用于本机使用 Docker-Machine 命令可以管理的在相同局域网内的其他 Docker 主机,也就是 Windows - Intranet - Linux - Docker
## 本脚本假设 Docker-Machine 命令能查询到至少一台 Docker 主机,如果该 Docker 主机安装在当前 Windows 的 Hyper-V 中,则可以采用虚拟交换机方式保证在相同局域网
## 使用 Hyper-V 的虚拟交换机方式创建虚拟机的命令类似于:docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1
# 本脚本运行时自动创建用于共享的用户,自动创建共享文件夹,自动在 Docker 主机中加载,并生成用于测试的命令
# 本脚本中的密码不仅随机生成,而且密码不保存在任何持久存储。不过仍旧建议不要在 Windows 的系统文件夹中运行本脚本,避免共享系统文件夹导致的安全隐患
# 免责声明:本脚本涉及技术较多,包括:PowerShell、Unix Shell、WMI、Docker,而且需要运行在管理员角色,在不同环境可能导致难以预期的结果,仅供学习参考
# 本脚本使用方法:创建一个英文名称的文件夹,其中创建一个 .ps1 文件,把本脚本的内容完整复制进去,然后运行 PowerShell 管理员控制台,进入文件夹,运行脚本
# 参数
## -workingDir 要共享的文件夹,如果不提供,或者不是文件夹,则使用当前文件夹
## -machineName Docker 主机的名称,应处于 docker-machine ls 列表中,如果不提供或者不存在或者不处于 Running 状态,则使用 docker-machine ls 列表中处于 Running 状态的第一台主机
## -volumeName 共享到 Docker 主机上的卷的名称,如果不提供,则自动生成
## -sharePath 共享的文件夹名称,如果不提供,则自动生成,该参数自动传入 Docker 主机,使用时并不涉及
## -userName 共享的文件夹的用户,如果不提供,则自动生成,该参数自动传入 Docker 主机,使用时并不涉及
## -password 共享的文件夹的用户的密码,如果不提供,则自动生成,该参数自动传入 Docker 主机,使用时并不涉及
## -replaceVolume 当 Docker 主机上包含同名的卷的名称时,替换已有设置,否则退出
Param([string]$workingDir,[string]$machineName,[string]$volumeName,[string]$sharePath,[string]$userName,[string]$password,[switch]$replaceVolume
)
# 常量
## 安全字符
$safe_charactors = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
# 参数
## workingDir
### 判断要共享的文件夹,如果不提供,或者不是文件夹,则使用当前文件夹
if ([string]::IsNullOrEmpty($workingDir))
{$workingDir = (Get-Location).Path
}
elseif (-Not ([io.Directory]::Exists($workingDir)))
{$workingDir = (Get-Location).Path
}
echo "Working Directory : " $workingDir
### 获取路径的最后一段,也就是文件夹名,由于后面会多次使用该文件夹名,避免出现字符集问题建议使用纯英文,或者手工设置
$directory_name = [System.IO.Path]::GetFileName($workingDir)
echo "Directory Name : " $directory_name
### 为了避免文件夹名重复,通过计算路径的散列值区分
### 把字符串转换成内存中的流计算散列值,从这里也可以看出 PowerShell 实现的合理性,因为 PowerShell 中的字符串是字符,而散列值需要按照字节计算,因此需要按照字符集转换,此处使用 MD5 算法
$directory_hash = Get-FileHash -Algorithm MD5 -InputStream ([System.IO.MemoryStream]::new((new-object -TypeName System.Text.UTF8Encoding).GetBytes($workingDir))) | Select-Object -ExpandProperty Hash
echo "Directory Hash : " $directory_hash
### 为了避免路径中的非ASCII字符,对文件夹名进行过滤
$directory_filter_name = ""
foreach($c in $directory_name.ToCharArray()) {if ($safe_charactors.Contains($c)) {$directory_filter_name += $c}}
echo "Directory Filter Name : " $directory_filter_name
## volumeName
### 判断是否设置了卷参数
if([string]::IsNullOrEmpty($volumeName))
{### 卷的名称,使用前缀和散列值区分$volumeName = -Join('Share_for_Docker_', $directory_filter_name, '_', $directory_hash)
}
## sharePath
### 判断是否设置了共享路径参数
if([string]::IsNullOrEmpty($sharePath))
{### 共享文件夹名称,使用前缀和散列值区分$sharePath = -Join('Share_for_Docker_', $directory_filter_name, '_', $directory_hash)
}
echo "Share Path : " $sharePath
## userName
### 判断是否设置了用户名参数
if([string]::IsNullOrEmpty($userName))
{### 用于共享的用户名增加 Docker 前缀,以便于未来管理$userName = -Join('Docker_', $directory_filter_name)### 由于 Windows 用户的用户名最长 20 字符,为了后面的散列值,按照 13 个字符截断if ($userName.Length -gt 13) {$userName = $userName.Substring(0, 13)}### 用户名增加散列值作为后缀$userName = -Join($userName, '_', $directory_hash)### 由于 Windows 用户的用户名最长 20 字符,按照 20 个字符截断if ($userName.Length -gt 20) {$userName = $userName.Substring(0, 20)}
}
echo "User Name :" $userName
## password
### 判断是否设置了密码参数
if([string]::IsNullOrEmpty($password))
{### 密码使用随机自动生成for($password = $Null ; $password.length -le 32; $password += "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray() | Get-Random){}
}
echo "Password Generated"
# 判断参数
## machineName
### 判断是否设置了 machineName 参数
if(-not [string]::IsNullOrEmpty($machineName))
{### 判断是否存在名称为 machineName 且正在运行的 Docker 主机if((docker-machine ls --filter 'STATE=Running' --filter "Name=${machineName}" --format '{{.Name}}') -eq $Null){### 如果不存在说明 machineName 参数无效,设置为空$machineName = $Null}
}
### 判断是否设置了 machineName 参数
if([string]::IsNullOrEmpty($machineName))
{$machineName = $(docker-machine ls --filter 'STATE=Running' --format "{{.Name}}" | Select-Object -First 1)
}
### 判断是否设置了 machineName 参数
if([string]::IsNullOrEmpty($machineName))
{echo 'machineName invalid and/or no running docker machine'exit
}
### docker 环境变量
### 使用 docker-machine 命令生成环境变量并运行,以便于后续的的 docker 命令直接使用,注意此处为了解决中文问题做了转码,
foreach ($line in (& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env $machineName))
{
[System.Text.Encoding]::GetEncoding("utf-8").GetString([System.Text.Encoding]::GetEncoding("gb2312").GetBytes($line)) |  Invoke-Expression
}
## volumeName
### 判断是否存在名称为 volumeName 的卷
if((docker volume ls --filter "Name=${volumeName}" --format '{{.Name}}') -ne $Null)
{echo 'Volume Name exist : ' $volumeNameif($replaceVolume.IsPresent){echo 'Remove Existence volume'docker volume rm --force ${volumeName}echo 'Existence volume removed'}else{exit}
}
## sharePath
### 判断共享路径是否存在
#[WMICLASS]"WIN32_Share"
if((Get-WmiObject -Class Win32_Share -Filter "name = '$sharePath'") -ne $Null)
{### 共享路径存在的时候退出,由人工处理echo "Share path exist : " $sharePathexit
}
## userName
### 判断用户名是否存在
if((Get-WmiObject -Class Win32_UserAccount -Filter "name = '${userName}'") -ne $Null)
{### 用户存在的时候退出,由人工处理echo "User Exist : " $userNameexit
}
# 创建用户
$winnt_localhost = [ADSI]"WinNT://localhost"
## 创建用户对象
$new_user = $winnt_localhost.create("user", $userName)
## 设置密码
$new_user.setpassword($password)
## 设置信息,用户只有设置信息后才会创建,因此没有参数也要调用
$new_user.setinfo()
## 设置这个账户的密码永远不过期
Get-WmiObject -Class Win32_UserAccount -Filter "name = '${username}'" | Set-WmiInstance -Argument @{PasswordExpires = 0}
# 文件夹权限
## 创建一个访问规则
$access_rule = New-Object System.Security.AccessControl.FileSystemAccessRule($userName, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
## 获取当前路径的访问控制列表
$acl = Get-Acl $workingDir
## 在访问控制列表中添加访问规则
$acl.SetAccessRule($access_rule)
## 在当前路径中设置访问控制列表
Set-Acl -Path $workingDir -AclObject $acl
# 共享文件夹
## 创建一个信任用户对象
$Trustee = ([wmiclass]'Win32_trustee').psbase.CreateInstance()
## 设置信任用户的名字
$Trustee.Name = $userName
## 设置信任用户的域,本地域为空
$Trustee.Domain = $Null
## 创建一个访问控制对象
$ACE = ([WMIClass] "Win32_ACE").psbase.CreateInstance()
## 访问控制的掩码,Magic Number,具体含义请自行搜索
$ACE.AccessMask = 2032127
## 访问控制的标志
$ACE.AceFlags = 3
## 访问控制的类型
$ACE.AceType = 0
## 访问控制的信任用户
$ACE.Trustee = $Trustee
## 创建一个安全描述对象
$sd = ([WMIClass] "Win32_SecurityDescriptor").psbase.CreateInstance()
## 安全描述的标志
$sd.ControlFlags = 4
## 安全描述的访问控制
$sd.DACL = $ACE
## 安全描述的信任用户组
$sd.group = $Trustee
## 安全描述的信任用户
$sd.owner = $Trustee
## 获得共享对象
$Share = [WMICLASS]"WIN32_Share"
## 为当前文件夹创建共享文件夹
$Share.Create($workingDir, $sharePath, 0, $Null, "Share for Docker", "", $sd)
# 在虚拟机中运行脚本获取 Host Windows 的IP地址
## 此处欢迎集思广益:这种获取IP的方法不是很优雅,比较hack。先获取tty,然后切掉前面的/dev/,使用虚拟机上的w命令,按照tty过滤,最后输出第三个字段
$local_ip = $(docker-machine ssh $machineName 'tty=$(tty | cut -c 6-); w -i | grep $tty | awk ''{print $3;}''')
echo "Local IP : " $local_ip
# 加载共享文件夹
docker volume create --driver local --opt type=cifs --opt device=//${local_ip}/${sharePath} --opt o=username=${userName},password=${password} --name ${volumeName}
#演示命令
echo 'demo:'
## 这个命令在共享文件夹中随机创建一个文件
echo "docker run --rm -v ${volumeName}:/share alpine touch (get-date -Format '/\s\h\are/yyyy-MM-dd-HH-mm-ss-fffffff.\tx\t')"
## 这个命令列出共享文件夹,可以查询到刚才创建的文件
echo "docker run --rm -v ${volumeName}:/share alpine ls /share"
echo ""
echo "WARNING : '...input/output error' is a known error. This may occur with mobile storage devices"

从一台 Windows 10 上共享文件夹到Docker中的Volume卷相关推荐

  1. 桌面图标设计里的计算机是灰色的,小技巧教您如何将Windows 10上的桌面图标设置中的回收站为灰色!...

    如果Windows 10的``桌面图标设置''窗口中的``回收站''选项显示为灰色,则可以查看本逐步指南以解决问题.这将帮助您取回"桌面图标设置"面板中的"回收站&quo ...

  2. Windows 7 Windows 10配置共享文件夹

    文章目录 1.准备 1.1 关闭防火墙 1.2 开启文件共享 1.3 下载共享文件 后言 平时我们在工作或学习中中经常需要将自己的文件复制给他人或者将他人的文件复制过来的需求.然而部分情况是需要复制的 ...

  3. 从Windows 10共享文件夹给Docker虚拟机中的Docker的神奇bug

    一,回顾 这篇文章是基于之前发布的脚本 http://blog.csdn.net/hu_zhenghui/article/details/79087151 不过在更多的设备上测试的时候,发现时灵时不灵 ...

  4. c++如何获取文件时间_如何在Windows 10上获取文件或文件夹的所有权

    要访问Windows 10上的任何文件或文件夹,你必须具有相应的权限.遗憾的是,如果你没有编辑某些文件和文件夹的权限,则可能会出现某些问题,这时你必须对该文件夹或文件取得所有权. 要想取得某个文件夹的 ...

  5. 如何在Windows 10上使用Microsoft Defender扫描文件或文件夹中的恶意软件

    On Windows 10, Microsoft Defender (formerly called "Windows Defender") always scans files ...

  6. 获取Windows 10上文件资源管理器的帮助

    Windows 10 no longer has built-in help for File Explorer, as Windows 7 does. Microsoft makes you sea ...

  7. 设置代理_如何防止用户更改Windows 10上的代理设置

    如何在Windows 10上禁用代理设置 在Windows 10上,可以使用组策略编辑器和注册表以至少两种不同的方式禁用通过"设置"应用程序(和" Internet选项& ...

  8. vscode重置应用程序_如何在Windows 10上重置应用程序的数据

    vscode重置应用程序 With Windows 10's Anniversary Update, you can now reset an app's data without actually ...

  9. 如何在 Windows 10 上安装 WSL 2

    翻译自 Joey Sneddon 2020年10月30日的文章<How to Install WSL 2 on Windows 10> [1] 如果您想在最新的 Windows 版本中尝试 ...

最新文章

  1. 一文读懂Faster RCNN
  2. 【 C 】const 学习笔记
  3. DevExpress的下拉框控件ComboBoxEdit控件的使用
  4. 科大星云诗社动态20201120
  5. VTK:PolyData之MiscCellData
  6. 解决C# 7.2中的结构体性能问题
  7. CUBA平台正在开源
  8. 1023. 组个最小数 (20)
  9. 编写一个程序,找出数组中元素的最大值,要求用到成员函数。
  10. pandas 日期处理
  11. 2021年C++项目中的十大Bug:乍一看都正确的代码,实则暗藏玄机
  12. 物体识别_深度学习在物体识别中的应用探讨:以ImageNet和人脸识别为例
  13. Fuchsia中GN与Ninja构建demo
  14. Android 隐藏ImageView
  15. java基础七--网络编程(1)
  16. springboot和springframework以及jdk版本的对应关系
  17. 百度人脸识别,一次耗时600毫秒
  18. stm32f4串口烧录[flymcu]
  19. screen投屏怎么用_Screen投屏
  20. android 打开文件管理器选择文件

热门文章

  1. 【怎么卸载影子系统?卸载影子系统解决方法】
  2. tif文件转为shp文件_在arcgis中怎么把tif格式的遥感图像转换为矢量图
  3. oracle中如何转换成数字,如何在Oracle中实现数字进制转换完全版?
  4. 使用 VMware Server 在 Linux 上安装 Oracle RAC 10g
  5. linux启动时、登录时或注销时执行脚本
  6. 随机森林(Random Forest)算法原理
  7. nginx $1,2,3的含义
  8. 做人,该善良时就善良,该勇敢时就要有勇气去对应
  9. python批量下载网页图片,不用再复制粘贴了(7)
  10. 基于spring boot的毕业设计论文选题申报管理系统