问题/说明
我确信我添加的 vagrant box 没有损坏,因为我在 mac 机器上使用过它并且它工作正常......
通过执行以下操作,我能够在各种场合重现此问题:
-
在 macOS 中创建一个 Virtualbox VM(基于 Intel 的 mac 运行任何东西...Mojave、Catalina、Mojave、Big Sur 等...)
-
vagrant package --base $VIRTUALBOX_VM_NAME_HERE --output test.box
-
将.box 文件传输到 Ubuntu
-
vagrant box add --provider virtualbox --name $VAGRANT_BOX_NAME_HERE test.box
-
解压错误:
The box failed to unpackage properly. Please verify that the box
file you're trying to add is not corrupted and that enough disk space
is available and then try again.
The output from attempting to unpackage (if any):
x ./include/
x ./include/README.md
x ./include/_Vagrantfile
x ./include/LICENSE
x ./metadata.json
x ./box.ovf
x ./Vagrantfile
x ./info.json
x ./box-disk001.vmdk: gzip decompression failed
bsdtar: Error exit delayed from previous errors.
答案就在错误信息背后的隐藏上下文中:
bsdtar: Error exit delayed from previous errors.*
请注意,这个 vagrant box add ... 是在 Ubuntu 上运行的,并且正在尝试使用 bsdtar 而不是通常的 tar 命令解压缩。 .box 文件是在 macOS 上创建的,并使用其自己的 bsdtar 版本进行压缩。通常,Linux 上的原生.tar 文件是使用tar 的GNU 版本创建的。 There are some important differences between bsdtar, GNU tar, and the Linux version libarchive bsdtar.
这意味着我们不能期望在所有情况下都在一个平台上创建一个.tar 文件,并且能够在没有可以处理该文件的tar 的适当兼容版本的情况下在另一个平台上解压它。该文件没有损坏,只是与 Linux 版本的 bsdtar 预期处理的格式不同。
人们可能会认为vagrant package 旨在创建一个可移植的.box 文件。然而,由于经典 bsdtar、libarchivebsdtar 和 GNU tar 之间的差异,我们最终遇到了不可移植性问题。虚拟机磁盘文件通常使用稀疏文件实现。 VirtualBox 将稀疏文件用于.vmdk 文件格式,以支持动态增长和缩小来宾 VM 磁盘,同时在主机操作系统上仍然保持相对较小。根据您的版本,bsdtar handles these sparse files differently 比其他版本的tar。 Vagrant 使用bsdtar,但这并不能确保生成的.box 文件在系统之间是兼容的和完全可移植的。 MacOS 附带的 bsdtar 版本与当前在 Ubuntu Linux 上可用的版本不同。
macOS 大苏尔
$ sw_vers
ProductName: macOS
ProductVersion: 11.6.1
BuildVersion: 20G224
$ ls -l /usr/bin/tar
lrwxr-xr-x 1 root wheel 6 Jan 1 2020 /usr/bin/tar -> bsdtar
$ bsdtar --version
bsdtar 3.3.2 - libarchive 3.3.2 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.6
Ubuntu Focal Fossa
$ lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
$ tar --version
tar (GNU tar) 1.30
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by John Gilmore and Jay Fenlason.
$ apt-cache show libarchive-tools | grep 'Description-en'
Description-en: FreeBSD implementations of 'tar' and 'cpio' and other archive tools
$ sudo apt-get install libarchive-tools
$ bsdtar --version
bsdtar 3.4.0 - libarchive 3.4.0 zlib/1.2.11 liblzma/5.2.4 bz2lib/1.0.8 liblz4/1.9.2 libzstd/1.4.4
解决方案
我为这个问题找到的一种解决方法是避免在 macOS 上使用由vagrant package 创建的.box 文件。除非您还导入到另一台 macOS 机器,否则由于 bsdtar 问题,此 .box 文件将无法工作。相反,从$HOME/.vagrant.d/boxes/$VAGRANT_BOX_NAME_HERE 中单独复制文件。这些是裸露的 VirtualBox .ovf 和 .vmdk 文件,它们也应该与 Linux 上的 VirtualBox 兼容。一旦通过您喜欢的任何方法将这些文件安全地传输到 Linux,它们就可以在那里加载到 VirtualBox 或通过 vagrant 命令直接从 .vagrant.d/boxes 使用。
您有几个选项可以传输文件。我建议使用rsync 来避免tar 和bsdtar 出现问题。
# From macOS machine
rsync --progress -av ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name target-machine.local:~/.vagrant.d/boxes/
# Or... from Linux machine side
rsync --progress -av your-mbp.local:~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name ~/.vagrant.d/boxes/
注意:在rsync 源路径和目标路径中,斜线/ 很重要! See this brief rsync tutorial for help using rsync
文件传输后,请务必检查它们是否相同。我使用 shasum -a 256 为文件生成 SHA256 哈希。两边的哈希值应该匹配。
# Check on both machines separately...
cd ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name/0/virtualbox/
shasum -a 256 box-disk001.vmdk
# Or... use `shasum -c -` and SSH for a one-liner:
# Prints "OK" and exit status 0 if checksums match
( cd ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name/0/virtualbox/ && shasum -a 256 box-disk001.vmdk ) | ssh exampleuser@your-mbp.local '( cd ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name/0/virtualbox/ && shasum -a 256 -c - )'
如果你真的想尝试使用[bsd]tar 或.box 文件...
另一个选项是using gnu-tar from Homebrew 将文件重新打包为兼容的.tar 存档。然后将其复制并解压缩到.vagrant.d/boxes。我试过了,发现它仍然在 Linux 端导致了一个不相同的.vmdk 磁盘文件。 (在两台机器上使用sha256sum 或perl 的shasum -a 256 进行检查)。
另一个选择是在 Ubuntu 机器上使用来自 libarchive-tools 包的 bsdtar。我试过这个并且能够从vagrant box add重现同样的错误
# View .box file contents
bsdtar -v -t -f /path/to/Vagrant_Box/example.box
# Try to extract
mkdir ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name
cd ~/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name
bsdtar -v -x -f /path/to/Vagrant_Box/example.box
x ./include/
x ./include/README.md
x ./include/_Vagrantfile
x ./include/LICENSE
x ./metadata.json
x ./box.ovf
x ./Vagrantfile
x ./info.json
x ./box-disk001.vmdk: gzip decompression failed
bsdtar: Error exit delayed from previous errors.
因此,最好避免在这些平台上使用tar 和bsdtar,因为它们对box-disk001.vmdk 稀疏文件的处理不兼容。
Vagrant Box 格式内容
正如我们在上面看到的,.box 解压结构的示例可能类似于以下内容:
/Users/exampleuser/.vagrant.d/boxes/someuser-VAGRANTSLASH-vagrant-box-example-name/
└── 0
└── virtualbox
├── Vagrantfile
├── box-disk001.vmdk
├── box.ovf
├── include
│ ├── LICENSE
│ ├── README.md
│ └── _Vagrantfile
├── info.json
└── metadata.json
3 directories, 8 files
注意:info.json 文件和include 下的任何内容(例如:README.md、_Vagrantfile)都是可选的。这些可以通过vagrant package 选项添加:--vagrantfile、--info 和--include。它们不是运行 VM 所必需的。
这些文件可以以相同的结构放入 Ubuntu 机器的 ~/.vagrant.d/boxes/ 文件夹中。确保盒子目录名称与您的预期盒子名称匹配(例如:目录someuser-VAGRANTSLASH-vagrant-box-example-name = 盒子名称someuser/vagrant-box-example-name)。
设置Vagrantfile 以使用盒子名称运行盒子,然后照常运行vagrant up。
示例:
Vagrant.configure("2") do |c|
c.berkshelf.enabled = false if Vagrant.has_plugin?("vagrant-berkshelf")
c.vm.box = "someuser/vagrant-box-example-name"
c.vm.hostname = "default-vagrant-box-example-name.vagrantup.com"
c.vm.boot_timeout = 1200
c.vm.synced_folder ".", "/vagrant", disabled: true
c.vm.provider :virtualbox do |p|
p.name = "vagrant-box-example-name"
p.customize ["modifyvm", :id, "--audio", "none"]
end
end
macOS 虚拟机笔记
如果有问题的 .box 文件是 macOS 虚拟机,那么您可能仍然无法在 Linux 上轻松运行它。原因是 Apple 的 boot.efi 具有 macOS 特定的启动固件。从技术上讲,不支持在非 Apple 硬件上运行 macOS(你知道......因为资本主义......??)。鉴于创建硬件 Hackintosh 机器是可能的,我敢肯定有人已经想通了。我还没有找到让这个工作的方法,但也许其他人知道......?