-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: improve docs on authoring components
- Loading branch information
Showing
2 changed files
with
205 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,208 @@ | ||
Components are units of infrastructure, configured in bash and expressed in | ||
Terraform HCL. | ||
This framework lets you easily deploy logical units of infrastructure called | ||
"components". | ||
|
||
* 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. | ||
# What you need to know before you can use this framework | ||
|
||
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: | ||
|
||
* [Terraform tutorials][terra-tut] | ||
* [POSIX shell scripting][posix-sh] | ||
|
||
[posix-sh]:https://www.grymoire.com/Unix/Sh.html | ||
[terra-tut]:https://learn.hashicorp.com/terraform | ||
|
||
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. | ||
|
||
# What is a component? | ||
|
||
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. | ||
|
||
## Anatomy of a component | ||
|
||
Here is what a component looks like, one generated by `terraform-component create`: | ||
|
||
```sh | ||
$ 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: | ||
|
||
1. Informational files that tell you what the component is and how it can be reused. | ||
`LICENSE.md` and `README.md` | ||
2. 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`, and `deploy-hooks.sh`. | ||
3. 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 component | ||
* `outputs.tf`, which documents the outputs this component makes available to | ||
other components | ||
* `variables.tf`, which documents what inputs the component needs to implement | ||
the infrastructure. | ||
|
||
### Terraform versions | ||
|
||
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.][terra-vers] | ||
|
||
Tip: always set the Terraform version in your components. | ||
|
||
[terra-vers]:https://hub.docker.com/r/hashicorp/terraform/tags | ||
|
||
### Variables | ||
|
||
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: | ||
|
||
```sh | ||
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: | ||
|
||
```sh | ||
TF_VAR_region=${AWS_REGION:-us-west-2} | ||
``` | ||
|
||
To experiment with the shell, you can run: | ||
|
||
```sh | ||
docker run -it --entrypoint /bin/sh hashicorp/terraform | ||
``` | ||
|
||
# Licensing of components | ||
[Read more about Terraform variables.][terra-vars] | ||
|
||
[terra-vars]:https://www.terraform.io/language/values/variables | ||
|
||
### Outputs | ||
|
||
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.][terra-outs] | ||
|
||
[terra-outs]:https://www.terraform.io/language/values/outputs | ||
|
||
#### Expressing dependencies | ||
|
||
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.][terra-rs] | ||
|
||
[terra-rs]:https://www.terraform.io/language/state/remote-state-data | ||
|
||
### Licensing | ||
|
||
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. | ||
|
||
# Component deployment life-cycle | ||
|
||
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. | ||
|
||
# Extending terraform-component | ||
|
||
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: | ||
|
||
1. At install time, download a copy of this framework (`npm install`, `composer install`, | ||
etc.) using curl (or similar) and store in a directory named `deployer` (or | ||
similar). | ||
1. Write a script that wraps this framework's `terraform-component`. For example, | ||
that script might authenticate the user with the cloud provider. | ||
1. 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. | ||
|
||
# Additional resources | ||
|
||
* 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. |