My custom vagrant development environment, allowing quick dev boxes to be created, based on folder(s) of code.
After a couple of months running ProxiBlue, I realised that I need to adapt my dev environment, and virtualize.
I often get codebase zips and db dumps from clients, to debug a specifc issue on their site, specific to their setup.
My want was simple:
- Create a folder, and place given site code therein.
- Bring that up as a virtual machine.
- Try and make it generic enough to easily prototype test boxes or debug on client code base/database given.
- allow quick testing of code in various PHP versions / environments
- I did not need anything fancy like REDIS boxes etc, but they can easily be used in the setup.
So I looked at Vagrant, and since the Vagrant commands file is simply just a ruby script, I adjusted to my needs.
Initially the environment included code to also automatically install new magento installs, but I slimmed that down. I use this also for work that is not magento related (example wordpress) so made it more generic.
- Vagrant, latest is best. I use 1.8.1. Not tested on any others, but should work.
- Docker. I use Linux (Manjaro), so installed via its package manager. I am on version 1.10.3, build 20f81dd
- https://github.com/tonistiigi/dnsdock (more later in setup)
This is as per docker usage. If you use anything other than docker, you are on your own ;)
One main issue with using docker to bring up client machines is ip address allocation. Docker dynamically assigns ip's to the machines. Since it was not ideal to use ip's in browser, I found a solution to overcome this issue:
https://github.com/tonistiigi/dnsdock
So basically, we will configure docker to use this dnsdock service as its main DNS server. Dnsdock will be setup to use your normal DNS server as its fallback Your machine will be set to use DNSdock as its first dns server.
So, every time docker starts a new box, it will report that box to DNSDock, and viola - you can use named addresses for your boxes.
Start dnsdock like this:
docker run -d -v /var/run/docker.sock:/var/run/docker.sock --restart always --name dnsdockmain -p 172.17.42.1:53:53/udp tonistiigi/dnsdock -domain=".local.com" -nameserver="8.8.8.8:53"
The IP 172.17.42.1 is my local host machine docker bridge interface. Usually called docker0
09:26 $ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.42.1 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:f2ff:fe5a:f88b prefixlen 64 scopeid 0x20<link>
ether 02:42:f2:5a:f8:8b txqueuelen 0 (Ethernet)
RX packets 443825 bytes 263992938 (251.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 463292 bytes 185656093 (177.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
-domain=".local.com" = your local domain used. The folder will become the hostname. so you end up with FOLDER.local.com
as the url to use.
-nameserver="8.8.8.8:53" = the fallback DNS to use. Without this you will not be able to get any other DNS lookups working. Change to your corporate internal DNS server if exist.
Next, setup your local machine to use the docker0 interface as its DNS server. You need to adjust how depending on what OS your host is.
09:28 $ cat /etc/resolv.conf
# Generated by resolvconf
nameserver 172.17.42.1
and finally, you need to tell docker to use DNSdock Again, you need to adjust per your host OS:
09:31 $ cat /etc/systemd/system/docker.service.d/docker.conf
[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon --bip=172.17.42.1/16 --dns=172.17.42.1 -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock
In Debian that will be located under /etc/defaults
The important bits are: --bip=172.17.42.1/16 --dns=172.17.42.1
Once done, you should be able to query DNSDock for any set entries: In your browser :
http://dnsdock.local.com/services
at this point you'd see one entry for dnsdock itself:
"f5cbde595e53187bd1ad65e01a62046035c769fbfcee2815008d7a1be47e366e":{"Name":"dnsdock","Image":"dnsdock","Ip":"172.17.0.1","Ttl":-1,"Aliases"
- Clone this repo
- cd into the cloned folder:
cd vagrant-docker
- cd into the
machines
folder:cd machines
- create a new folder. This will be the web root folder with your site code.
- cd back to the base folder 'vagrant-docker'. NOTE: for all vagrant commands, you need to be at this folder level.
- bring up the virtual box :
vagrant --name=<FOLDER NAME> up
You will now see the guest booting up. The initial boot may be the slowest as the docker host needs to be built. subsequent up's thereafter will be a matter of seconds, as the guest is already build. If you destroy the guest, it will restart from the initial pull/build.
- once built, you can ssh to the box with :
vagrant --name=<FOLDER NAME> ssh
- You will find mysql running using username root, password root
- You will find a fresh (blank) db called 'database'
- you can now import whatever db you need into the base database, and configure the source to use the db.
You can easily test the same codebase in different versions of PHP/MYSQL/APACHE etc by creating a symlink in the machines folder
example:
ln -s ./<FOLDER> ./<NEW_NAME>
you can then bring up a second box, using the linked source folder, but designate a different basebox (default is DEBAIN_8)
vagrant --name=<NEW_NAME> --basebox=DEBAIN_7 up
you will end with a box on the original folder (debain 8) and one on the linked folder (debain 7) allowing you to quickly test code in multiple PHP versions and environments.
Other custom switches:
- '--bindports' usage : --bindports=1 : this will bind the box to your lcoal host port 80/443 - allowing external access to the box. Only one box can bind this at any time.
- '--webserver' usage : --webserver=apache|php : this will invoke the noted webserver, default is apache, use PHP for php's internal webserver (not used the internal php server in a long while, so may be broken)
The docker guests expose mysql port, so you can easily use a mysql client from your host to connect to each mysql instance. Just use the noted DNS name of guest as the mysql host.
Since the site code is located on the host, in a local folder, PHPStorm does not have issues.
After a guest db was imported, I generally run the command : /vagrant/scripts/magento_make_db_local.sh
for any magento guests.
This script uses n98-magerun to reconfigure the site urls to {{base_url}}
allowing for the dynamic urls to be used.
You can easily add to this script any other configuration changes you want into imported db's
https://gist.github.com/ProxiBlue/dfc74f35721b57e96b560d898cb6bfeb
If a box (folder) requires some specific setup to run when they get provisioned, you can create a file called <FOLDER>.sh
within the /provision folder.
When a box with that folder name is provisioned (either by an initial startup, or by invoking --provision on a stopped box), the given shell script will be invoked as a final step.
If no such file exists, generic.sh will run.
You can add a custom webserver instance. Simply create the file named: start-#{webserver}#-web.sh
where #{webserver}# is the name.
Place this file in the /provision folder.
Look at the two existing files for examples on usage.
The default is : start-apache-web.sh
Composer, n98-magerun and phpunit is installed into all boxes. If you want to add stuff to install when provisioned, add them to generic.sh
Virtualbox and vmware-workstation instances invokes install_packages.sh
during provisioning. (these are done inside the Docker file for docker instances)
This can make it quite slow to issue a --provision on boxes running in virtualbox
You can force the provider, as normal with Vagrant, by using --provider=docker|virtualbox|vmware-workstation
The default xdebug.ini setup will have the profiler setup to output to the folder /var/www/html/var/profiler
In Magento land that will place profiling traces in the Magento var
folder. Please ensure this is excluded in your .gitignore!
The folder /var/www/html
is a symlink to the sources of the folder you have initialised as the virtual machine: html -> /vagrant/machines/jackt/www//docroot
If you use this setup for other work (excample WordPress) you may have to create the var
folder in the root of your site code.
xdebug.profiler_enable_trigger=On
xdebug.profiler_enable=0
xdebug.profiler_output_dir=/var/www/html/var/profiler
xdebug.max_nesting_level=200
xdebug.profiler_output_name="%R-%u.trace"
xdebug.profiler_append=On
Traces will have the name of the action controller in magento
example: _checkout_cart_-1479617767_818847.trace
is a trace of the cart page loading.
You can trigger profiling using any Xdebug helper I use this one: https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc?hl=en
Once enabled, you will have traces placed in the folder, which is conveniently placed to load up with PHPStorm profiler :) WINNING!
00:15 $ vagrant --name=dyncatprod up
using docker as provider and 4168 for ssh
Bringing machine 'dyncatprod' up with 'docker' provider...
==> dyncatprod: Image is already built from the Dockerfile. `vagrant reload` to rebuild.
==> dyncatprod: Starting container...
==> dyncatprod: Waiting for machine to boot. This may take a few minutes...
dyncatprod: SSH address: 172.17.0.4:22
dyncatprod: SSH username: vagrant
dyncatprod: SSH auth method: private key
dyncatprod: Warning: Connection refused. Retrying...
==> dyncatprod: Machine booted and ready!
==> dyncatprod: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> dyncatprod: flag to force provisioning. Provisioners marked to run always will still run.
==> dyncatprod: Running provisioner: shell...
dyncatprod: Running: /tmp/vagrant-shell20161115-27495-kddkjx.sh
==> dyncatprod: stdin: is not a tty
==> dyncatprod: STARTING APACHE WEBSERVER
==> dyncatprod: Site default-ssl already enabled
==> dyncatprod: Module rewrite already enabled
==> dyncatprod: Module headers already enabled
==> dyncatprod: Considering dependency setenvif for ssl:
==> dyncatprod: Module setenvif already enabled
==> dyncatprod: Considering dependency mime for ssl:
==> dyncatprod: Module mime already enabled
==> dyncatprod: Considering dependency socache_shmcb for ssl:
==> dyncatprod: Module socache_shmcb already enabled
==> dyncatprod: Module ssl already enabled
==> dyncatprod: Restarting web server: apache2
==> dyncatprod: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. Set the 'ServerName' directive globally to suppress this message
==> dyncatprod: .
[Tue Nov 15 00:16:06] [lucas@DeepThought vagrant-docker]$ [master L|⚑ 3]
00:16 $