1) Amazon ElastiCache Overview
Amazon ElastiCache Overview:
• The same way RDS is to get managed Relational Databases…
• ElastiCache is to get managed Redis or Memcached
• Caches are in-memory databases with really high performance, low latency
• Helps reduce load off of databases for read intensive workloads
• Helps make your application stateless
• AWS takes care of OS maintenance / patching, optimizations, setup, configuration, monitoring, failure recovery and backups
• Using ElastiCache involves heavy application code changes
2) ElastiCache – Redis vs Memcached

3) Redis Cluster Mode Disabled
ta sẽ có một Redis Cluster chỉ có 1 Shard với số lượng node của Shard là 1 tới 6 node.
https://viblo.asia/p/aws-elasticache-provisioning-with-terraform-x7Z4D6xoLnX

3.1) Create VPC for Redis Cluster
Ở đây chúng ta sẽ tạo VPC vì trong thực tế chả bao giờ chúng ta sử dụng VPC default cả.
>>>>>>>>>>
>>>c1-01-variables.tf
>>>>>>>>>>
# Input Variables
# AWS Region
variable "aws_region" {
description = "Region in which AWS Resources to be created"
type = string
default = "us-east-1"
}
variable "env" {
description = "Environment in which AWS Resources to be created"
type = string
default = "develop"
}
locals {
name = "nimtechnology"
common_tags = {
Component = "nimtechnology"
Environment = var.env
}
redis_cluster_name = "${local.name}-${var.cluster_name}"
}
variable "cluster_name" {
default = "aws-redis"
}
# VPC CIDR Block
variable "vpc_cidr_block" {
description = "VPC CIDR Block"
type = string
default = "10.0.0.0/16"
}
# VPC Database Subnets
variable "vpc_elasticache_subnets" {
description = "VPC Redis Subnets"
type = list(string)
default = ["10.0.151.0/24", "10.0.152.0/24"]
}
# VPC Create Database Subnet Group (True / False)
variable "vpc_create_elasticache_subnet_group" {
description = "VPC Create Redis Subnet Group"
type = bool
default = true
}
# VPC Create Database Subnet Route Table (True or False)
variable "vpc_create_elasticache_subnet_route_table" {
description = "VPC Create Redis Subnet Route Table"
type = bool
default = true
}
# VPC Public Subnets
variable "vpc_public_subnets" {
description = "VPC Public Subnets"
type = list(string)
default = ["10.0.101.0/24", "10.0.102.0/24"]
}
# VPC Private Subnets
variable "vpc_private_subnets" {
description = "VPC Private Subnets"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
# VPC Enable NAT Gateway (True or False)
variable "vpc_enable_nat_gateway" {
description = "Enable NAT Gateways for Private Subnets Outbound Communication"
type = bool
default = true
}
# VPC Single NAT Gateway (True or False)
variable "vpc_single_nat_gateway" {
description = "Enable only single NAT Gateway in one Availability Zone to save costs during our demos"
type = bool
default = true
}
Chúng ta sử dụng module VPC
>>>>>>>>>>>>>
>>>>c1-02-vpc.tf
>>>>>>>>>>>>>
# AWS Availability Zones Datasource
data "aws_availability_zones" "available" {
}
# Create VPC Terraform Module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
#version = "3.11.0"
version = "~> 3.11"
# VPC Basic Details
name = local.redis_cluster_name
cidr = var.vpc_cidr_block
azs = data.aws_availability_zones.available.names
public_subnets = var.vpc_public_subnets
private_subnets = var.vpc_private_subnets
#Elasticache Subnets
elasticache_subnets = var.vpc_elasticache_subnets
create_elasticache_subnet_group = var.vpc_create_elasticache_subnet_group
create_elasticache_subnet_route_table = var.vpc_create_elasticache_subnet_route_table
# create_elasticache_internet_gateway_route = true
# create_elasticache_nat_gateway_route = true
# NAT Gateways - Outbound Communication
enable_nat_gateway = var.vpc_enable_nat_gateway
single_nat_gateway = var.vpc_single_nat_gateway
# VPC DNS Parameters
enable_dns_hostnames = true
enable_dns_support = true
tags = local.common_tags
vpc_tags = local.common_tags
# Additional Tags to Subnets
public_subnet_tags = {
Type = "Public Subnets"
"kubernetes.io/role/elb" = 1
"kubernetes.io/cluster/${local.redis_cluster_name}" = "shared"
}
private_subnet_tags = {
Type = "private-subnets"
"kubernetes.io/role/internal-elb" = 1
"kubernetes.io/cluster/${local.redis_cluster_name}" = "shared"
}
elasticache_subnet_tags = {
Type = "database-subnets"
}
}
3.2) Install Redis Cluster Mode Disabled on AWS by terraform
c2-01-redis-variables.tf
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//checked
variable "family" {
type = string
default = "redis5.0"
}
//checked
variable "cache_identifier" {
default = "redis-cluster-mode-enable-nimtechnology"
}
//checked
variable "automatic_failover_enabled" {
default = true
}
//checked
variable "multi_az_enabled" {
default = true
}
variable "alarm_memory_threshold" {
# 10MB
default = "10000000"
}
variable "alarm_cpu_threshold" {
default = "75"
}
//checked
variable "desired_clusters" {
default = "3"
}
//checked
variable "instance_type" {
default = "cache.t2.micro"
}
//checked
variable "engine_version" {
default = "5.0.6"
}
//checked
variable "maintenance_window" {
default = "sun:02:30-sun:03:30"
}
//checked
variable "at_rest_encryption_enabled" {
type = bool
default = true
description = "Enable encryption at rest"
}
//checked
variable "transit_encryption_enabled" {
type = bool
default = true
description = <<-EOT
Set `true` to enable encryption in transit. Forced `true` if `var.auth_token` is set.
If this is enabled, use the [following guide](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#connect-tls) to access redis.
EOT
}
//checked
variable "sns_topic_name" {
type = string
default = "Unknown"
}
Chúng ta tạo security Group để các Instance khác connect vào redis
#
# Security group resources
#
resource "aws_security_group" "redis" {
vpc_id = module.vpc.vpc_id
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
#https://stackoverflow.com/questions/43980946/define-tags-in-central-section-in-terraform
tags = merge(
local.common_tags,
tomap({
"Name" = "sgCacheCluster" ##look into
})
)
# the "map" function was deprecated in Terraform v0.12
# tags = merge(
# local.common_tags,
# map(
# "Name", "sgCacheCluster",
# "Project", var.project,
# )
# )
lifecycle {
create_before_destroy = true
}
}
Tiếp đến là Redis
>>>>>>>>>>>>>>>>
>>>>
c2-03-redis.tf
>>>>>
resource "aws_sns_topic" "redis" {
name = var.sns_topic_name
}
# #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_parameter_group
resource "aws_elasticache_parameter_group" "redis" {
name = "cache-params"
family = var.family
parameter {
name = "activerehashing"
value = "yes"
}
parameter {
name = "notify-keyspace-events"
value = "KEA"
}
}
# #
# # ElastiCache resources
# #
resource "aws_elasticache_replication_group" "redis" {
replication_group_id = lower(var.cache_identifier)
description = "${var.env}-nimtechnology"
automatic_failover_enabled = var.automatic_failover_enabled
multi_az_enabled = var.multi_az_enabled
#availability_zones = var.availability_zones == [] ? null : var.availability_zones
# preferred_cache_cluster_azs = module.vpc.azs
num_cache_clusters = var.desired_clusters
node_type = var.instance_type
engine_version = var.engine_version
parameter_group_name = aws_elasticache_parameter_group.redis.name
subnet_group_name = module.vpc.elasticache_subnet_group_name
security_group_ids = [aws_security_group.redis.id]
maintenance_window = var.maintenance_window
notification_topic_arn = aws_sns_topic.redis.arn
port = "6379"
# cluster_mode {
# replicas_per_node_group = 1
# num_node_groups = 2
# }
at_rest_encryption_enabled = var.at_rest_encryption_enabled
transit_encryption_enabled = var.transit_encryption_enabled
tags = merge(
local.common_tags,
tomap({
"Name" = "CacheReplicationGroup"
})
)
}
#
# CloudWatch resources
#
resource "aws_cloudwatch_metric_alarm" "cache_cpu" {
count = var.desired_clusters
alarm_name = "alarm${var.env}CacheCluster00${count.index + 1}CPUUtilization"
alarm_description = "Redis cluster CPU utilization"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "CPUUtilization"
namespace = "AWS/ElastiCache"
period = "300"
statistic = "Average"
threshold = var.alarm_cpu_threshold
dimensions = {
CacheClusterId = "${aws_elasticache_replication_group.redis.id}-00${count.index + 1}"
}
alarm_actions = [aws_sns_topic.redis.arn]
}
resource "aws_cloudwatch_metric_alarm" "cache_memory" {
count = var.desired_clusters
alarm_name = "alarm${var.env}CacheCluster00${count.index + 1}FreeableMemory"
alarm_description = "Redis cluster freeable memory"
comparison_operator = "LessThanThreshold"
evaluation_periods = "1"
metric_name = "FreeableMemory"
namespace = "AWS/ElastiCache"
period = "60"
statistic = "Average"
threshold = var.alarm_memory_threshold
dimensions = {
CacheClusterId = "${aws_elasticache_replication_group.redis.id}-00${count.index + 1}"
}
alarm_actions = [aws_sns_topic.redis.arn]
}
Và sau đây là 1 số hình ảnh trên was


4) Using module terraform to deploy Redis cluster on AWS
Hiện tại mình đang có public 1 module để create redis cluster.
https://registry.terraform.io/modules/mrnim94/elasticache/aws/latest
Pay attention to…
Để tạo được elasticache thì bạn cần tạo 1 thứ là Subnet Group trên Elasticache
Tại sao mình nói vậy?
Nhìn ảnh bên dưới tab Network and Security.

Chúng ta sẽ thấy ở left menu có Subnet Group có thấy subnet

Do chúng ta hay sử dụng terraform có khi chúng ta ko để ý:
Create ElastiCache Subnet Group by VPC Module.

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
#version = "3.11.0"
version = "~> 3.11"
#Elasticache Subnets
elasticache_subnets = var.vpc_elasticache_subnets
create_elasticache_subnet_group = var.vpc_create_elasticache_subnet_group
create_elasticache_subnet_route_table = var.vpc_create_elasticache_subnet_route_table
# create_elasticache_internet_gateway_route = true
# create_elasticache_nat_gateway_route = true
elasticache_subnet_tags = {
Type = "database-subnets"
}
}
Point ElastiCache Subnet Group base on the existed subnet.

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
#version = "3.11.0"
version = "~> 3.11"
# VPC Basic Details
name = local.redis_cluster_name
cidr = var.vpc_cidr_block
azs = data.aws_availability_zones.available.names
public_subnets = var.vpc_public_subnets
private_subnets = var.vpc_private_subnets
Bạn tạo ElastiCache Subnet Group
resource "aws_elasticache_subnet_group" "redis" {
name = "subnet-group-redis"
subnet_ids = module.vpc.private_subnets
}
Bạn khai báo trong aws_elasticache_replication_group
