Working with infrastructure code is very similar to working with software code. Countless books and methods exist on the subject and approaches are usually very opinionated.
A simple workflow I propose to use here for our infrastructure-as-code work is based on what's called the GitHub Flow (https://guides.github.com/introduction/flow/):
To step through this recipe, you will need the following:
Start by creating a new repository for use with your team. Use any service that works for you: GitLab, GitHub, BitBucket, and others. This example uses GitHub.
Create a new repository on GitHub:
Now import this new empty repository on your workstation, in a dedicated folder:
$ git clone <your_git_repostory_address> Cloning into 'my_infrastructure_code'... remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Receiving objects: 100% (3/3), done. Checking connectivity... done.
Create a new Git branch to work on an initial infrastructure:
$ git checkout -b new_infrastructure Switched to a new branch 'new_infrastructure'
Add some Terraform code from the previous recipes, such as a single CoreOS instance. For the record, here's the variables.tf
file:
variable "aws_region" { default = "eu-west-1" } variable "aws_ssh_admin_key_file" { default = "keys/aws_terraform" } variable "aws_coreos_ami" { default = "ami-85097ff6" } variable "cluster_size" { default = "1" description = "Number of nodes in the cluster" } variable "aws_instance_type" { default = "t2.micro" description = "Instance type" }
Here's a deliberately badly formatted provider.tf
:
provider "aws" { region = "${var.aws_region}" }
Also, here's a CoreOS instance in instances.tf
:
resource "aws_instance" "coreos" { count = "${var.cluster_size}" ami = "${var.aws_coreos_ami}" instance_type = "${var.aws_instance_type}" key_name = "${aws_key_pair.admin_key.key_name}" associate_public_ip_address = true tags { Name = "coreos_${count.index+1}" } }
Let's be sure our code validates:
$ terraform validate
Thankfully, it does!
Does this code plan to do what we want it to do? Have a look:
$ terraform plan [...] + aws_instance.coreos [...] + aws_key_pair.admin_key [...] Plan: 2 to add, 0 to change, 0 to destroy.
What are the new files on this branch that aren't on master? Let's find out:
$ git status [...] instances.tf keys.tf keys/ provider.tf variables.tf
Good, those are the files we just created. Let's add them to a commit
:
$ git add . $ git commit -m "an initial infrastructure" [new_infrastructure 2415ad4] an initial infrastructure 6 files changed, 65 insertions(+) create mode 100644 instances.tf create mode 100644 keys.tf create mode 100644 keys/aws_terraform create mode 100644 keys/aws_terraform.pub create mode 100644 provider.tf create mode 100644 variables.tf
Now let's send the branch upstream so that our coworkers can see our work that's still not yet in production:
$ git push --set-upstream origin new_infrastructure Counting objects: 9, done. Delta compression using up to 4 threads. Compressing objects: 100% (8/8), done. Writing objects: 100% (9/9), 2.60 KiB | 0 bytes/s, done. Total 9 (delta 0), reused 0 (delta 0) To [email protected]:sjourdan /my_infrastructure_code.git * [new branch] new_infrastructure -> new_infrastructure Branch new_infrastructure set up to track remote branch new_infrastructure from origin.
Navigate to your repository, and you'll see something similar to the following screenshot, showing an information about the new branch being just pushed. GitHub proposes to easily create a pull request. A pull request is a request to merge the content of one branch to another branch. In our case, we want to ask our coworkers to merge our new_infrastructure
branch into the master branch, to create some discussion:
When you open a pull request, GitHub automatically tries the requested merge (in our case, from our branch to master). Here, no conflicts are noted, so we can write a message explaining what our request is all about. A pull request is often composed of multiple commits, so a summary is more than welcome:
Now everyone from your team have access to your work and can discuss it right from GitHub if necessary:
A few minutes later, one of your coworkers reviews your code and sends you a remark:
She might be right; let's find out with the Terraform formatter:
$ terraform fmt provider.tf
Looks like there was a formatting issue! Use git diff
to see what's the difference:
$ git diff diff --git a/provider.tf b/provider.tf index 59cdf2a..b54eb94 100644 --- a/provider.tf +++ b/provider.tf @@ -1 +1,3 @@ -provider "aws" { region = "${var.aws_region}" } +provider "aws" { + region = "${var.aws_region}" +}
We're happy with that; let's add
, commit
, and push
. Pushing to our remote branch will automatically add our commit to the pull request as well:
$ git add provider.tf $ git commit -m "fixed bad formatting" [new_infrastructure b027825] fixed bad formatting 1 file changed, 3 insertions(+), 1 deletion(-) $ git push
Our coworker can now see in real time that we took her remark into account, as GitHub automatically marks it as outdated:
Now our coworker pulled the changes on her side, tried to plan the changes herself with Terraform, and announces she's happy with the results as well:
$ terraform apply aws_key_pair.admin_key: Creating... [...] aws_instance.coreos: Creating...[...] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Is there anything new in our repository? Have a look:
$ git status terraform.tfstate
Sure, now we have to ship our infrastructure state to the pull request:
$ git add terraform.tfstate $ git commit -m "initial terraform state" $ git push
Our coworker sees that everything is all right, and she also checked the server is doing well. So, now she can merge our branch, close the pull request with a message, and then delete the now useless branch:
Our code and its fixes are now on master, along with the updated infrastructure state, all done in full collaboration with a coworker.
For any new feature, anything added to the infrastructure should follow the same pattern: create a branch, insert your changes, open a pull request, discuss the changes with the coworkers, apply the change, and merge to master. Master is now the reference again.
3.144.48.135