Team workflow example

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/):

Team workflow example

Getting ready

To step through this recipe, you will need the following:

  • An account on some Git hosting (self-hosted or commercial)
  • A working Terraform installation
  • An AWS account with an SSH key configured in Terraform (refer to the Chapter 2, Provisioning IaaS with Terraform recipes)
  • An Internet connection

How to do it…

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.

A simple Git repository

Create a new repository on GitHub:

Note

We might be storing secrets in that repository, such as SSH private keys or passwords. It's probably a safer option to create a private Git repository for now.

A simple Git repository

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.

Initial infrastructure code

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}"
  }
}

Terraform code validation

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.

This looks exactly like our objective. Let's continue.

Infrastructure code commit

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.

Make a pull request

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:

Make a pull request

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:

Make a pull request

Now everyone from your team have access to your work and can discuss it right from GitHub if necessary:

Make a pull request

A few minutes later, one of your coworkers reviews your code and sends you a remark:

Make a pull request

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:

Make a pull request

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:

Make a pull request

Apply the changes

So let's do that right now:

$ 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:

Apply the changes
Apply the changes

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.48.135