Vagrantfile是声明式环境定义文件,自动化安装需通过config.vm.provision块指定shell脚本或Ansible等provisioner执行;直接写apt命令会因Ruby语法误解而仅在宿主机运行。

Vagrantfile 本身不是“自动化脚本”的配置入口,而是声明式环境定义文件;真正执行自动化安装的,是 config.vm.provision 块里指定的 shell 脚本、Ansible Playbook 或其他 provisioner。
为什么直接在 Vagrantfile 里写 install php 命令会失败
很多人误以为在 Vagrantfile 中直接写 apt install -y php 就能运行,但这是 Ruby 文件,不是 Shell 脚本 —— 所有系统级命令必须包裹在 config.vm.provision 块中,由 Vagrant 在虚拟机启动时调用对应 provisioner 执行。
- 裸写命令(如
`apt update`)会被 Ruby 解释为反引号命令替换,仅在宿主机执行,对虚拟机无效 - 不指定
type的provision默认使用 shell,但路径、权限、执行时机(run: "always"还是"once")必须显式控制 - 若用
privileged: false,则无法执行需要 root 权限的 apt/yum 操作,报错类似E: Could not open lock file
怎么让 Vagrant 启动时自动装 PHP + Apache + MySQL
最轻量、最可控的方式是用内联 shell provisioner。以下片段可直接插入 Vagrantfile 的 config 块内(注意缩进和 Ruby 语法):
config.vm.provision "shell", inline:
- 使用
多行字符串避免转义问题,结尾SHELL必须顶格且无空格 -
DEBIAN_FRONTEND=noninteractive防止 apt 安装时卡在交互式配置(如 tzdata) - 首次
vagrant up会执行;后续vagrant reload --provision可重跑,但不会自动清理旧状态
用外部 shell 脚本更利于调试和复用
把安装逻辑拆到独立文件(如 provision.sh),比内联更易维护。Vagrant 会将该脚本复制进虚拟机并执行:
config.vm.provision "shell", path: "provision.sh", privileged: true
-
path是相对于Vagrantfile的路径,不是绝对路径 -
privileged: true(默认值)确保以 root 身份运行,否则多数服务安装会失败 - 脚本开头建议加
#!/bin/bash -e,遇到任意命令失败立即退出,避免半截环境 - 若脚本含中文注释或特殊字符,保存为 UTF-8 编码,否则 Vagrant 复制后可能乱码报错
常见 Provisioning 失败原因和绕过方法
执行 vagrant up 后 provision 卡住或报错,往往不是脚本本身问题,而是环境前置条件缺失:
-
vagrant ssh登录后手动执行脚本第一行,看是否提示command not found—— 很可能是 Ubuntu 镜像未预装curl/wget,需先apt install -y curl - 网络超时导致
apt update失败:在provision.sh开头加apt-get clean && rm -rf /var/lib/apt/lists/*,再换国内源(如清华源) - MySQL 安装时因密码交互失败:用
debconf-set-selections预置 root 密码,或改用mysql_secure_installation的非交互模式 - PHP 扩展没生效:确认
php.ini路径是否正确(php --ini查看),扩展是否写入了extension=行而非仅拷贝了 so 文件
真正麻烦的从来不是写几行安装命令,而是 provisioner 执行时的上下文 —— 它不继承你的宿主机 bashrc,没有 alias,PATH 往往只有基本目录,连 lsb_release 都可能未安装。每次失败,优先 vagrant ssh 进去手动模拟,比盲改 Vagrantfile 高效得多。











