Skip to content

Commit

Permalink
Merge pull request #5 from clientIO/module-fix
Browse files Browse the repository at this point in the history
Module fix
  • Loading branch information
Riqardos authored Feb 2, 2024
2 parents c4d2cfd + d918070 commit 3f3b67c
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 25 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,22 @@ Admin user is initialized through automated task running in ECS. Variable `init_


## Examples
See [Development example](examples/development/README.md) for further information. (Minimal setup)
See [Production example](examples/production/README.md) for further information. (High available setup)
- See [Development example](examples/development/README.md) for further information. (Minimal setup)
- See [Production example](examples/production/README.md) for further information. (High available setup)

## Pricing
[AWS Pricing estimation](https://calculator.aws/#/estimate?id=255bd4b7f28f0aadd6dcc8e746b475ea18fd2779) for each environemnt.
Pricing can vary based on real traffic.

- Development ~ 450$/month
- Production ~ 900$/month

## Simple VPN
You can use [sshuttle](https://github.com/sshuttle/sshuttle) to connect to private VPC network.
1. Run EC2 with configured SSH keys in your public subnet
2. Install `sshuttle`
3. Connect through `sshuttle` to your running EC2 (`sshuttle -r <SSH_CONFIG> 0.0.0.0/0 -vv`)
4. Your network traffic should be routed through EC2, you should be able to see managed AWS services running in private subnets.


## Architecture
Expand Down Expand Up @@ -122,7 +136,7 @@ See [Production example](examples/production/README.md) for further information.
| <a name="input_alb_ingress_security_group_rules"></a> [alb\_ingress\_security\_group\_rules](#input\_alb\_ingress\_security\_group\_rules) | Application Load Balancer security group ingress rules | <pre>map(object({<br> ip_protocol = string<br> from_port = optional(number)<br> to_port = optional(number)<br> referenced_security_group_id = optional(string)<br> description = optional(string)<br> cidr_ipv4 = optional(string)<br> cidr_ipv6 = optional(string)<br> }))</pre> | <pre>{<br> "all_http": {<br> "cidr_ipv4": "0.0.0.0/0",<br> "from_port": 80,<br> "ip_protocol": "tcp",<br> "to_port": 80<br> },<br> "all_https": {<br> "cidr_ipv4": "0.0.0.0/0",<br> "from_port": 443,<br> "ip_protocol": "tcp",<br> "to_port": 443<br> }<br>}</pre> | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no |
| <a name="input_availability_zones"></a> [availability\_zones](#input\_availability\_zones) | List of availability zones | `list(string)` | <pre>[<br> "eu-central-1a",<br> "eu-central-1b",<br> "eu-central-1c"<br>]</pre> | no |
| <a name="input_certificate_arn"></a> [certificate\_arn](#input\_certificate\_arn) | Certificate ARN, if not set, certificate will be automatically created using '*.<root\_dns\_name>', `zone_id` must be set | `string` | `null` | no |
| <a name="input_certificate_arn"></a> [certificate\_arn](#input\_certificate\_arn) | Certificate ARN, if not set, certificate will be automatically created using '*.<root\_dns\_name>' | `string` | `null` | no |
| <a name="input_document_db"></a> [document\_db](#input\_document\_db) | DocumentDB configuration object | <pre>object({<br> cluster_size = optional(number, 1)<br> cluster_family = optional(string, "docdb5.0")<br> instance_class = optional(string, "db.t4g.medium")<br> engine_version = optional(string, "5.0.0")<br> cluster_parameters = optional(list(object({<br> apply_method = string<br> name = string<br> value = string<br> })), [])<br> })</pre> | `{}` | no |
| <a name="input_ecs_autoscaling_config"></a> [ecs\_autoscaling\_config](#input\_ecs\_autoscaling\_config) | n/a | `any` | <pre>{<br> "on_demand": {<br> "capacity_provider": {<br> "default_capacity_provider_strategy": {<br> "base": 1,<br> "weight": 10<br> },<br> "maximum_scaling_step_size": 5,<br> "minimum_scaling_step_size": 1,<br> "target_capacity": 100<br> },<br> "instance_type": "m5.large",<br> "max_size": 6,<br> "min_size": 1,<br> "mixed_instances_policy": {<br> "instances_distribution": {<br> "on_demand_allocation_strategy": "prioritized",<br> "on_demand_base_capacity": 1,<br> "on_demand_percentage_above_base_capacity": 100,<br> "spot_allocation_strategy": "lowest-price"<br> },<br> "override": [<br> {<br> "instance_type": "m5.large",<br> "weighted_capacity": "1"<br> },<br> {<br> "instance_type": "c5.large",<br> "weighted_capacity": "1"<br> }<br> ]<br> },<br> "use_mixed_instances_policy": true<br> },<br> "spot": {<br> "capacity_provider": {<br> "default_capacity_provider_strategy": {<br> "base": 0,<br> "weight": 80<br> },<br> "maximum_scaling_step_size": 5,<br> "minimum_scaling_step_size": 1,<br> "target_capacity": 100<br> },<br> "instance_type": "m5.large",<br> "max_size": 6,<br> "min_size": 1,<br> "mixed_instances_policy": {<br> "instances_distribution": {<br> "on_demand_allocation_strategy": "prioritized",<br> "on_demand_base_capacity": 0,<br> "on_demand_percentage_above_base_capacity": 0,<br> "spot_allocation_strategy": "lowest-price"<br> },<br> "override": [<br> {<br> "instance_type": "m5.large",<br> "weighted_capacity": "1"<br> },<br> {<br> "instance_type": "c5.large",<br> "weighted_capacity": "1"<br> }<br> ]<br> },<br> "use_mixed_instances_policy": true<br> }<br>}</pre> | no |
| <a name="input_ecs_cluster_config"></a> [ecs\_cluster\_config](#input\_ecs\_cluster\_config) | Cluster configuration object `execute_command_configuration`, see more [terraform docs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | `any` | <pre>{<br> "log_configuration": {<br> "cloud_watch_log_group_name": "/aws/ecs/aws-ec2"<br> },<br> "logging": "OVERRIDE"<br>}</pre> | no |
Expand All @@ -146,7 +160,7 @@ See [Production example](examples/production/README.md) for further information.
| <a name="input_stage"></a> [stage](#input\_stage) | Stage, e.g. 'prod', 'staging', 'dev' | `string` | `""` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no |
| <a name="input_vpc_config"></a> [vpc\_config](#input\_vpc\_config) | VPC configuration, ignored if `external_vpc` is set | <pre>object({<br> ipv4_primary_cidr_block = string<br> availability_zones = list(string)<br> })</pre> | <pre>{<br> "availability_zones": [<br> "eu-central-1a",<br> "eu-central-1b",<br> "eu-central-1c"<br> ],<br> "ipv4_primary_cidr_block": "10.0.0.0/16"<br>}</pre> | no |
| <a name="input_zone_id"></a> [zone\_id](#input\_zone\_id) | Route53 DNS zone ID, if not set AWS route53 will be not used | `string` | `""` | no |
| <a name="input_zone_id"></a> [zone\_id](#input\_zone\_id) | Route53 DNS zone ID, if not set AWS route53 will be not used | `string` | `null` | no |

## Outputs

Expand Down
2 changes: 1 addition & 1 deletion ecs-ec2.tf
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ locals {
ECS_ENABLE_HIGH_DENSITY_ENI=true
ECS_ENABLE_SPOT_INSTANCE_DRAINING=true
ECS_ENGINE_AUTH_TYPE=dockercfg
ECS_ENGINE_AUTH_DATA=${sensitive(base64decode(var.ecs_registry_auth_data))} # pragma: allowlist secret
ECS_ENGINE_AUTH_DATA=${sensitive(try(base64decode(var.ecs_registry_auth_data), ""))} # pragma: allowlist secret
EOF
EOT
}
Expand Down
37 changes: 28 additions & 9 deletions examples/development/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,7 @@ module "appmixer_module" {

enable_deletion_protection = false

elasticache = {
parameter = [
{
name = "notify-keyspace-events"
value = "lK"
}
]
}

ecs_autoscaling_config = {
on_demand = {
instance_type = "m5.large"
Expand Down Expand Up @@ -151,9 +144,35 @@ module "appmixer_module" {
ecs_per_service_config = {
engine = {
entrypoint = ["/bin/bash", "-c"]
command = ["apt-get update; apt-get install wget; wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem; node gridd.js --http --emails"]
command = ["apt-get update; apt-get -y install wget; wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem; node gridd.js --http --emails"]
}
quota = {
entrypoint = ["/bin/bash", "-c"]
command = ["apt-get update; apt-get -y install wget; wget -O /root//global-bundle.pem https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem; npm start"]
}
}

elasticsearch = {
instance_count = 1
}

elasticache = {
cluster_size = 1
parameter = [
{
name = "notify-keyspace-events"
value = "lK"
}
]
}

document_db = {
cluster_size = 1
}

rabbitmq = {
deployment_mode = "SINGLE_INSTANCE"
}
}

output "appmixer_module" {
Expand Down
12 changes: 12 additions & 0 deletions examples/development/providers.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# Good practice is to use s3 bucket to save the state and dynamodb table as lock to restrict access to the state
# For example:
#
# terraform {
# backend "s3" {
# bucket = "appmixer-terraform-state"
# key = "appmixer/terraform.tfstate"
# region = "eu-central-1"
# }
# }


provider "aws" {
region = "eu-central-1"
}
4 changes: 3 additions & 1 deletion examples/production/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ The code in this example shows how to use the module with production configurati

## Resources

No resources.
| Name | Type |
|------|------|
| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |

## Inputs

Expand Down
16 changes: 13 additions & 3 deletions examples/production/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ locals {
availability_zones = ["eu-central-1a", "eu-central-1b", "eu-central-1c"]
}

data "aws_route53_zone" "this" {
name = "appmixer.co"
}

module "appmixer_module" {
source = "../../"

name = local.name
namespace = local.namespace
environment = local.environment

root_dns_name = "ecs.appmixer.co"
zone_id = "XXX"
root_dns_name = "ecs-prod.appmixer.co"
zone_id = data.aws_route53_zone.this.zone_id

vpc_config = {
ipv4_primary_cidr_block = "10.0.0.0/16"
Expand Down Expand Up @@ -117,12 +121,18 @@ module "appmixer_module" {
}

elasticache = {
cluster_size = length(local.availability_zones)
cluster_size = 2
instance_type = "cache.t3.medium"
}

document_db = {
cluster_size = length(local.availability_zones)
}

rabbitmq = {
deployment_mode = "CLUSTER_MULTI_AZ"
host_instance_type = "mq.m5.large"
}


}
12 changes: 12 additions & 0 deletions examples/production/providers.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# Good practice is to use s3 bucket to save the state and dynamodb table as lock to restrict access to the state
# For example:
#
# terraform {
# backend "s3" {
# bucket = "appmixer-terraform-state"
# key = "appmixer/terraform.tfstate"
# region = "eu-central-1"
# }
# }


provider "aws" {
region = "eu-central-1"
}
10 changes: 7 additions & 3 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ locals {
password = random_password.elasticsearch_password.result
}

documentdb = var.external_documentdb != null ? var.external_documentdb : "mongodb://${module.documentdb_cluster.master_username}:${module.documentdb_cluster.master_password}@${module.documentdb_cluster.endpoint}:27017/appmixer?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
documentdb = var.external_documentdb != null ? var.external_documentdb : "mongodb://${module.documentdb_cluster.master_username}:${module.documentdb_cluster.master_password}@${module.documentdb_cluster.endpoint}:27017/appmixer?replicaSet=rs0&readPreference=primaryPreferred&retryWrites=false"

## Services default configuration

Expand Down Expand Up @@ -105,8 +105,12 @@ locals {

# Quota service configuration
quota = {
image = "registry.appmixer.com/appmixer-quota:5.2.0"
env = {}
image = "registry.appmixer.com/appmixer-quota:5.2.0"
env = {
DB_TLS_CA_FILE = "/root/global-bundle.pem"
DB_USE_TLS = "true"
DB_SSL_VALIDATE = "true"
}
cpu = 256
memory = 512
}
Expand Down
4 changes: 2 additions & 2 deletions route53.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ resource "aws_acm_certificate" "alb" {

resource "aws_route53_record" "cert_alb" {
for_each = {
for dvo in aws_acm_certificate.alb[0].domain_validation_options : dvo.domain_name => {
for dvo in local.acm_certificate_enabled ? aws_acm_certificate.alb[0].domain_validation_options : [] : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
} if local.acm_certificate_enabled
}
}

allow_overwrite = true
Expand Down
4 changes: 2 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ variable "availability_zones" {

variable "zone_id" {
type = string
default = ""
default = null
description = "Route53 DNS zone ID, if not set AWS route53 will be not used"
}

Expand All @@ -54,7 +54,7 @@ variable "root_dns_name" {
variable "certificate_arn" {
type = string
default = null
description = "Certificate ARN, if not set, certificate will be automatically created using '*.<root_dns_name>', `zone_id` must be set"
description = "Certificate ARN, if not set, certificate will be automatically created using '*.<root_dns_name>'"
}

variable "document_db" {
Expand Down

0 comments on commit 3f3b67c

Please sign in to comment.