This framework lets you easily deploy logical units of infrastructure called "components".
To be successful using this framework, you will need to understand how to build infrastructure using the Terraform language. You will also need to know how to set variables using POSIX shell syntax. Here are some guides to get you started on these topics:
As you gain more confidence in using this framework, you can use advanced POSIX sh shell scripting to dynamically adjust values passed in to your Terraform, and you can deploy more advanced Terraform constructs like conditional resources.
A component is a logical unit of infrastructure. It does something. What it does is up to you. When creating a component, plan what its function is within the infrastructure, thoughtfully. Components should not try to do too much and, at the same time, not be so small as to offer no value on their own.
Here is what a component looks like, one generated by terraform-component create
:
$ tree components/terraform_state_backend_s3
components/terraform_state_backend_s3
├── LICENSE.md
├── README.md
├── build-env.sh
├── deploy-env.sh
├── deploy-hooks.sh
└── terraform
├── main.tf
├── outputs.tf
└── variables.tf
All components have this structure, which generally falls into three categories:
- Informational files that tell you what the component is and how it can be reused.
LICENSE.md
andREADME.md
- POSIX shell scripts that pass data from the command line invocation into the
Terraform HCL, at various points throughout the deployment life-cycle.
build-env.sh
,deploy-env.sh
, anddeploy-hooks.sh
. - The infrastructure implementation, in Terraform HCL within the
terraform/
sub-directory. You may have one or more files in here. By convention there are:main.tf
, which holds the implementation of your infrastructure componentoutputs.tf
, which documents the outputs this component makes available to other componentsvariables.tf
, which documents what inputs the component needs to implement the infrastructure.
Different versions of Terraform offer different features. Generally, the higher the version number, the more features. Usually you want to use the latest possible version, to take advantage of new features and bug and security fixes.
Each component, individually, declares what version of Terraform it wants to use. This allows you to develop components independently: older components can continue to use older versions of Terraform, while newer ones use newer versions.
Set the value of TERRAFORM_VERSION
in your build-env.sh
file to the version
of Terraform you want to use, or if you do not, your component inherits the
value from this framework.
Available versions are listed at Docker Hub.
Tip: always set the Terraform version in your components.
Variables specified in the terraform/variables.tf
file (or any other *.tf
file that holds a variable
terraform declaration) must be given before your
component will deploy. The values are specified in the deploy-env.sh
file.
Normally, the values are expressed using simple assignment, like:
TF_VAR_region=us-west-2
However, you can use shell scripting to calculate values dynamically, based on
other values in the environment. For example, to use the value of a variable
named AWS_REGION
if it exists, but otherwise default to us-west-2
, you could
use:
TF_VAR_region=${AWS_REGION:-us-west-2}
To experiment with the shell, you can run:
docker run -it --entrypoint /bin/sh hashicorp/terraform
Read more about Terraform variables.
Your component may output information that other components to depend upon. This often happens when a component creates a resource then needs to share that resource's identifier with dependent components.
Outputs specified in the terraform/outputs.tf
file (or any other *.tf
file that holds an output
terraform declaration) will be available for other
components to use. (See the next section on expression dependencies.)
Read more about Terraform outputs.
As much as possible, components should be independent and not depend upon other components, because it simplifies replicating environments and reduces the complexity of understanding relationships between components.
However, there are times when you want or need component dependencies, so this framework supports them. Refer to the Terraform documentation for more.
While this framework is licensed under the GNU General Public License, version 3,
components within this sub-directory may have a different license. Components
must specify their license in the form of a LICENSE.md
file, even if it's the
same as this framework.
Components without a LICENSE.md
inherit the license of this framework: GPLv3.
When you run terraform-component deploy
, the framework code runs through a
series of well-defined steps called "the deployment life-cycle" on the component
you've chosen to deploy.
The first step is to build a Docker image that houses the logical combination of
your component's code and the base files provided by the framework. This image
has everything needed to deploy the Terraform. So long as you make no changes
to your component's Terraform or shell configuration, this image will be used
every time you deploy. The configuration values in build-env.sh
drive various
features available in the built image, and that's the extent of configurability
you have on the build step.
The second step is to deploy the built Docker image. This step is far more
customizable. The deploy-env.sh
script runs, programatically setting values
for your Terraform to access. Since the terraform process is multi-staged (init,
plan, apply, etc), you can configure behavior before and after each of these
stages with the deploy-hooks.sh
file.
You can use this framework standalone via fork and clone, which is the easiest way to get started. It's meant to be easy, so that you can focus on getting infrastructure-as-code deployed.
You can also extend this framework with your own custom behavior or private components. A common way to do this is:
- At install time, download a copy of this framework (
npm install
,composer install
, etc.) using curl (or similar) and store in a directory nameddeployer
(or similar). - Write a script that wraps this framework's
terraform-component
. For example, that script might authenticate the user with the cloud provider. - Arrange for your wrapper script to point to your components and use your environment setup.
Here's a rough outline of these steps:
# download the latest release of this framework and put into a directory named `deployer`
curl https://api.github.com/repos/bishopb/terraform-component/tarball \
| tar xzC deployer --strip 1
# invoke the framework deployer, after setting up the environment and pointing it
# to our custom components
env \
default_TF_VAR_providers=aws \
default_TF_VAR_credentials=aws \
default_TF_VAR_backend=s3 \
COMPONENT_PATH=./components:./deployer/components \
./deployer/bin/terraform-component deploy "component-name" "apply"
There is no limit to how you can compose this framework into your environment.
- To learn how to create components, run
terraform-component create
and read the help documentation. - To better understand the organization of a component, refer to the
lib/component_skeleton
directory.