mirror of
https://github.com/sidpalas/devops-directive-terraform-course.git
synced 2025-12-13 14:21:14 +00:00
Compare commits
17 Commits
test-pr-fl
...
feature/pu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dead4bda7d | ||
|
|
521ce1be1e | ||
|
|
4fd6d96faf | ||
|
|
8e07a9ca52 | ||
|
|
470941a03d | ||
|
|
a35c1c0632 | ||
|
|
becbd33b93 | ||
|
|
3c0fe8a7f4 | ||
|
|
f21f709b51 | ||
|
|
4afa2070b3 | ||
|
|
d551e98de5 | ||
|
|
4199e89b67 | ||
|
|
b46e7de9b4 | ||
|
|
5fd2d96596 | ||
|
|
30b623bfac | ||
|
|
3b6a954159 | ||
|
|
2e3891b7dc |
53
.github/workflows/terraform.yml
vendored
53
.github/workflows/terraform.yml
vendored
@@ -1,9 +1,12 @@
|
||||
name: "Terraform"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# Uncomment to enable staging deployment
|
||||
# push:
|
||||
# branches:
|
||||
# - main
|
||||
release:
|
||||
types: [published]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
@@ -23,7 +26,8 @@ jobs:
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v1
|
||||
with:
|
||||
terraform_version: 0.15.4
|
||||
terraform_version: 1.0.1
|
||||
terraform_wrapper: false
|
||||
|
||||
- name: Terraform Format
|
||||
id: fmt
|
||||
@@ -36,7 +40,8 @@ jobs:
|
||||
- name: Terraform Plan
|
||||
id: plan
|
||||
if: github.event_name == 'pull_request'
|
||||
run: terraform plan -no-color
|
||||
# Route 53 zone must already exist for this to succeed!
|
||||
run: terraform plan -var db_pass=${{secrets.DB_PASS }} -no-color
|
||||
continue-on-error: true
|
||||
|
||||
- uses: actions/github-script@0.9.0
|
||||
@@ -70,6 +75,38 @@ jobs:
|
||||
if: steps.plan.outcome == 'failure'
|
||||
run: exit 1
|
||||
|
||||
# - name: Terraform Apply
|
||||
# if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||
# run: terraform apply -auto-approve
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.15.5'
|
||||
|
||||
- name : Terratest Execution
|
||||
if: github.event_name == 'pull_request'
|
||||
working-directory: 08-testing/tests/terratest
|
||||
run: |
|
||||
go test . -v timeout 10m
|
||||
|
||||
- name: Check tag
|
||||
id: check-tag
|
||||
run: |
|
||||
if [[ ${{ github.ref }} =~ ^refs\/tags\/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo ::set-output name=environment::production
|
||||
elif [[ ${{ github.ref }} == 'refs/heads/main' ]]; then echo ::set-output name=environment::staging
|
||||
else echo ::set-output name=environment::unknown
|
||||
fi
|
||||
|
||||
- name: Terraform Apply Global
|
||||
if: github.event_name == 'push' || github.event_name == 'release'
|
||||
working-directory: 07-managing-multiple-environments/file-structure/global
|
||||
run: |
|
||||
terraform init
|
||||
terraform apply -auto-approve
|
||||
|
||||
- name: Terraform Apply Staging
|
||||
if: steps.check-tag.outputs.environment == 'staging' && github.event_name == 'push'
|
||||
run: terraform apply -var db_pass=${{secrets.DB_PASS }} -auto-approve
|
||||
|
||||
- name: Terraform Apply Production
|
||||
if: steps.check-tag.outputs.environment == 'production' && github.event_name == 'release'
|
||||
working-directory: 07-managing-multiple-environments/file-structure/production
|
||||
run: |
|
||||
terraform init
|
||||
terraform apply -var db_pass=${{secrets.DB_PASS }} -auto-approve
|
||||
|
||||
3
01-cloud-and-iac/README.md
Normal file
3
01-cloud-and-iac/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 01 - Evolution of Cloud + Infrastructure as Code
|
||||
|
||||
This module doesn't have any corresponding code.
|
||||
@@ -1,8 +0,0 @@
|
||||
## Install Terraform
|
||||
1) install terraform
|
||||
|
||||
## AWS Account Setup
|
||||
2) create non-root AWS user
|
||||
3) Add AmazonEC2FullAccess
|
||||
4) Save Access key + secret key (or use AWS CLI `aws configure` -- https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
|
||||
|
||||
22
02-overview/README.md
Normal file
22
02-overview/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## 02 - Overview + Setup
|
||||
|
||||
## Install Terraform
|
||||
|
||||
Official installation instructions from HashiCorp: https://learn.hashicorp.com/tutorials/terraform/install-cli
|
||||
|
||||
## AWS Account Setup
|
||||
|
||||
AWS Terraform provider documentation: https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication
|
||||
|
||||
1) create non-root AWS user
|
||||
2) Add the necessary IAM roles (e.g. AmazonEC2FullAccess)
|
||||
3) Save Access key + secret key (or use AWS CLI `aws configure` -- https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
|
||||
|
||||
## Hello World
|
||||
|
||||
`./main.tf` contains minimal configuration to provision an EC2 instance.
|
||||
|
||||
1) `aws configure`
|
||||
2) `terraform init`
|
||||
3) `terraform plan`
|
||||
4) `terraform apply`
|
||||
@@ -1,4 +1,45 @@
|
||||
1) Create account credentials
|
||||
## 03 - Basics
|
||||
|
||||
## Remote Backends
|
||||
|
||||
Remote backends enable storage of TF state in a remote, location to enable secure collaboration.
|
||||
|
||||
### Terraform Cloud
|
||||
|
||||
https://www.terraform.io/cloud
|
||||
|
||||
`./terraform-cloud-backend/main.tf`
|
||||
|
||||
### AWS S3 + Dynamo DB
|
||||
|
||||
Steps to initialize backend in AWS and manage it with Terraform:
|
||||
|
||||
1) Use config from `./aws-backend/` (init, plan, apply) to provision s3 bucket and dynamoDB table with local state
|
||||
2) Uncomment the remote backend configuration
|
||||
3) Reinitialize with `terraform init`:
|
||||
|
||||
```
|
||||
Do you want to copy existing state to the new backend?
|
||||
Pre-existing state was found while migrating the previous "local" backend to the
|
||||
newly configured "s3" backend. No existing state was found in the newly
|
||||
configured "s3" backend. Do you want to copy this state to the new "s3"
|
||||
backend? Enter "yes" to copy and "no" to start with an empty state.
|
||||
|
||||
Enter a value: yes
|
||||
```
|
||||
|
||||
Now the S3 bucket and dynamoDB table are mam and are able to be used as the state backend!
|
||||
|
||||
## Web-App
|
||||
|
||||
Generic web application architecture including:
|
||||
- EC2 instances
|
||||
- S3 bucket
|
||||
- RDS instance
|
||||
- Load balancer
|
||||
- Route 53 DNS config
|
||||
|
||||
This example will be refined and improved in later modules.
|
||||
|
||||
## Architecture
|
||||

|
||||
@@ -1,31 +0,0 @@
|
||||
Steps to initialize backend in AWS and manage it with Terraform:
|
||||
|
||||
1) Use config from `bootstrap` (init, plan, apply) to provision s3 bucket and dynamoDB table with local state
|
||||
2) copy state file into import-bootstrap
|
||||
1) cp terraform.tfstate ../import-bootstrap
|
||||
3) Initialize within `import-bootstrap` using `terraform init`
|
||||
4) Uncomment out s3 backend provider:
|
||||
|
||||
```
|
||||
backend "s3" {
|
||||
bucket = "devops-directive-tf-state"
|
||||
key = "tf-infra/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
dynamodb_table = "terraform-state-locking"
|
||||
encrypt = true
|
||||
}
|
||||
```
|
||||
|
||||
4) Reinitialize with `terraform init`:
|
||||
|
||||
```
|
||||
Do you want to copy existing state to the new backend?
|
||||
Pre-existing state was found while migrating the previous "local" backend to the
|
||||
newly configured "s3" backend. No existing state was found in the newly
|
||||
configured "s3" backend. Do you want to copy this state to the new "s3"
|
||||
backend? Enter "yes" to copy and "no" to start with an empty state.
|
||||
|
||||
Enter a value: yes
|
||||
```
|
||||
|
||||
Now the S3 bucket and dynamoDB table are managed by Terraform and are able to be used as the state backend!
|
||||
@@ -1,47 +0,0 @@
|
||||
terraform {
|
||||
### UNCOMMENT THIS AFTER INITIALIZNG ###
|
||||
# backend "s3" {
|
||||
# bucket = "devops-directive-tf-state"
|
||||
# key = "03-basics/import-bootstrap/terraform.tfstate"
|
||||
# region = "us-east-1"
|
||||
# dynamodb_table = "terraform-state-locking"
|
||||
# encrypt = true
|
||||
# }
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "terraform_state" {
|
||||
bucket = "devops-directive-tf-state"
|
||||
force_destroy = true
|
||||
versioning {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
server_side_encryption_configuration {
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "AES256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_dynamodb_table" "terraform_locks" {
|
||||
name = "terraform-state-locking"
|
||||
billing_mode = "PAY_PER_REQUEST"
|
||||
hash_key = "LockID"
|
||||
attribute {
|
||||
name = "LockID"
|
||||
type = "S"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
terraform {
|
||||
# THIS BACKEND CONFIG GETS UNCOMMENTED IN IMPORT-BOOTSTRAP
|
||||
#############################################################
|
||||
## AFTER RUNNING TERRAFORM APPLY (WITH LOCAL BACKEND)
|
||||
## YOU WILL UNCOMMENT THIS CODE THEN RERUN TERRAFORM INIT
|
||||
## TO SWITCH FROM LOCAL BACKEND TO REMOTE AWS BACKEND
|
||||
#############################################################
|
||||
# backend "s3" {
|
||||
# bucket = "devops-directive-tf-state"
|
||||
# bucket = "devops-directive-tf-state" # REPLACE WITH YOUR BUCKET NAME
|
||||
# key = "03-basics/import-bootstrap/terraform.tfstate"
|
||||
# region = "us-east-1"
|
||||
# dynamodb_table = "terraform-state-locking"
|
||||
@@ -21,7 +25,7 @@ provider "aws" {
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "terraform_state" {
|
||||
bucket = "devops-directive-tf-state"
|
||||
bucket = "devops-directive-tf-state" # REPLACE WITH YOUR BUCKET NAME
|
||||
force_destroy = true
|
||||
versioning {
|
||||
enabled = true
|
||||
@@ -1,8 +0,0 @@
|
||||
## Terraform Cloud Account Setup
|
||||
1) Create account at terraform.io
|
||||
2) Use terraform login
|
||||
3) Set any necessary credentials for whichever cloud services you are using because with terraform cloud backend, the plan/apply are actually run remotely.
|
||||
```
|
||||
# AWS_ACCESS_KEY_ID
|
||||
# AWS_SECRET_ACCESS_KEY
|
||||
```
|
||||
@@ -21,8 +21,14 @@ provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
variable "db_pass" {
|
||||
description = "password for database"
|
||||
variable "db_pass_1" {
|
||||
description = "password for database #2"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "db_pass_2" {
|
||||
description = "password for database #2"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
@@ -39,7 +45,7 @@ module "web_app_1" {
|
||||
create_dns_zone = true
|
||||
db_name = "webapp1db"
|
||||
db_user = "foo"
|
||||
db_pass = var.db_pass
|
||||
db_pass = var.db_pass_1
|
||||
}
|
||||
|
||||
module "web_app_2" {
|
||||
@@ -53,6 +59,6 @@ module "web_app_2" {
|
||||
instance_type = "t2.small"
|
||||
create_dns_zone = true
|
||||
db_name = "webapp2db"
|
||||
db_user = "foo"
|
||||
db_pass = var.db_pass
|
||||
db_user = "bar"
|
||||
db_pass = var.db_pass_2
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
terraform {
|
||||
# Assumes s3 bucket and dynamo DB table already set up
|
||||
# See /code/03-basics/aws-backend
|
||||
backend "s3" {
|
||||
bucket = "devops-directive-tf-state"
|
||||
key = "07-managing-multiple-environments/global/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
dynamodb_table = "terraform-state-locking"
|
||||
encrypt = true
|
||||
}
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
# Route53 zone is shared across staging and production
|
||||
resource "aws_route53_zone" "primary" {
|
||||
name = "mysuperawesomesite.com"
|
||||
}
|
||||
@@ -39,7 +39,7 @@ module "web_app" {
|
||||
domain = "mysuperawesomesite.com"
|
||||
environment_name = local.environment_name
|
||||
instance_type = "t2.small"
|
||||
create_dns_zone = true
|
||||
create_dns_zone = false
|
||||
db_name = "${local.environment_name}mydb"
|
||||
db_user = "foo"
|
||||
db_pass = var.db_pass
|
||||
|
||||
@@ -32,7 +32,7 @@ locals {
|
||||
}
|
||||
|
||||
module "web_app" {
|
||||
source = "../../05-organization-and-modules/web-app-module"
|
||||
source = "../../06-organization-and-modules/web-app-module"
|
||||
|
||||
# Input Variables
|
||||
bucket_name = "devops-directive-web-app-data-${local.environment_name}"
|
||||
|
||||
6
08-testing/tests/terratest/README.md
Normal file
6
08-testing/tests/terratest/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
How to run this test?
|
||||
|
||||
Build, then run...
|
||||
|
||||
`go test -v timeout 10m`
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestTerraformHelloWorldExample(t *testing.T) {
|
||||
instanceURL := terraform.Output(t, terraformOptions, "url")
|
||||
tlsConfig := tls.Config{}
|
||||
maxRetries := 30
|
||||
timeBetweenRetries := 5 * time.Second
|
||||
timeBetweenRetries := 10 * time.Second
|
||||
|
||||
http_helper.HttpGetWithRetryWithCustomValidation(
|
||||
t, instanceURL, &tlsConfig, maxRetries, timeBetweenRetries, validate,
|
||||
|
||||
45
README.md
Normal file
45
README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# DevOps Directive Terraform Course
|
||||
|
||||
This is the companion repo to the complete Terraform course from DevOps Directive (https://www.youtube.com/c/DevOpsDirective)
|
||||
|
||||
*Note:* The videos for the course have not been released yet... stay tuned!
|
||||
|
||||
## 01 - Evolution of Cloud + Infrastructure as Code
|
||||
|
||||
High level overview of the evolution of cloud computing and infrastructure as code.
|
||||
|
||||
This module does not have any corresponding code.
|
||||
|
||||
## 02 - Overview + Setup
|
||||
|
||||
Terraform overview and setup instructions.
|
||||
|
||||
Includes basic `hello world` terraform config to provision a single AWS EC2 instance.
|
||||
|
||||
## 03 - Basics
|
||||
|
||||
Covers main usage pattern, setting up remote backends (where the terraform state is stored) using terraform Cloud and AWS, and provides a naive implementation of a web application architecture.
|
||||
|
||||
## 04 - Variables and Outputs
|
||||
|
||||
Introduces the concepts of variables which enable Terraform configurations to be flexible and composable. Refactors web application to use these features.
|
||||
|
||||
## 05 - Language Features
|
||||
|
||||
Describes additional features of the Hashicorp Configuration Language (HCL).
|
||||
|
||||
## 06 - Organization and Modules
|
||||
|
||||
Demonstrates how to structure terraform code into reuseable modules and how to instantiate/configure modules.
|
||||
|
||||
## 07 - Managing Multiple Environments
|
||||
|
||||
Shows two methods for managing multiple environments (e.g. dev/staging/prodution) with Terraform.
|
||||
|
||||
## 08 - Testing
|
||||
|
||||
Explains different types of testing (manual + automated) for Terraform modules and configurations.
|
||||
|
||||
## 09 - Developer Workflows + CI/CD
|
||||
|
||||
Covers how teams can work together with Terraform and how to set up CI/CD pipelines to keep infrastructure environments up to date.
|
||||
Reference in New Issue
Block a user