Deploying Modules
Prerequisites
This guide assumes:
-
You have prior experience working with infrastructure tools such as OpenTofu (Terraform) and Terragrunt. If you are not, please review the concept docs before proceeding.
-
You have completed the necessary repository setup guide.
Using Terragrunt to Deploy Modules
In the Panfactum stack, we use Terragrunt to configure and deploy OpenTofu / Terraform modules.
The configuration-as-code for each deployed module is stored in your repository's environments folder. 1 Terragrunt uses an extended version of the Hashicorp Configuration Language (HCL) to define each module's deployment configuration. If you are new to terragrunt, you should review the basics of the syntax here.
Terragrunt wraps tofu
/ terraform
CLI and contains the same subcommands (e.g., apply
, plan
, etc.). Simply
navigate to the module subdirectory in your environments folder and run the desired command (e.g., terragrunt apply
).
Terragrunt also provides a run-all
subcommand that allows you to deploy every module inside a directory
which can be very helpful for updating all the modules in a particular environment (e.g., terragrunt run-all apply
).
Local Deployments
When working with modules locally, it can be helpful to override your organization's values in the standard terragrunt configuration files. For example, you may want to use a different provider configuration to pull in your specific AWS profile, or you may want to test a specific module version.
Each of the standard files has .user.yaml
counterparts that will override the normal file values:
global.yaml
:global.user.yaml
environment.yaml
:environment.user.yaml
region.yaml
:region.user.yaml
module.yaml
:module.user.yaml
These files are automatically ignored by version control.
CI Systems
We are actively working on providing CI templates to automate the deployment process of the infrastructure. This should be available in the next release.
Defining a Module for Deployment
When defining infrastructure modules for deployment, each module will receive its own folder. You will add
a terragrunt.hcl
file to each folder which will contain your deployment configuration.
To take advantage of the Panfactum stack, your terragrunt.hcl
must at minimum have the following include
block:
include "panfactum" {
path = find_in_parent_folders("panfactum.hcl")
expose = true
}
You will also likely want to include a terraform
source such as the following:
terraform {
source = "github.com/Panfactum/stack.git//packages/infrastructure/aws_eks"
}
The source syntax follows these rules..
We do provide some convenience utilities for setting easily setting the source if you are:
-
using a Panfacutm module
-
using a first-party module (defined in your infrastructure repo)
Finally, you will likely want an inputs
field to define the provided inputs to the sourced infrastructure module:
inputs = {
foo = "bar"
}
A full file example might look something like this:
include "panfactum" {
path = find_in_parent_folders("panfactum.hcl")
expose = true
}
terraform {
source = "github.com/Panfactum/stack.git//packages/terraform/aws_eks"
}
inputs = {
foo = "bar"
}
Setting up Providers
Before you deploy a module, you must setup your OpenTofu (Terraform) providers.
We provide ready-made configuration for many providers (see the full list here).
To enable a provider, add the provider under providers
key of the module's module.yaml
.
For example, this module.yaml
would enable the aws
and kubernetes
provider for a module:
providers:
- aws
- kubernetes
Some providers require extra configuration variables. To view each provider's required configuration variables, see the reference docs.
Generally, you will want to configure a provider on an environment-wide or region-wide basis (i.e.,
in the environment.yaml
or region.yaml
files).
Determining Which Providers to Enable
There are two different methods to determine which providers to enable.
Direct Method
Every OpenTofu module will have a required_providers block that looks like this:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.10"
}
tls = {
source = "hashicorp/tls"
version = "4.0.4"
}
}
}
You can use this information to determine which providers to enable. In the above case, it would be the aws
and tls
providers.
Indirect Method
As modules can import other modules (which may have their own discrete required providers), the direct method may be tedious depending on the depth of the module tree.
You can instead rely on the .terraform.lock.hcl
file that gets generated after running terragrunt init
in the module directory.
You can run terragrunt init
without first configuring modules.
The .terraform.lock.hcl
file may look as follows:
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "5.10.0"
constraints = "5.10.0"
hashes = [
"h1:AgF54/79Nb/oQjbAMMewENSIa1PEScMn20Xa91hZR2g=",
"h1:csg7yqBE71epsXpVFPn4p8sCKoBNCFLfJq3Qa61XNQ4=",
"zh:24f8b40ba25521ec809906623ce1387542f3da848952167bc960663583a7b2c7",
"zh:3c12afbda4e8ed44ab8315d16bbba4329ef3f18ffe3c0d5ea456dd05472fa610",
"zh:4da2de97535c7fb51ede8ef9b6bd45c790005aec36daac4317a6175d2ff632fd",
"zh:5631fd3c02c5abe5e51a73bd77ddeaaf97b2d508845ea03bc1e5955b52d94706",
"zh:5bdef27b4e5b2dcd0661125fcc1e70826d545903b1e19bb8d28d2a0c812468d5",
"zh:7b7f6b3e00ad4b7bfaa9872388f7b8014d8c9a1fe5c3f9f57865535865727633",
"zh:935f7a599a3f55f69052b096491262d59787625ce5d52f729080328e5088e823",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:a451a24f6675f8ad643a9b218cdb54c2af75a53d6a712daff46f64b81ec61032",
"zh:a5bcf820baefdc9f455222878f276a7f406a1092ac7b4c0cdbd6e588bff84847",
"zh:c9ab7b838a75bbcacc298658c1a04d1f0ee5935a928d821afcbe08c98cca7c5f",
"zh:d83855b6d66aaa03b1e66e03b7d0a4d1c9f992fce06f00011edde2a6ad6d91d6",
"zh:f1793e9a1e3ced98ca301ef1a294f46c06f77f6eb10f4d67ffef87ea60835421",
"zh:f366c99ddb16d75e07a687a60c015e8e2e0cdb593dea902385629571bd604859",
"zh:fb3ec60ea72144f480f495634c6d3e7a7638d7061a77c228a30768c1ae0b91f6",
]
}
Using Secrets
Secrets are encrypted and stored directly inside the repository just like any other configuration setting. The Panfactum stack uses sops for ensuring this is done securely and in a manner that integrates with terragrunt. See our guide for setting up sops.
Assuming you have an encrypted file called secrets.yaml
adjacent to your terragrunt.hcl
, you
can access its values using the following syntax: 2
locals {
secrets = yamldecode(sops_decrypt_file("${get_terragrunt_dir()}/secrets.yaml"))
}
inputs = {
secret_input = local.secrets.my_secret
}
Defining the Dependency Graph
Typically, there will be an order in which your infrastructure modules must be deployed and updated. For example, you will need to launch your Kubernetes cluster before you can deploy Helm charts to it.
You should explicitly declare these dependencies via terragrunt dependency
blocks (docs).
This will ensure that modules are always updated in the desired order. Additionally, you can use this functionality to pass the outputs of one module into the inputs of another.
Resource Tagging
All Panfactum modules deploy resources with standard tags / labels..
You can add arbitrary additional tags by setting extra_tags
in any of the following files:
global.yaml
environment.yaml
region.yaml
module.yaml
extra_tags
is an object where the keys and values must both be strings.
The defined tags
will be applied to all modules in the specified scope. For example, if extra_tags
is defined in environment.yaml
,
all resources in that environment will receive the tags.
Footnotes
-
This folder lives in your stack repository, is defined by the environment variable
PF_ENVIRONMENTS_DIR
, and was created when runningpf-update-terragrunt
. For more information, see our repository setup guide ↩ -
Note that you must use the
get_terragrunt_dir()
function to resolve the filepath. This will ensure a stable location regardless of how terragrunt is run. ↩