By default, a Terraform Cloud remote run will copy the entire
source repository to the TFC runner before it runs the plan. If there
are lots of files in the repository that aren’t needed by Terraform,
this can take a long time. Using the .terraformignore
file can
significantly reduce the time for TFC to prepare a remote plan.
A common pattern is to have a terraform/
subdirectory in a repository
to deploy the infrastructure that supports the application/service/code
in the repository itself. For the purposes of TFC, only that subdirectory
is needed by the runner.
As a simple example, I’ll use the repository for this blog.
It uses the Hugo static site generator to generate content
from a bunch of markdown files. Alongside the content, there is a
terraform/
directory to create/manage an AWS S3 bucket, and
CloudFront distribution.
www.oasys.net/
├── archetypes
├── assets
│ ├── css
│ └── scss
├── content
│ ├── fragments
│ └── posts
├── data
├── layouts
│ ├── _default
│ ├── partials
│ ├── resume
│ ├── shortcodes
│ └── static
├── public
├── resources
│ └── _gen
├── static
├── terraform
└── themes
└── PaperMod
In this small repo there are hundreds of directories and thousands of files that are needlessly copied to the runner, slowing down execution:
moonstone:~/www.oasys.net/terraform/(main=)[www-oasys-net]$ time terraform plan
Running plan in Terraform Cloud. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.
Preparing the remote plan...
The remote workspace is configured to work with configuration at
terraform relative to the target repository.
Terraform will upload the contents of the following directory,
excluding files or directories as defined by a .terraformignore file
at /Users/jlavoie/www.oasys.net/.terraformignore (if it is present),
in order to capture the filesystem context the remote workspace expects:
/Users/jlavoie/www.oasys.net
To view this run in a browser, visit:
https://app.terraform.io/app/oasys/www-oasys-net/runs/run-gySZB1FwgNznF8Hd
Waiting for the plan to start...
Terraform v1.1.7
on linux_amd64
Configuring remote state backend...
Initializing Terraform configuration...
aws_s3_bucket.public: Refreshing state... [id=www.oasys.net]
aws_s3_bucket_policy.public: Refreshing state... [id=www.oasys.net]
aws_s3_bucket_acl.public-read: Refreshing state... [id=www.oasys.net,public-read]
aws_s3_bucket_website_configuration.website: Refreshing state... [id=www.oasys.net]
aws_cloudfront_distribution.dist: Refreshing state... [id=E2GOHKG4OK8ZRL]
[...]
No changes. Your infrastructure matches the configuration.
Your configuration already matches the changes detected above. If you'd like
to update the Terraform state to match, create and apply a refresh-only plan.
real 2m28.516s
user 0m2.948s
sys 0m1.957s
Terraform supports (since version 0.12.11
) a .terraformignore
file in the root of the repository, indicating
which files/directories Terraform Cloud actually needs. This uses the
.gitignore
syntax. In this particular case, we can
invert the logic and ignore everything except the needed directories.
# controls what directories get uploaded to TFC for remote runs
#
# deny by default
*
# explicitly list included directories
!terraform/
Now runs are significantly faster:
moonstone:~/www.oasys.net/terraform/(main*%=)[www-oasys-net]$ time terraform plan > /dev/null
real 0m24.708s
user 0m0.535s
sys 0m0.131s