Use a lockable state repository.

Also, make use of terraform workspaces.
This commit is contained in:
Patrick MARIE 2022-02-19 17:03:41 +01:00
parent 3443833de1
commit 1425c98072
11 changed files with 179 additions and 15 deletions

View File

@ -50,6 +50,19 @@ For all the next commands, make sure to use the `AWS_PROFILE` environment variab
$ export AWS_PROFILE=infra-test
```
### State space initialization
This section can be skipped; If so, make sure to disable other projects' `init.tf`.
The `state` infra will create a s3 & dynamo space to store terraform state.
```sh
$ cd state
$ terraform init
$ terraform plan -var "aws_profile=$AWS_PROFILE" -out tf.plan
$ terraform apply tf.plan
...
```
### First: EKS
@ -100,7 +113,9 @@ Once eks is deployed, and kubectl correctly configured, we can continue by deplo
```sh
$ cd ../k8s
$ terraform init
$ terraform plan -var enable_nginx=1 -out tf.plan
# By default, it will install nginx; To disable it, use prod's workspace by:
# $ terraform workspace new prod
$ terraform plan -out tf.plan
$ terraform apply
...
Apply complete! Resources: 3 added, 0 changed, 1 destroyed.
@ -109,19 +124,58 @@ Apply complete! Resources: 3 added, 0 changed, 1 destroyed.
As a result, let's verify there is our stuff deployed:
```sh
$ kubectl get pods --namespace testaroo
$ kubectl get pods --namespace testaroo-default
NAME READY STATUS RESTARTS AGE
alpine 1/1 Running 0 5m3s
nginx-98cf9b965-l785s 1/1 Running 0 5m3s
nginx-98cf9b965-smpkr 1/1 Running 0 5m3s
$ kubectl get deploy -n testaroo nginx -o wide
$ kubectl get deploy -n testaroo-default nginx -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 2/2 2 2 5m46s nginx-container nginx app=Nginx
$ kubectl get svc -n testaroo -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx NodePort 172.20.10.182 <none> 80:31234/TCP 6m8s app=Nginx
$ kubectl get svc -n testaroo-default -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-lb LoadBalancer 172.20.0.75 a3a176133964a463db33dafb6c6e06a1-480398782.eu-west-3.elb.amazonaws.com 80:30512/TCP 57s app=Nginx
nginx-np NodePort 172.20.227.6 <none> 80:31234/TCP 57s app=Nginx
```
And now, as the `default` workspace was deployed, it is possible to switch to prod's:
```sh
$ terraform workspace new prod
$ terraform plan -out tf-prod.plan
$ terraform apply tf-prod.plan
$ kubectl get ns
NAME STATUS AGE
default Active 18m
kube-node-lease Active 18m
kube-public Active 18m
kube-system Active 18m
testaroo-default Active 3m10s
testaroo-prod Active 14s
$ kubectl get pods -n testaroo-prod
NAME READY STATUS RESTARTS AGE
alpine 1/1 Running 0 39s
```
No `nginx` for `prod`'s workspace, as it was disabled!
After using workspaces, it is possible to check the state files in s3:
```sh
$ aws s3 ls terraform-state-infra-aws-eks
PRE env:/
PRE global/
$ aws s3 ls terraform-state-infra-aws-eks/global/s3/
2022-02-19 16:29:43 33800 terraform.eks.tfstate
2022-02-19 16:40:25 18754 terraform.k8s.tfstate
$ aws s3 ls terraform-state-infra-aws-eks/env:/prod/global/s3/
2022-02-19 16:43:03 8392 terraform.k8s.tfstate
```
### Reaching the app.
@ -157,7 +211,7 @@ $ kubectl get svc -n testaroo nginx-lb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-lb LoadBalancer 172.20.149.132 a34059e68106b41a292730b5defe734b-581837320.eu-west-3.elb.amazonaws.com 80:31698/TCP 3m50s
$ terraform output 09:59:47
$ terraform output
lb-address = "a34059e68106b41a292730b5defe734b-581837320.eu-west-3.elb.amazonaws.com"
```

9
eks/init.tf Normal file
View File

@ -0,0 +1,9 @@
terraform {
backend "s3" {
bucket = "terraform-state-infra-aws-eks"
key = "global/s3/terraform.eks.tfstate"
region = "eu-west-3"
dynamodb_table = "terraform-state-locks-infra-aws-eks"
encrypt = true
}
}

9
k8s/init.tf Normal file
View File

@ -0,0 +1,9 @@
terraform {
backend "s3" {
bucket = "terraform-state-infra-aws-eks"
key = "global/s3/terraform.k8s.tfstate"
region = "eu-west-3"
dynamodb_table = "terraform-state-locks-infra-aws-eks"
encrypt = true
}
}

View File

@ -1,6 +1,6 @@
resource "kubernetes_namespace" "testaroo" {
metadata {
name = "testaroo"
name = "testaroo-${terraform.workspace}"
}
}
@ -20,7 +20,7 @@ resource "kubernetes_pod" "basic-pod" {
}
resource "kubernetes_deployment" "testaroo" {
count = var.enable_nginx
count = terraform.workspace == "prod" ? 0 : 1
metadata {
name = "nginx"
@ -56,7 +56,7 @@ resource "kubernetes_deployment" "testaroo" {
}
resource "kubernetes_service" "testaroo" {
count = var.enable_nginx
count = length(kubernetes_deployment.testaroo)
metadata {
name = "nginx-np"
@ -78,7 +78,7 @@ resource "kubernetes_service" "testaroo" {
}
resource "kubernetes_service" "testaroo-lb" {
count = var.enable_nginx
count = length(kubernetes_deployment.testaroo)
metadata {
name = "nginx-lb"

View File

@ -1,4 +1,5 @@
variable "enable_nginx" {
type = number
default = 0
}
# Superseeded by terraform's workspaces.
# variable "enable_nginx" {
# type = number
# default = 0
# }

21
state/.terraform.lock.hcl Normal file
View File

@ -0,0 +1,21 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "3.74.3"
constraints = "~> 3.27"
hashes = [
"h1:h4TYqgRKTuuWfZtxJnEGcs/NxGCaxZ4jr0IwTfgZDRM=",
"zh:25401cd4667d0496caf7e92e74ecef7c98cf74465570705cda2207770c27ff6c",
"zh:2d154527a9b2585f72fc5eceac635257e3f50f68de8a519e71c795d5166a0a22",
"zh:499fa5201804a5a33a90d683147fb2f81da91bfcd8ed20293f88f6f39cedbf97",
"zh:730284250fd949a59afb6935b3a68a33709d5a78b686fa98f351ad32c919cfc3",
"zh:7461ebd6fb35900d620cfa3f42126d988ea1e604ee3828d1c64d5727f908bd26",
"zh:7c85743b31c7459f8e74aaa98471ba82c54517eb908603411808a12982d89b1c",
"zh:8ed977b7fb97de624f5414b08cab36fd973a624072e0e9082c0c822e0864c7b9",
"zh:94ae7313bb0b425d4007a0b70601a337972c4f0f7a323487acf69215e74b4425",
"zh:b5a1589672d709da725a72c46d28bf5b2dea71325f6e0b44a0049f644cd09eba",
"zh:c7e8e7ce59e4578416557fc2f138137af3c8365ac3e34f0ff5166323c7d641a1",
"zh:ccf2e286b207e749fff76bb4075deddb9e7e237936d8654f34828c54e7035455",
]
}

17
state/README.md Normal file
View File

@ -0,0 +1,17 @@
# state
This terraform infra creates mandatory s3 bucket & dynamo db for locks to handle terraform's states.
## Usage
```sh
$ export AWS_PROFILE=infra-test
$ terraform init
$ terraform plan -var "aws_profile=$AWS_PROFILE" -out tf.plan
$ terraform apply tf.plan
...
$
```
Once created, other terraform infras' states can be saved in those s3/dynamo's repositories.

9
state/dynamo.tf Normal file
View File

@ -0,0 +1,9 @@
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-state-locks-infra-aws-eks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}

15
state/main.tf Normal file
View File

@ -0,0 +1,15 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.27"
}
}
required_version = ">= 0.14.9"
}
provider "aws" {
profile = var.aws_profile
region = var.aws_region
}

19
state/s3.tf Normal file
View File

@ -0,0 +1,19 @@
resource "aws_s3_bucket" "terraform_state" {
bucket = "terraform-state-infra-aws-eks"
# lifecycle {
# prevent_destroy = true
# }
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}

10
state/variables.tf Normal file
View File

@ -0,0 +1,10 @@
variable "aws_profile" {
type = string
default = "aws-infra"
}
variable "aws_region" {
type = string
default = "eu-west-3"
}