Search code examples
mysqldockerphpmyadminvagrant

How to migrate from docker-compose to vagrant?


Here is my docker-compose file that works fine and I want to reproduce the same results using Vagrant:

version: '3.7'
services:
  db:
    image: mysql:5.7.36
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test_db
    ports:
      - "3308:3306"
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    restart: always
    environment:
      PMA_HOST: db
      PMA_USER: root
      PMA_PASSWORD: root
    ports:
      - "8080:80"

Execute docker-compose up and visit localhost:8080 phpmyadmin works fine. When I try to the same with vagrant containers are built and they are running, but phpmyadmin is unable to communicate with mysql container. Here is my Vagrantfile:

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

Vagrant.configure("2") do |config|
    config.vm.define "mysql" do |db|
        db.vm.network "forwarded_port", guest: 3306, host: 3308
        db.vm.hostname = "mysqldb"
        db.vm.provider "docker" do |d|
          d.image = "mysql:5.7.36"
          d.env = {
            :MYSQL_ROOT_PASSWORD  => "root",
            :MYSQL_DATBASE        => "test_db"
          }
          d.remains_running = "true"
        end
      end
    config.vm.define "phpmyadmin" do |pa|
        pa.vm.network "forwarded_port", guest: 80, host: 8080
        pa.vm.hostname = "phpmyadmin"
        pa.vm.provider "docker" do |d|
            d.image = "phpmyadmin/phpmyadmin:latest"
            d.env = {
                :PMA_HOST       => "mysqldb",
                :PMA_USER       => "root",
                :PMA_PASSWORD   => "root"
            }
            d.remains_running = "true"
        end
    end
end

How can I get the phpmyadmin and MySQL working together with vagrant?


Solution

  • I got the solution. I need to define the network at the top level.

    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    
    # This file works exactly like the docker-compose.yml file.
    Vagrant.configure("2") do |config|
        # Define the network, using which the containers can communicate
        config.vm.network :private_network, type: "dhcp"
        config.vm.define "mysql" do |db|
            # Without prot forwardign vagrant entwork doesnt work
            db.vm.network "forwarded_port", guest: 3306, host: 3306
            db.vm.hostname = "mysqldb"
            db.vm.provider "docker" do |d|
              d.image = "mysql:5.7.36"
              d.env = {
                :MYSQL_ROOT_PASSWORD  => "root",
                :MYSQL_DATBASE        => "test_db"
              }
              d.remains_running = "true"
            end
          end
        config.vm.define "phpmyadmin" do |pa|
            pa.vm.network "forwarded_port", guest: 80, host: 8080
            pa.vm.hostname = "phpmyadmin"
            pa.vm.provider "docker" do |d|
                d.image = "phpmyadmin/phpmyadmin:latest"
                d.env = {
                    :PMA_HOST       => "mysqldb",
                    :PMA_USER       => "root",
                    :PMA_PASSWORD   => "root",
                    # Without specifying the specific port phpadmin container doesn't work
                    :PMA_PORT       => "3306", 
                }
                d.remains_running = "true"
            end
        end
    end
    

    I still need to solve one more problem - how to define a dependency between vms. Build the VM phpmyadmin only after mysql is up and running.

    Unlike docker-compose it is not possible to set a direct dependency in vagrant. But it is possible to do a sequential build by setting the option --no-parallel eg:- vagrant up --no-parallel.

    Even though docker-compose has the dependency set, the dependency is only to the extent of waiting for the dependent container to be built but not waiting for the services in the container to be up and running.

    Hence even after building sequentially in vagrant, the dependent services failed to connect. It did not matter vagrant or docker-compose. Services with in the containers need to wait for their dependent services to be up.

    So I added a delay in the dependent containers in a timed loop, the dependent service will attempt to connect and upon failure will wait for 30 seconds to connect again, after 10 attempts it gives up.