vagrant(9)Provision配置例子

vagrant provision 是 Vagrant 的核心功能之一,帮你自动在虚拟机上应用配置,省去手动操作的麻烦。它支持多种 provisioner(Shell、Ansible、Chef 等),灵活性很高。无论你是想快速搭个开发环境,还是调试复杂的部署脚本,vagrant provision 都能派上用场。


1.内容

  • Provision 简介:自动化配置虚拟机环境(如安装软件、配置服务)。
  • 支持的 Provision 类型
    • Shell:最简单的脚本方式,支持内联和外部脚本。
    • Ansible:使用 playbook 进行声明式配置。
    • Puppet:通过 manifests 实现配置管理。
    • Chef:使用 cookbooks 进行自动化部署。
    • Docker:直接在虚拟机中运行 Docker 容器。
    • File:将主机文件传输到虚拟机。
  • 触发 Provision:控制自动化执行时机(首次启动、每次启动、手动触发)。
  • 最佳实践:编写可复用、可维护的脚本。

provisioning support


2.使用 Shell 脚本

Shell 是最简单直接的 Provision 方式,适合快速配置或小型项目。

  1. 内联 Shell 脚本

    • 编辑 Vagrantfile,安装 Apache 并启动:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "shell", inline: <<-SHELL
      apt update
      apt install -y apache2
      systemctl start apache2
      systemctl enable apache2
      echo "<h1>Hello from Vagrant Shell Provision</h1>" > /var/www/html/index.html
      SHELL
      end
    • 启动虚拟机并运行 Provision:
      1
      vagrant up --provision
    • 验证:主机浏览器访问 http://localhost:8080,应显示自定义页面。
  2. 外部 Shell 脚本

    • 创建一个 setup.sh 文件:
      1
      2
      3
      4
      5
      6
      #!/bin/bash
      apt update
      apt install -y nginx
      systemctl start nginx
      systemctl enable nginx
      echo "<h1>Hello from Nginx</h1>" > /usr/share/nginx/html/index.html
    • 修改 Vagrantfile
      1
      2
      3
      4
      5
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "shell", path: "setup.sh"
      end
    • 确保脚本可执行:
      1
      chmod +x setup.sh
    • 启动并验证:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示 Nginx 页面。

3.使用 File Provision

File Provision 用于将主机文件传输到虚拟机,适合传输配置文件或静态文件。

  1. 传输单个文件

    • 创建一个 index.html 文件:
      1
      <h1>Hello from File Provision</h1>
    • 修改 Vagrantfile,将文件传输到虚拟机并安装 Nginx:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "file", source: "index.html", destination: "/tmp/index.html"
      config.vm.provision "shell", inline: <<-SHELL
      apt update
      apt install -y nginx
      mv /tmp/index.html /usr/share/nginx/html/index.html
      systemctl start nginx
      systemctl enable nginx
      SHELL
      end
    • 启动并验证:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示传输的页面。
  2. 传输目录

    • 创建一个目录 web_content 并添加文件:
      1
      2
      mkdir web_content
      echo "<h1>Directory Provision</h1>" > web_content/index.html
    • 修改 Vagrantfile
      1
      2
      3
      4
      5
      config.vm.provision "file", source: "web_content", destination: "/tmp/web_content"
      config.vm.provision "shell", inline: <<-SHELL
      mv /tmp/web_content /usr/share/nginx/html/web_content
      systemctl restart nginx
      SHELL
    • 访问 http://localhost:8080/web_content/index.html,验证传输。

4.使用 Ansible

Ansible 是一种声明式配置管理工具,适合复杂环境配置。

  1. 安装 Ansible(主机)
    • 在主机上安装 Ansible(以 Ubuntu 为例):
      1
      2
      sudo apt update
      sudo apt install -y ansible
  2. 创建 Ansible Playbook
    • 创建一个 playbook.yml 文件:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      - hosts: all
      become: yes
      tasks:
      - name: Install Nginx
      apt:
      name: nginx
      state: present
      update_cache: yes
      - name: Start Nginx
      service:
      name: nginx
      state: started
      enabled: yes
      - name: Copy custom index page
      copy:
      content: "<h1>Hello from Ansible</h1>"
      dest: /usr/share/nginx/html/index.html
  3. 配置 Vagrant 使用 Ansible
    • 修改 Vagrantfile
      1
      2
      3
      4
      5
      6
      7
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "ansible" do |ansible|
      ansible.playbook = "playbook.yml"
      end
      end
  4. 启动并验证
    • 启动虚拟机:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示 Ansible 配置的页面。(本机须提前安装好ansible及配置好联通性)

ansible

  • ansible #本机ansible连接到虚机上执行任务
  • ansible_local #在虚机内执行任务(须提前安装好ansible)

5.使用 Puppet

Puppet 是另一种配置管理工具,适合企业级自动化。

  1. 安装 Puppet Agent(虚拟机)
    • Vagrant 会自动安装 Puppet Agent,无需手动操作。
  2. 创建 Puppet Manifest
    • 创建一个 manifests/default.pp 文件:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      package { 'nginx':
      ensure => installed,
      }

      service { 'nginx':
      ensure => running,
      enable => true,
      require => Package['nginx'],
      }

      file { '/usr/share/nginx/html/index.html':
      ensure => file,
      content => '<h1>Hello from Puppet</h1>',
      require => Package['nginx'],
      }
  3. 配置 Vagrant 使用 Puppet
    • 修改 Vagrantfile
      1
      2
      3
      4
      5
      6
      7
      8
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "puppet" do |puppet|
      puppet.manifests_path = "manifests"
      puppet.manifest_file = "default.pp"
      end
      end
  4. 启动并验证
    • 启动虚拟机:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示 Puppet 配置的页面。

6.使用 Chef

Chef 使用 cookbooks 进行配置管理,适合复杂自动化需求。

  1. 安装 Chef DK(主机,推荐)
    • 在主机上安装 Chef DK(以 Ubuntu 为例):
      1
      2
      wget https://packages.chef.io/files/stable/chefdk/4.13.3/ubuntu/20.04/chefdk_4.13.3-1_amd64.deb
      sudo dpkg -i chefdk_4.13.3-1_amd64.deb
  2. 创建 Chef Cookbook
    • 使用 chef 命令生成 cookbook:
      1
      chef generate cookbook cookbooks/myweb
    • 编辑 cookbooks/myweb/recipes/default.rb
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      package 'nginx' do
      action :install
      end

      service 'nginx' do
      action [:enable, :start]
      end

      file '/usr/share/nginx/html/index.html' do
      content '<h1>Hello from Chef</h1>'
      action :create
      end
  3. 配置 Vagrant 使用 Chef
    • 修改 Vagrantfile
      1
      2
      3
      4
      5
      6
      7
      8
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "chef_solo" do |chef|
      chef.add_recipe "myweb::default"
      chef.cookbooks_path = "cookbooks"
      end
      end
  4. 启动并验证
    • 启动虚拟机:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示 Chef 配置的页面。

8.使用 Docker

Docker Provision 允许在虚拟机中直接运行 Docker 容器。

  1. 配置 Docker Provision
    • 修改 Vagrantfile,安装 Docker 并运行一个 Nginx 容器:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      Vagrant.configure("2") do |config|
      config.vm.box = "Ubuntu/jammy64"
      config.vm.network "forwarded_port", guest: 80, host: 8080
      config.vm.provision "docker" do |d|
      d.run "nginx",
      image: "nginx:latest",
      args: "-p 80:80"
      end
      end
  2. 启动并验证
    • 启动虚拟机:
      1
      vagrant up --provision
    • 主机浏览器访问 http://localhost:8080,显示 Nginx 容器页面。

9.控制 Provision 触发

  1. 手动触发
    • 启动时不运行 Provision:
      1
      vagrant up --no-provision
    • 手动运行:
      1
      vagrant provision
  2. 每次启动触发
    • Vagrantfile 中设置:
      1
      config.vm.provision "shell", path: "setup.sh", run: "always"

run: once,always,never


10.代码示例

  1. Shell 内联
    1
    2
    3
    4
    5
    config.vm.provision "shell", inline: <<-SHELL
    apt update
    apt install -y apache2
    systemctl start apache2
    SHELL
  2. File Provision
    1
    config.vm.provision "file", source: "index.html", destination: "/tmp/index.html"
  3. Ansible Playbook (playbook.yml):
    1
    2
    3
    4
    5
    6
    7
    - hosts: all
    become: yes
    tasks:
    - name: Install Nginx
    apt:
    name: nginx
    state: present
  4. Puppet Manifest (default.pp):
    1
    2
    3
    package { 'nginx':
    ensure => installed,
    }
  5. Chef Recipe (default.rb):
    1
    2
    3
    package 'nginx' do
    action :install
    end
  6. Docker Provision
    1
    2
    3
    config.vm.provision "docker" do |d|
    d.run "nginx", image: "nginx:latest", args: "-p 80:80"
    end

11.错误处理

  1. Shell 脚本失败
    • 问题:语法错误或权限不足。
    • 解决
      • 检查脚本语法。
      • 确保外部脚本可执行(chmod +x setup.sh)。
      • 添加调试输出:set -xecho "Step X"
      • 查看详细日志:vagrant up --provision --debug.
  2. File Provision 失败
    • 问题:文件未找到或权限不足。
    • 解决
      • 确保源文件存在且路径正确。
      • 检查主机文件权限(chmod 644 index.html)。
  3. Ansible 失败
    • 问题:Ansible 未安装或 playbook 错误。
    • 解决
      • 确保主机已安装 Ansible
      • 检查 playbook 语法:ansible-playbook playbook.yml --syntax-check.
      • 确保虚拟机支持 SSH(默认即可)。
  4. Puppet 失败
    • 问题:Puppet Agent 安装失败或 manifest 语法错误。
    • 解决
      • 检查 Puppet 版本兼容性。
      • 使用 puppet parser validate default.pp 检查语法。
  5. Chef 失败
    • 问题:Chef DK 未安装或 recipe 错误。
    • 解决
      • 确保主机已安装 Chef DK。
      • 检查 recipe 语法:chef-client --local-mode -z -r myweb::default.
  6. Docker 失败
    • 问题:Docker 未安装或镜像拉取失败。
    • 解决
      • 确保虚拟机网络正常。
      • 检查 Docker 镜像是否存在:docker pull nginx:latest.

12.官方文档