# Move module call to config branch and specify Terraform sample into .cycloid.yml
This section introduce Cycloid stacks concept to improve the reusability of your stack.
We created a Terraform module during the last step and used it in a main.tf
file inside our stacks
branch. This step will make it more flexible and follow Cycloid stacks concept.
Keep in mind a stack can be deployed several times for different environments or projects. The standard way to do this is to create a Terraform module in the stacks
branch. A Terraform module should be generic and describe an application. This means if we want for an application to create two environments, staging
and prod
, we might want the same infrastructure but with a smaller instance size on staging. So we will describe the infrastructure in a Terraform module and call this module 2 times (one for each env) using different parameters for the instance type.
As well this concept can also be applied to other technologies like Ansible.
This is where you apply Cycloid stacks concept. To make it simple, there is no technological limitation. It's just a way to split a template
(here, the Terraform module) and a parameters
of a template (here Terraform module call).
In our use-case, we will transform the call of the Terraform module main.tf
in a sample file. Each time someone uses your stack, it will use the Terraform module from the stacks
branch and automatically push the module's parameters in a config
branch using your sample file. We will go more into detail about it in this step.
Follow those steps to apply all changes described in this step
As described above let's define our new main.tf.sample
as a sample in the Cycloid stack (similarly to the pipeline variables sample file), we will define the Terraform sample in .cycloid.yml
file.
stack-sample/.cycloid.yml
config:
default:
...
# Configuration of terraform to setup the infrastructure
terraform:
instance:
path: 'terraform/main.tf.sample'
destination: '($ project $)/terraform/($ environment $)/main.tf'
2
3
4
5
6
7
8
TIPS
Cycloid special vars can be used in .cycloid.yml
file, in our case '($ project $)/terraform/($ environment $)/main.tf'
will be rendered by 'snowy/terraform/test/main.tf'
.
Those lines define the path of your stack sample in the stacks
branch and the expected path for the sample after user configuration in the config
branch.
After this change, the next time you create a project or a new environment with this stack, the example of Terraform file to put in the Git config
branch will be displayed, letting the user specify is own configuration:
Then it will be automatically pushed into his config repository
Unfortunately, this does not apply to an existing env, and this is why we created the config branch and manually put this file in the commands above.
Now to make your pipeline take into account, you need to apply the concept of merging stacks
and config
that you will define in the pipeline with the following changes:
- Add a
git
resource for our newconfig
branch. - Add merge stack and config sample as describe in produce a configured stack from stack and config section.
stack-sample/pipeline/variables.sample.yml
# Branch used to store the config of the stack
config_git_branch: config
2
We define a pipeline variable to specify the branch for our new git
resource. And as well create a new git resource for the config branch:
stack-sample/pipeline/pipeline.yml
resources:
...
# The Terraform config (will be merged with the stack)
- name: git_config
type: git
source:
uri: ((git_repository))
branch: ((config_git_branch))
private_key: ((git_ssh_key))
paths:
- ((project))/terraform/((env))/*
2
3
4
5
6
7
8
9
10
11
12
Notice the paths
section here to limit the trigger of the pipeline only if the configuration for this specific project and env change.
Then we need to merge our stack and our config inside the pipeline. We will use the same tips as the previous step based on YAML Alias indicators (opens new window).
stack-sample/pipeline/pipeline.yml
# YAML anchors
shared:
- &task-merge-stack-and-config
task: merge-stack-and-config
config:
platform: linux
image_resource:
type: docker-image
source:
repository: cycloid/cycloid-toolkit
tag: latest
run:
path: /usr/bin/merge-stack-and-config
inputs:
- name: git_config
path: "config"
- name: git_stack
path: "stack"
outputs:
- name: merged-stack
path: "merged-stack"
params:
CONFIG_PATH: ((project))/terraform/((env))
STACK_PATH: stack-sample/terraform
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
This task calls a script provided by cycloid in our cycloid-toolkit image (opens new window) to merge our two expected inputs stack
and config
and put the result of the merge in a merged-stack
output.
This merge also takes CONFIG_PATH
and STACK_PATH
as params related to the expected path of Terraform files defined in .cycloid.yml
Last change, add task-merge-stack-and-config
task and git_config
resource in our Terraform jobs to merge our config and stack before running the Terraform resource.
stack-sample/pipeline/pipeline.yml
jobs:
...
- name: terraform-plan
plan:
- do:
- get: git_stack
trigger: true
- get: git_config
trigger: true
- get: git_code
trigger: true
passed:
- unittest
- *task-merge-stack-and-config
- *task-get-commit
- put: tfstate
params:
plan_only: true
terraform_source: merged-stack/
var_files:
- extracted-vars/terraform.tfvars
- name: terraform-apply
plan:
- do:
- get: git_stack
trigger: false
passed:
- terraform-plan
- get: git_config
trigger: false
passed:
- terraform-plan
- get: tfstate
trigger: false
passed:
- terraform-plan
- get: git_code
passed:
- terraform-plan
- *task-merge-stack-and-config
- *task-get-commit
- put: tfstate
params:
plan_run: true
terraform_source: merged-stack/
var_files:
- extracted-vars/terraform.tfvars
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
The code above adds the get
call of our git_config
resource, then use the YAML anchor to add a merge task before.
Then we also changed the terraform_source
from terraform (put: tfstate
) to use the output of our merge merged-stack
instead of the Terraform code from the stack branch.
Add and commit those changes in Git:
git add .
git commit -m "Step 5"
git push origin stacks
2
3
Get back to Cycloid's dashboard, and click on the Refresh pipeline
button .
# Key points to remember
- A stack can be deployed several times for different environments or projects
- A Terraform module should be generic and describe an application (same thing with Ansible for example)
- A stack is a way to split a template (for example a Terraform module) and a parameters of a template (for example a Terraform module call or
main.tf
) - Most of the time, the parameters (for example
main.tf
) is transformed in a sample file - Each time someone uses your stack, it will use the Terraform module from the
stacks
branch and automatically push the module's parameters in aconfig
branch using your sample file