Skip to content

Commit

Permalink
enable redis-sentinel
Browse files Browse the repository at this point in the history
  • Loading branch information
sandrampeter committed Dec 10, 2024
1 parent 3d8b942 commit d1d5df7
Show file tree
Hide file tree
Showing 12 changed files with 586 additions and 2 deletions.
11 changes: 10 additions & 1 deletion locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ locals {
}
)

redis = try(
redis = var.enable_redis_sentinel ? try(
module.redis_sentinel[0],
{
hostname = null
password = null
redis_port = null
use_password_auth = null
use_tls = null
}
) : try(
module.redis[0],
{
hostname = null
Expand Down
26 changes: 25 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module "networking" {
# -----------------------------------------------------------------------------
module "redis" {
source = "./modules/redis"
count = local.enable_redis_module ? 1 : 0
count = local.enable_redis_module && var.enable_redis_sentinel == false ? 1 : 0

active_active = var.operational_mode == "active-active"
friendly_name_prefix = var.friendly_name_prefix
Expand All @@ -91,6 +91,30 @@ module "redis" {
redis_port = var.redis_encryption_in_transit ? "6380" : "6379"
}

# -----------------------------------------------------------------------------
# Redis Sentinel
# -----------------------------------------------------------------------------

module "redis_sentinel" {
count = var.enable_redis_sentinel ? 1 : 0
source = "./modules/redis-sentinel"

domain_name = var.domain_name
tfe_instance_sg = module.vm.tfe_instance_sg

aws_iam_instance_profile = module.service_accounts.iam_instance_profile.name
asg_tags = var.asg_tags
ec2_launch_template_tag_specifications = var.ec2_launch_template_tag_specifications
friendly_name_prefix = var.friendly_name_prefix
health_check_grace_period = var.health_check_grace_period
health_check_type = var.health_check_type
instance_type = var.instance_type
key_name = var.key_name
network_id = local.network_id
network_subnets_private = local.network_private_subnets
network_private_subnet_cidrs = local.network_private_subnet_cidrs
}

# -----------------------------------------------------------------------------
# AWS PostreSQL Database
# -----------------------------------------------------------------------------
Expand Down
79 changes: 79 additions & 0 deletions modules/redis-sentinel/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Description: This file contains the docker-compose configuration for the redis-sentinel module.
services:
redis-leader:
container_name: redis-leader
command: "redis-server --appendonly yes --requirepass ${redis_sentinel_password}"
image: redis:7
ports :
- ${redis_port}:${redis_port}
redis-follower-1:
container_name: redis-follower-1
depends_on:
- redis-leader
command: "redis-server --replicaof redis-leader ${redis_port} --requirepass ${redis_password} --masterauth ${redis_sentinel_password}"
image: redis:7
ports :
- 6380:${redis_port}
redis-follower-2:
container_name: redis-follower-2
depends_on:
- redis-leader
command: "redis-server --replicaof redis-leader ${redis_port} --requirepass ${redis_password} --masterauth ${redis_sentinel_password}"
image: redis:7
ports :
- 6381:${redis_port}
redis-sentinel-1:
container_name: redis-sentinel-1
depends_on:
- redis-leader
- redis-follower-1
- redis-follower-2
command: >
sh -c 'echo "sentinel resolve-hostnames yes" > /etc/sentinel.conf &&
echo "sentinel monitor ${redis_sentinel_leader_name} redis-leader 6379 2" >> /etc/sentinel.conf &&
echo "sentinel auth-pass ${redis_sentinel_leader_name} ${redis_sentinel_password}" >> /etc/sentinel.conf &&
echo "sentinel down-after-milliseconds ${redis_sentinel_leader_name} 5000" >> /etc/sentinel.conf &&
echo "sentinel failover-timeout ${redis_sentinel_leader_name} 10000" >> /etc/sentinel.conf &&
echo "loglevel notice" >> /etc/sentinel.conf &&
echo "sentinel deny-scripts-reconfig yes" >> /etc/sentinel.conf &&
redis-sentinel /etc/sentinel.conf'
image: redis:7
ports:
- ${redis_sentinel_port}:${redis_sentinel_port}
redis-sentine-2:
container_name: redis-sentinel-2
depends_on:
- redis-leader
- redis-follower-1
- redis-follower-2
command: >
sh -c 'echo "sentinel resolve-hostnames yes" > /etc/sentinel.conf &&
echo "sentinel monitor ${redis_sentinel_leader_name} redis-leader 6379 2" >> /etc/sentinel.conf &&
echo "sentinel auth-pass ${redis_sentinel_leader_name} ${redis_sentinel_password}" >> /etc/sentinel.conf &&
echo "sentinel down-after-milliseconds ${redis_sentinel_leader_name} 5000" >> /etc/sentinel.conf &&
echo "sentinel failover-timeout ${redis_sentinel_leader_name} 10000" >> /etc/sentinel.conf &&
echo "loglevel notice" >> /etc/sentinel.conf &&
echo "sentinel deny-scripts-reconfig yes" >> /etc/sentinel.conf &&
redis-sentinel /etc/sentinel.conf'
image: redis:7
ports:
- 26380:${redis_sentinel_port}
redis-sentinel-3:
container_name: redis-sentinel-3
depends_on:
- redis-leader
- redis-follower-1
- redis-follower-2
command: >
sh -c 'echo "sentinel resolve-hostnames yes" > /etc/sentinel.conf &&
echo "sentinel monitor ${redis_sentinel_leader_name} redis-leader 6379 2" >> /etc/sentinel.conf &&
echo "sentinel auth-pass ${redis_sentinel_leader_name} ${redis_sentinel_password}" >> /etc/sentinel.conf &&
echo "sentinel down-after-milliseconds ${redis_sentinel_leader_name} 5000" >> /etc/sentinel.conf &&
echo "sentinel failover-timeout ${redis_sentinel_leader_name} 10000" >> /etc/sentinel.conf &&
echo "loglevel notice" >> /etc/sentinel.conf &&
echo "sentinel deny-scripts-reconfig yes" >> /etc/sentinel.conf &&
redis-sentinel /etc/sentinel.conf'
image: redis:7
ports:
- 26381:${redis_sentinel_port}

50 changes: 50 additions & 0 deletions modules/redis-sentinel/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

locals {
redis_user_data_template = "${path.module}/script.sh"
redis_leader_user_data = templatefile(local.redis_user_data_template, {

compose = base64encode(templatefile(local.compose_path, {
redis_sentinel_password = var.redis_sentinel_password
redis_sentinel_leader_name = var.redis_sentinel_leader_name
redis_sentinel_port = var.redis_sentinel_port
redis_port = var.redis_port
redis_password = var.redis_password
}))})
compose_path = "${path.module}/compose.yaml"
tags = concat(
[
{
key = "Name"
value = "${var.friendly_name_prefix}-tfe"
propagate_at_launch = true
},
],
[
for k, v in var.asg_tags : {
key = k
value = v
propagate_at_launch = true
}
]
)
default_health_check_grace_period = 1500
health_check_grace_period = var.health_check_grace_period != null ? var.health_check_grace_period : local.default_health_check_grace_period
}

data "aws_ami" "ubuntu" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

owners = ["099720109477"] # Canonical
}
75 changes: 75 additions & 0 deletions modules/redis-sentinel/networking.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
## DNS Record for Redis Sentinel cluster Load Balancer
# ----------------------------------------------------
data "aws_route53_zone" "tfe" {
name = var.domain_name
private_zone = false
}

resource "aws_route53_record" "sentinel" {
zone_id = data.aws_route53_zone.tfe.zone_id
name = "${var.friendly_name_prefix}-redis-sentinel"
type = "A"

alias {
name = aws_lb.redis_sentinel_lb.dns_name
zone_id = aws_lb.redis_sentinel_lb.zone_id
evaluate_target_health = true
}
}

# Network Load Balancer for Redis Sentinel cluster
# ------------------------------------------------

resource "aws_lb" "redis_sentinel_lb" {
name = "${var.friendly_name_prefix}-redis-sentinel-nlb"
internal = true
load_balancer_type = "network"
subnets = var.network_subnets_private
}

# Network Load Balancer Listener and Target Group for Redis and Sentinel
# ----------------------------------------------------------------------

resource "aws_lb_listener" "redis_sentinel_listener_6379" {
load_balancer_arn = aws_lb.redis_sentinel_lb.arn
port = 6379
protocol = "TCP"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.redis_sentinel_tg_6379.arn
}
}

resource "aws_lb_target_group" "redis_sentinel_tg_6379" {
name = "${var.friendly_name_prefix}-redis-sentinel-tg-6379"
port = 6379
protocol = "TCP"
vpc_id = var.network_id

health_check {
protocol = "TCP"
}
}

resource "aws_lb_listener" "redis_sentinel_listener_26379" {
load_balancer_arn = aws_lb.redis_sentinel_lb.arn
port = 26379
protocol = "TCP"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.redis_sentinel_tg_26379.arn
}
}

resource "aws_lb_target_group" "redis_sentinel_tg_26379" {
name = "${var.friendly_name_prefix}-redis-sentinel-tg-26379"
port = 26379
protocol = "TCP"
vpc_id = var.network_id

health_check {
protocol = "TCP"
}
}
32 changes: 32 additions & 0 deletions modules/redis-sentinel/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
output "hostname" {
value = aws_route53_record.sentinel.fqdn
}

output "redis_port" {
value = var.redis_port
}

output "redis_sentinel_port" {
value = var.redis_sentinel_port
}

output "redis_sentinel_leader_name" {
value = var.redis_sentinel_leader_name
}

output "redis_sentinel_password" {
value = var.redis_sentinel_password
}

output "password" {
value = var.redis_password
}

output "use_password_auth" {
value = var.redis_use_password_auth ? true : false
description = "A boolean which indicates if password authentication is required by the Redis"
}

output "use_tls" {
value = var.use_tls ? true : false
}
18 changes: 18 additions & 0 deletions modules/redis-sentinel/script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eu pipefail

curl --noproxy '*' --fail --silent --show-error --location https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor --output /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release --codename --short) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get --assume-yes update
apt-get --assume-yes install docker-ce docker-ce-cli containerd.io
apt-get --assume-yes autoremove

tfe_dir="/etc/redis"
mkdir -p $tfe_dir

echo ${compose} | base64 -d > $tfe_dir/compose.yaml
docker compose -f $tfe_dir/compose.yaml up -d
61 changes: 61 additions & 0 deletions modules/redis-sentinel/security-group.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Allow inbound from Redis Sentinel instances to TFE VPC

resource "aws_security_group" "redis_sentinel_inbound_allow" {
name = "${var.friendly_name_prefix}-redis-sentinel-inbound-allow"
vpc_id = var.network_id
}

resource "aws_security_group_rule" "redis_sentinel_leader" {
security_group_id = aws_security_group.redis_sentinel_inbound_allow.id
type = "ingress"
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = var.network_private_subnet_cidrs
}

resource "aws_security_group_rule" "redis_sentinel" {
security_group_id = aws_security_group.redis_sentinel_inbound_allow.id
type = "ingress"
from_port = 26379
to_port = 26379
protocol = "tcp"
cidr_blocks = var.network_private_subnet_cidrs
}

resource "aws_security_group_rule" "ssh_inbound" {

security_group_id = aws_security_group.redis_sentinel_inbound_allow.id
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.network_private_subnet_cidrs
}

resource "aws_security_group_rule" "redis_sentinel_inbound" {
security_group_id = aws_security_group.redis_sentinel_inbound_allow.id
type = "ingress"
from_port = 0
to_port = 0
protocol = "-1"
self = true
}

# Allow all traffic outbound from Redis Sentinel instances to www

resource "aws_security_group" "redis_sentinel_outbound_allow" {
name = "${var.friendly_name_prefix}-redis-sentinel-outbound-allow"
vpc_id = var.network_id
}

resource "aws_security_group_rule" "redis_sentinel_outbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all traffic outbound from Redis Sentinel instances to TFE"

security_group_id = aws_security_group.redis_sentinel_outbound_allow.id
}
Loading

0 comments on commit d1d5df7

Please sign in to comment.