If you have access to Docker for Windows then it would be easier to set up Docker compose on Ubuntu Bash as described in this article, but if you don't have access to Windows Premium (and thus no Hyper-V), this is a good alternative.
This example project is set up in such a way that the backend, devops and frontend folders all exist within the same project folder. Within the backend and frontend folders are contained the source code folders and the
node_modules folders (more on this later). The devops folder contains the
docker-compose.yaml file which is used by Docker compose to set up the project using the
docker-compose -f ./docker-compose.dev.yaml up --build command from within the devops directory. The project folder structure is illustrated below:
backend/ ├── node_modules ├── src └── etc... devops/ ├── docker-compose.yaml └── etc... frontend/ ├── node_modules ├── src └── etc... Vagrantfile
Simple in practice, but try running this from an Ubuntu Vagrant machine using VirtualBox as a provider on a Windows host and all hell breaks loose.
Node Modules and Shared Folder Issues
By default, the folder that contains the
Vagrantfile is mounted to
/vagrant in the VM, which means that all of the folders within that same folder get shared between the Host machine (running Windows 10 in this case) and the guest VM (running Ubuntu 16). The same directory structure from the VM's perspective can be seen below:
vagrant/ ├── backend/ │ ├── node_modules │ ├── src │ └── etc... ├── devops/ │ ├── docker-compose.yaml │ └── etc... └── frontend/ ├── node_modules ├── src └── etc...
As some of you know, the first step in setting up a node project is to install the project package dependencies using the
npm install command. This is where the first major issues occur as NPM packages generally use symlinks for binaries within the package. As previously stated, the
node_modules folders get shared between the host and guest machines meaning that those files must adhere to the constraints from both operating systems in some cases. In this particular case, Windows has terrible support for symlinks which results in multiple different errors for multiple different packages, and thus a failed installation. Additionally, Windows also has a maximum path size of 260 characters which adds further complications.
A simple fix is to tell NPM not to use symlinks during installation using the
npm install --no-bin-links command, but this generally does not work for more complex packages. A second fix, which sometimes works but is usually finicky, is to run Vagrant from a command prompt with administrator permissions after adding the following line to the Vagrant config file which allows for symlinks to be used on the VM:
Unfortunately this did not work for me, and this solution still doesn't help with the 260 character path limit imposed by Windows.
Generally, the content in the
node_modules folder is not actually needed on the host machine. A better solution is, thus, to store the content of the
node_modules folders within the VM and not have them synced across to the Windows host. This can be achieved by running the following commands from within the VM as shown here:
File Change Detection
File change detection is an important part of development and has many use cases such as allowing various components of the project to reload when the code has been altered. In our current example project, nodemon watches out for any changes in the backend code of our Node server, and the
ng serve command watches out for any changes in the frontent code.
Unfortunately for us, file change events do not automatically get propagated from our Windows host to our guest Ubuntu VM. This means that unless we come up with a solution, the whole development environment will have to be re-built using the
docker-compose command every single time we want our new code changes to reflect on the system, resulting in unnecessary delays.
Luckily though, a simple Vagrant plugin named fsnotify currently exists which solves this issue. It should be noted that a second Vagrant process needs to be running in parallel using the
vagrant fsnotify command, but a pull request exists on the fsnotify repository which can allow the plugin to run as a daemon during the
vagrant up command. To automatically download and use the plugin through the
Vagrantfile, simply add the following lines to your Vagrant configuration file:
A drawback is that from the technique being used in fsnotify (touching modified files), when multiple file changes occur within a window of 2 seconds only the first file change will be detected. This constraint should not cause any issues in the context of projects similar to ours as files typically do not change that quickly during development. Alternatively, if this causes issues, polling can be used but keep in mind that this can potentially slow down the application significantly.
Final Vagrantfile and Shell Scripts
Find below the
Vagrantfile and associated shell scripts which were used to set up this project environment.