Expert Python Programming(Third Edition)
上QQ阅读APP看书,第一时间看更新

Virtual development environments using Vagrant

Vagrant currently seems to be one of the most popular tools for developers to manage virtual machines for the purpose of local development. It provides a simple and convenient way to describe development environments with all system dependencies in a way that is directly tied to the source code of your project. It is available for Windows, Mac OS, and a few popular Linux distributions (refer to https://www.vagrantup.com). It does not have any additional dependencies. Vagrant creates new development environments in the form of virtual machines or containers. The exact implementation depends on a choice of virtualization providers. VirtualBox is the default provider, and it is bundled with the Vagrant installer, but additional providers are available as well. The most notable choices are VMware, Docker, Linux Containers (LXC), and Hyper-V.

The most important configuration is provided to Vagrant in a single file named Vagrantfile. It should be independent for every project. The following are the most important things it provides:

  • Choice of virtualization provider
  • A box, which is used as a virtual machine image
  • Choice of provisioning method
  • Shared storage between the VM and VM's host
  • Ports that need to be forwarded between VM and its host

The syntax language for Vagrantfile is Ruby. The example configuration file provides a good template to start the project and has an excellent documentation, so the knowledge of this language is not required. Template configuration can be created using a single command:

vagrant init

This will create a new file named Vagrantfile in the current working directory. The best place to store this file is usually the root of the related project sources. This file is already a valid configuration that will create a new VM using the default provider and base box image. The default Vagrantfile content that's created with the vagrant init command contains a lot of comments that will guide you through the complete configuration process.

The following is a minimal example of Vagrantfile for the Python 3.7 development environment based on the Ubuntu operating system, with some sensible defaults that, among others, enable port 80 forwarding in case you want to do some web development with Python:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
# Every Vagrant development environment requires a box.
# You can search for
boxes at https://vagrantcloud.com/search.
# Here we use Bionic version Ubuntu system for x64 architecture.
config.vm.box = "ubuntu/bionic64"

# Create a forwarded port mapping which allows access to a specific
# port within the machine from a port on the host machine and only
# allow access via 127.0.0.1 to disable public access

config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

config.vm.provider "virtualbox" do |vb|
# Display the VirtualBox GUI when booting the machine
vb.gui = false

# Customize the amount of memory on the VM:
vb.memory = "1024"
end

# Enable provisioning with a shell script.

config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install python3.7 -y
SHELL
end

In the preceding example, we have set an additional provision of system packages with simple shell script. When you feel that Vagrantfile is ready, you can run your virtual machine using the following command:

vagrant up

The initial start can take a few minutes, because the actual box image must be downloaded from the web. There are also some initialization processes that may take a while every time the existing VM is brought up, and the amount of time depends on the choice of provider, image, and your system's performance. Usually, this takes only a couple of seconds. Once the new Vagrant environment is up and running, developers can connect to it through SSH using the following shorthand:

vagrant ssh

This can be done anywhere in the project source tree below the location of Vagrantfile. For the developers' convenience, Vagrant will traverse all directories above the user's current working directory in the filesystem tree, looking for the configuration file and matching it with the related VM instance. Then, it establishes the secure shell connection, so the development environment can be interacted with just like an ordinary remote machine. The only difference is that the whole project source tree (root defined as the location of Vagrantfile) is available on the VM's filesystem under /vagrant/. This directory is automatically synchronized with your host filesystem, so you can normally work in the IDE or editor of your choice run on the host, and can treat the SSH session to your Vagrant VM just like a normal local Terminal session.

Let's take a look at virtual environments using Docker in the next section.