We all work on different projects with different tools and different versions. And usually, chaos arises with all sorts of incompatibility.
Let's now think about this scenario: You are working with a customer using Kubernetes 1.20, managed via a Terraform 1.0.7 project. Then, a new customer arrives, and the status of their infrastructure is Kubernetes 1.13 and Terraform 0.14.11.
A way to manage multiple versions of CLI tools is mandatory. There are a lot of tools specialized in one single CLI, for example, terraenv, tfenv, kbenv, etc, but all of them use a different logic, each with a slightly different CLI interface. We need something centralized to manage everything.
Here comes the cavalry: asdf. asdf is a tool to manage other tool versions using a plugin architecture. We will also use direnv, an extension for the shell. It augments existing shells with a new feature that loads and unloads environment variables depending on the current directory.
This combo will automatically set environment variables and change tool versions when entering and exiting the project/directory that requires them!
Let's install everything
First of all, make sure to uninstall direnv and asdf via brew - we will install everything with the git process.
brew remove asdf brew remove direnv
We will follow the guide on this page to install asdf: http://asdf-vm.com/guide/getting-started.html#_2-download-asdf
At the time of writing, the last asdf version is v.0.8.1.
Let's clone the asdf source code:
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.8.1
This command will clone the project in our home directory under the
Now add the following in your
Reload your CLI and now you should have the asdf command available.
Let's proceed with the installation of direnv.
asdf plugin add direnv
Now that the plugin is available, we also need to use asdf to install direnv like this:
asdf install direnv 2.28.0 asdf global direnv 2.28.0
Let's go ahead and install some other plugins:
asdf plugin add terraform asdf plugin add kustomize asdf plugin add helmfile asdf plugin add kubectl asdf plugin add helm
Now edit your
.zshrc file and add the required hook:
eval "$(asdf exec direnv hook bash)"
Replace bash with zsh if needed.
The last thing to do is to run the following command:
asdf direnv setup --shell zsh --version 2.28.0
Reload your CLI, and now everything should be ready to be configured.
Create two files in your home root:
cat <<EOF> .envrc use asdf EOF
cat <<EOF> .tool-versions direnv 2.28.0 terraform 1.0.7 kustomize 3.5.3 kubectl 1.20.2 EOF
The first line with the direnv version is mandatory, otherwise the integration will not work.
asdf install asdf exec direnv allow
The first command
asdf install will read the
.tool-versions file and install all the versions of the programs defined, if the asdf plugin is available.
The second command
asdf exec direnv allow will execute direnv to allow the execution of what we have defined in the
.envrc to run.
That's it, you should be able to use all the tools defined in the .tool-versions file with the correct versions!
Setup a new project/folder
Now we have configured a global version of tools, in our shell. How do we configure on a per-project basis? In the same way we configured the home, for example if we have a project that needs terraform 0.14.11 and some environment variables exported , we can create the two files, .envrc and .tool-versions, with the following content:
cat <<EOF> .enrvc use asdf export AWS_REGION=eu-west-1 EOF
cat <<EOF> .tool-versions terraform 0.14.11 EOF
Activate the environment with:
asdf exec direnv allow and install missing tool versions with
I hope this article has been helpful, because we have been looking for a centralized way to manage different tool versions for a long time. Thanks to Luca Novara - he was the first to find this solution that the whole SIGHUP team now uses.