Sep 2, 2017

How to enable Vagrant SSH access into a Docker container

Vagrant seems to work really well with VirtualBox and some other virtualization providers, but I had a situation where I wanted to get it to run with Docker instead (on my local Linux Mint system) and to enable Vagrant to have ssh access into the Docker container.

I started with the Docker image wadmiraal/drupal:7.54 which I had been using for doing Drupal development via Docker alone. There are several changes that had to be made, some in the Docker image, some in the Vagrantfile, in order to satisfy Vagrant expectations.

(1)  Create a user named vagrant in the guest system.

Running the image in a Docker container, I ssh'ed into it using its existing root user, then created a new user "vagrant". Set the password to "vagrant", which is a convention but it could be a different password.

I tested this new user by logging in manually.

# ssh -p 2222 vagrant@127.0.0.1

where 2222 is the local host port that is forwarded to the ssh port on the guest.

(2)  Provide ssh key authentication in the guest system.

On the host / local system, I already had ssh keys. I used the following command to set up the key in the guest system.

# ssh-copy-id -p 2222 vagrant@127.0.0.1

Again, I tested this by logging in manually.

(3)  Enable sudo for the vagrant user in the guest system.

The Vagrant docs say, "Many aspects of Vagrant expect the default SSH user to have passwordless sudo configured. This lets Vagrant configure networks, mount synced folders, install software, and more."

The Docker image I started with did not even have sudo available, so I logged into the guest as root and installed it.

# apt-get update
# apt-get install sudo

Then used visudo to edit /etc/sudoers to insert two lines.

# visudo

vagrant ALL=(ALL) NOPASSWD:ALL
Defaults:vagrant !requiretty


After making these changes to the guest, I used Docker to commit a new image. Let's call it earl/drupal:7.54

(4)  Add Docker settings in the Vagrantfile.

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'

Vagrant.configure("2") do |config|

  config.vm.network "forwarded_port", guest: 22, host: 2222

  config.vm.provider "docker" do |dock|
    dock.image = "earl/drupal:7.54"
    dock.name = "drupal-7.54"
    dock.has_ssh = true
  end

end

Specifying the default provider in the Vagrantfile is just a convenience so that you don't have to use the --provider option for the vagrant up command.

(5)  Set up password authentication for ssh in the Vagrantfile.

Vagrant.configure("2") do |config|

  config.ssh.username = "vagrant"
  config.ssh.password = "vagrant"

end

This is optional. If you provide config.ssh.password as above, Vagrant will use password authentication. Otherwise, Vagrant will default to key authentication, as in the following step. 

(6)  Set up key authentication for ssh in the Vagrantfile.

Vagrant.configure("2") do |config|

  config.ssh.keys_only = false
  config.ssh.private_key_path = "/home/earl/.ssh/id_rsa"

end

This is also optional. Do either step (5) or step (6). If you do both, Vagrant will use password authentication. 

ssh.keys_only must be set to false in order to use your own ssh keys, and you must also provide the path to those keys.

(7) Test that Vagrant is able to make a change in the guest.

For example, I added the following two lines to the Vagrantfile to execute a shell command.

Vagrant.configure("2") do |config|

  config.vm.provision "shell",
    inline: "touch /vagrant/hello-world" 
end

Doing vagrant up should boot up without errors and execute the shell command successfully. In the above snippet, because Vagrant automatically synchronizes the /vagrant directory on the guest with the host directory where the Vagrantfile is located, you can check for the hello-world file on the host.

Sources:

Creating a Base Box
https://www.vagrantup.com/docs/boxes/base.html

SSH Settings
https://www.vagrantup.com/docs/vagrantfile/ssh_settings.html

Docker Configuration
https://www.vagrantup.com/docs/docker/configuration.html