Install Terraform with tfenv
Joaquin Menchaca
Posted on January 15, 2023
There will come a time when you will need to change to different versions of Terraform. Similar to tools like rbenv
for Ruby or pyenv
for Python, there's a popular tool used to install different versions of Terraform called tfenv
.
Most tooling for infrastructure operations runs on Intel processors, called the amd64
architecture with in Terraform, but given the recent addition of Macbook M1 laptops, the architecture is arm64
. Older versions of Terraform that may be needed will require installing Terraform that is only available on Intel processors (amd64
binaries). This can be installed using tfenv
as well.
This article will have cover the following sections:
- Installing
tfenv
on Ubuntu (linux
) and mac OS (darwin
) - Installing a latest or recent version of Terraform
- Installing legacy versions of Terraform on macOS with Arm processor (Macbook M1/M2)
- Installing Legacy providers plugins (Ubuntu and Macbook M1/M2)
Installing tfenv
Here's how you can install tfenv
on Ubuntu (linux
) or mac OS (darwin
).
Installing tfenv on Ubuntu
git clone https://github.com/tfutils/tfenv.git ${HOME}/.tfenv
export PATH="${HOME}/.tfenv/bin:${PATH}"
# install to appropriate shell startup file, e.g. $HOME/.bashrc
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ${HOME}/.profile
Installing tfenv on mac OS
brew install tfenv
Installing Terraform
Once tfenv
is installed and available in the path, you can simply run something like this:
tfenv install 1.3.7
Using tfenv list-remote
you can fetch different versions of Terraform that are available for installation. From there, you can use GNU grep to select the desired version. For example, here's how to install the latest version:
LATEST_VERSION=$(tfenv list-remote \
| grep -vP '\d.\d{0,2}.\d{0,2}-.*' \
| head -1
)
tfenv install ${LATEST_VERSION}
NOTE: On macOS, which has BSD flavor grep
, it doesn't support PCRE. To get GNU Grep with support for PCRE, use brew install grep
.
You can extract the last minor version by passing in an explicit major version to GNU Grep:
# find latest 0.12
LATEST_0_12=$(tfenv list-remote \
| grep -oP '^0.12.\d{1,2}' \
| sort --version-sort \
| tail -1
)
tfenv install ${LATEST_0_12}
For the latest version, whatever that is, you can also just run the following:
tfenv install latest
Using the desired Terraform version
When you want to use the a particular version of an installed version terraform
, you can select it with the following:
tfenv use 1.3.7
Also, to have the Terraform switch automatically when navigating to the project directory, you can place a .terraform-version
to auto-select the version:
mkdir -p ${HOME}/my_project/.terraform-version
echo '1.3.7' > ${HOME}/my_project/.terraform-version
# change version of Terraform automatically
cd ${HOME}/my_project/.terraform-version
Installing Legacy x64 versions on Mac
If you Macbook sports a arm64 processor, you need to get Rosetta to run amd64
binaries on macOS. Afterward, you can follow these steps below to install legacy versions of terraform
.
export TFENV_ARCH="amd64"
# install amd64 terrafrom version since there are no arm64 binaries
tfenv install 0.12.31
tfenv use 0.12.31
Installing Legacy providers
In recent versions of Terraform, this installation will happen automatically when you run terraform init
First, you need to find the appropriate plugin version that matches the supported version of Terraform. In the case of terraform-provider-kubectl
, you need to install 1.11.2
of that version of that plugin.
Installing legacy provider on Ubuntu Linux
ARCH="linux_amd64"
VERS="1.11.2"
PKG="terraform-provider-kubectl_${VERS}_${ARCH}.zip"
REPO="gavinbunney/terraform-provider-kubectl"
URL="https://github.com/${REPO}/releases/download/v${VERS}/${PKG}"
# setup plugins directory if this does not exist already
mkdir -p ${HOME}/.terraform.d/plugins/${ARCH}/
# download archive and install plugin
pushd ${HOME}/Downloads
curl -sOL ${URL}
unzip ${PKG} && rm README.md LICENSE
mv terraform-provider-kubectl_v${VERS} </span>
${HOME}/.terraform.d/plugins/${ARCH}/
popd
Installing legacy provider on Macbook M1
For current Macbooks running the arm64 processor, you will need to install the legacy provider for amd64 (not arm64). This is how you can do that.
ARCH="darwin_amd64" # install amd64 plugin for legacy terraform
VERS="1.11.2"
PKG="terraform-provider-kubectl_${VERS}_${ARCH}.zip"
REPO="gavinbunney/terraform-provider-kubectl"
URL="https://github.com/${REPO}/releases/download/v${VERS}/${PKG}"
# setup plugins directory if this does not exist already
mkdir -p $HOME/.terraform.d/plugins/${ARCH}/
# download archive
pushd ${HOME}/Downloads
curl -sOL ${URL}
unzip ${PKG} && rm README.md LICENSE
mv terraform-provider-kubectl_v${VERS} </span>
${HOME}/.terraform.d/plugins/${ARCH}/
popd
Conclusion
I hope this is useful to your Terraform adventures. The reason why locking down versions of Terraform is important, is that there are significant language changes that make the code incompatible. The installer dependency chain with Terraform modules and providers will need to match the target version of the terraform
command.
In addition to this, the state that is generated from interacting with the provider will likely need to match, so it is important that the infrastructure that created with a particular version of Terraform, also be removed when ultimately terraform destroy
is used.
As the infrastructure progresses forward, there are techniques you can use to smoothly transition. One method it to have modular modules that depend on looking up the state in the cloud through data sources, and important existing infrastructure into the state using terraform import
. This is definitely material for a future article.
In the meantime, you can use the supported version with tools like tfenv
. Another tool, as an alternative to tfenv
is asdf. I have not explored supported legacy amd64 legacy binaries on Macbook M1 yet, but assume this can work. The asdf is nice in that it has a plugin architecture to support a variety of languages.
Lastly, about this article, which I am sure might unnerve shell purists, where I use $HOME
instead of ~
and I use of curly braces for ${VARIABLES}
, when they are not needed, when simply $VARIABLE
is preferred: this was done intentionally to make the variables light up in color syntax highlighters on different platforms, and $HOME
was used for novice uses that may not be familiar with ~
notation.
Posted on January 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.