founders_template 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile-rails6.lock +1 -1
  3. data/lib/founders_template/cli.rb +35 -4
  4. data/lib/founders_template/config_file.rb +11 -2
  5. data/lib/founders_template/version.rb +1 -1
  6. data/templates/Dockerfile.erb +68 -0
  7. data/templates/docker/nginx/nginx.conf +78 -0
  8. data/templates/docker-compose.yml.erb +75 -0
  9. data/templates/terraform/modules/application/main.tf +70 -0
  10. data/templates/terraform/modules/application/one_off_service.tf +48 -0
  11. data/templates/terraform/modules/application/outputs.tf +19 -0
  12. data/templates/terraform/modules/application/policies/ecs_execution.json +17 -0
  13. data/templates/terraform/modules/application/policies/ecs_execution_role.json +21 -0
  14. data/templates/terraform/modules/application/policies/ecs_task_execution.json +17 -0
  15. data/templates/terraform/modules/application/sshable.tf +17 -0
  16. data/templates/terraform/modules/application/task_definitions/one_off.json +18 -0
  17. data/templates/terraform/modules/application/task_definitions/web.json +41 -0
  18. data/templates/terraform/modules/application/task_definitions/worker.json +49 -0
  19. data/templates/terraform/modules/application/variables.tf +109 -0
  20. data/templates/terraform/modules/application/web_service.tf +62 -0
  21. data/templates/terraform/modules/application/worker_service.tf +48 -0
  22. data/templates/terraform/production/domains.tf +19 -0
  23. data/templates/terraform/production/main.tf +167 -0
  24. data/templates/terraform/production/ssl.tf +28 -0
  25. data/templates/terraform/production/variables.tf +36 -0
  26. data/templates/terraform/shared/main.tf +41 -0
  27. data/templates/terraform/shared/terraform.tfstate.backup +129 -0
  28. data/templates/terraform-production.tfvars.erb +4 -0
  29. data/templates/terraform-shared.tfvars.erb +1 -0
  30. metadata +26 -2
@@ -0,0 +1,109 @@
1
+ variable "name" {
2
+ description = "The name to use for resources"
3
+ type = string
4
+ }
5
+
6
+ variable "app_environment" {
7
+ description = "Environment variables to set on the application container"
8
+ default = []
9
+
10
+ type = list(object({
11
+ name = string,
12
+ value = string
13
+ }))
14
+ }
15
+
16
+ variable "worker_environment" {
17
+ description = "Environment variables to set on the worker container"
18
+ default = []
19
+
20
+ type = list(object({
21
+ name = string,
22
+ value = string
23
+ }))
24
+ }
25
+
26
+ variable "app_repository_url" {
27
+ description = "The URL to the image repository for the application container"
28
+ type = string
29
+ }
30
+
31
+ variable "web_repository_url" {
32
+ description = "The URL to the image repository for the web container"
33
+ type = string
34
+ }
35
+
36
+ variable "aws_region" {
37
+ description = "The AWS region to launch resources in"
38
+ type = string
39
+ default = "us-east-1"
40
+ }
41
+
42
+ variable "app_process_memory" {
43
+ description = "The amount of memory to allocate to the application process"
44
+ type = number
45
+ default = 768
46
+ }
47
+
48
+ variable "app_task_cpu" {
49
+ description = "The CPU units to allocate to the application task"
50
+ type = number
51
+ default = 256
52
+ }
53
+
54
+ variable "app_task_memory" {
55
+ description = "The memory to allocate to the application task"
56
+ type = number
57
+ default = 1024
58
+ }
59
+
60
+ variable "app_task_count" {
61
+ description = "The number of application tasks to run"
62
+ type = number
63
+ default = 1
64
+ }
65
+
66
+ variable "worker_task_cpu" {
67
+ description = "The CPU units to allocate to the worker task"
68
+ type = number
69
+ default = 256
70
+ }
71
+
72
+ variable "worker_task_memory" {
73
+ description = "The memory to allocate to the worker task"
74
+ type = number
75
+ default = 1024
76
+ }
77
+
78
+ variable "worker_task_count" {
79
+ description = "The number of worker tasks to run"
80
+ type = number
81
+ default = 1
82
+ }
83
+
84
+ variable "task_subnets" {
85
+ description = "The subnets to launch tasks in"
86
+ type = list
87
+ }
88
+
89
+ variable "vpc_id" {
90
+ description = "The VPC ID to launch things in"
91
+ type = string
92
+ }
93
+
94
+ variable "alb_listener" {
95
+ description = "The ALB Listener to use in the load balancer configuration"
96
+ }
97
+
98
+ variable "alb_target_group" {
99
+ description = "The ALB Target Group to use in the load balancer configuration"
100
+ }
101
+
102
+ variable "load_balance_security_group" {
103
+ description = "The Security group for the ALB"
104
+ }
105
+
106
+ variable "key_pair_public_key" {
107
+ description = "The public key for the EC2 Key Pair to use when running remote_console"
108
+ type = string
109
+ }
@@ -0,0 +1,62 @@
1
+ # WEB
2
+ resource "aws_cloudwatch_log_group" "web" {
3
+ name = "/ecs/service/${var.name}-web"
4
+ retention_in_days = "14"
5
+ }
6
+
7
+ resource "aws_cloudwatch_log_group" "app" {
8
+ name = "/ecs/service/${var.name}-app"
9
+ retention_in_days = "14"
10
+ }
11
+
12
+ data "template_file" "web_task_definition" {
13
+ template = file("${path.module}/task_definitions/web.json")
14
+
15
+ vars = {
16
+ app_log_path = aws_cloudwatch_log_group.app.name
17
+ web_log_path = aws_cloudwatch_log_group.web.name
18
+ app_image = "${var.app_repository_url}:latest"
19
+ web_image = "${var.web_repository_url}:latest"
20
+ environment = jsonencode(var.app_environment)
21
+ app_memory = var.app_process_memory
22
+ region = var.aws_region
23
+ }
24
+ }
25
+
26
+ resource "aws_ecs_task_definition" "web" {
27
+ family = "${var.name}-web"
28
+ network_mode = "awsvpc"
29
+ requires_compatibilities = ["FARGATE"]
30
+ cpu = var.app_task_cpu
31
+ memory = var.app_task_memory
32
+ execution_role_arn = aws_iam_role.ecs_execution_role.arn
33
+ task_role_arn = aws_iam_role.ecs_task_execution_role.arn
34
+
35
+ container_definitions = data.template_file.web_task_definition.rendered
36
+ }
37
+
38
+ resource "aws_ecs_service" "web" {
39
+ name = "${var.name}-web"
40
+ cluster = aws_ecs_cluster.main.id
41
+ task_definition = aws_ecs_task_definition.web.arn
42
+ desired_count = var.app_task_count
43
+ launch_type = "FARGATE"
44
+
45
+ network_configuration {
46
+ security_groups = [aws_security_group.ecs_tasks.id]
47
+ subnets = var.task_subnets
48
+ }
49
+
50
+ load_balancer {
51
+ target_group_arn = var.alb_target_group.id
52
+ container_name = "web"
53
+ container_port = "80"
54
+ }
55
+
56
+ depends_on = [var.alb_listener]
57
+
58
+ lifecycle {
59
+ create_before_destroy = true
60
+ ignore_changes = [task_definition]
61
+ }
62
+ }
@@ -0,0 +1,48 @@
1
+ # WORKER
2
+ resource "aws_cloudwatch_log_group" "worker" {
3
+ name = "/ecs/service/${var.name}-worker"
4
+ retention_in_days = "14"
5
+ }
6
+
7
+ data "template_file" "worker_task_definition" {
8
+ template = file("${path.module}/task_definitions/worker.json")
9
+
10
+ vars = {
11
+ app_log_path = aws_cloudwatch_log_group.worker.name
12
+ app_image = "${var.app_repository_url}:latest"
13
+ app_memory = var.app_process_memory
14
+ region = var.aws_region
15
+ worker_app_memory = var.worker_task_memory
16
+ environment = jsonencode(var.worker_environment)
17
+ }
18
+ }
19
+
20
+ resource "aws_ecs_task_definition" "worker" {
21
+ family = "${var.name}-worker"
22
+ network_mode = "awsvpc"
23
+ requires_compatibilities = ["FARGATE"]
24
+ cpu = var.worker_task_cpu
25
+ memory = var.worker_task_memory
26
+ execution_role_arn = aws_iam_role.ecs_execution_role.arn
27
+ task_role_arn = aws_iam_role.ecs_task_execution_role.arn
28
+
29
+ container_definitions = data.template_file.worker_task_definition.rendered
30
+ }
31
+
32
+ resource "aws_ecs_service" "worker" {
33
+ name = "${var.name}-worker"
34
+ cluster = aws_ecs_cluster.main.id
35
+ task_definition = aws_ecs_task_definition.worker.arn
36
+ desired_count = var.worker_task_count
37
+ launch_type = "FARGATE"
38
+
39
+ network_configuration {
40
+ security_groups = [aws_security_group.ecs_tasks.id]
41
+ subnets = var.task_subnets
42
+ }
43
+
44
+ lifecycle {
45
+ create_before_destroy = true
46
+ ignore_changes = [task_definition]
47
+ }
48
+ }
@@ -0,0 +1,19 @@
1
+ resource "aws_route53_zone" "primary" {
2
+ count = var.domain_name == null ? 0 : 1
3
+
4
+ name = var.domain_name
5
+ }
6
+
7
+ resource "aws_route53_record" "root" {
8
+ count = var.domain_name == null ? 0 : 1
9
+
10
+ zone_id = aws_route53_zone.primary[0].id
11
+ name = var.domain_name
12
+ type = "A"
13
+
14
+ alias {
15
+ name = module.application.alb.dns_name
16
+ zone_id = module.application.alb.zone_id
17
+ evaluate_target_health = true
18
+ }
19
+ }
@@ -0,0 +1,167 @@
1
+ provider "aws" {
2
+ version = "~> 2.8"
3
+ }
4
+
5
+ provider "template" {
6
+ version = "~> 2.0"
7
+ }
8
+
9
+ locals {
10
+ environment = "production"
11
+ ecr_expire_policy = <<EOF
12
+ {
13
+ "rules": [
14
+ {
15
+ "rulePriority": 1,
16
+ "description": "Expire images older than 14 days",
17
+ "selection": {
18
+ "tagStatus": "untagged",
19
+ "countType": "imageCountMoreThan",
20
+ "countNumber": 14
21
+ },
22
+ "action": {
23
+ "type": "expire"
24
+ }
25
+ }
26
+ ]
27
+ }
28
+ EOF
29
+ }
30
+
31
+ # You MUST run the TF files in the "shared" environment before this will work
32
+ terraform {
33
+ backend "s3" {
34
+ encrypt = true
35
+ bucket = "rails-app-terraform-production"
36
+ dynamodb_table = "rails-app-terraform-production"
37
+ region = "us-east-1"
38
+ key = "statefile"
39
+ }
40
+ }
41
+
42
+ module "vpc" {
43
+ source = "git://github.com/trobrock/terraform-vpc.git?ref=v1.0.0"
44
+
45
+ name = "${var.short_name}-${local.environment}"
46
+ }
47
+
48
+ resource "aws_ecr_repository" "app" {
49
+ name = "${var.short_name}-${local.environment}-app"
50
+ }
51
+
52
+ resource "aws_ecr_lifecycle_policy" "app" {
53
+ repository = aws_ecr_repository.app.name
54
+ policy = local.ecr_expire_policy
55
+ }
56
+
57
+ resource "aws_ecr_repository" "web" {
58
+ name = "${var.short_name}-${local.environment}-web"
59
+ }
60
+
61
+ resource "aws_ecr_lifecycle_policy" "web" {
62
+ repository = aws_ecr_repository.web.name
63
+ policy = local.ecr_expire_policy
64
+ }
65
+
66
+ module "code_pipeline" {
67
+ source = "git://github.com/trobrock/terraform-code-pipeline.git?ref=v2.0.0"
68
+
69
+ short_name = var.short_name
70
+ environment = local.environment
71
+ repo_owner = var.github_org
72
+ repo_name = var.github_repo
73
+
74
+ build_environment = [
75
+ {
76
+ name = "APP_REPOSITORY_URI"
77
+ value = aws_ecr_repository.app.repository_url
78
+ },
79
+ {
80
+ name = "WEB_REPOSITORY_URI"
81
+ value = aws_ecr_repository.web.repository_url
82
+ },
83
+ {
84
+ name = "DATABASE_URL"
85
+ value = module.database.url
86
+ },
87
+ {
88
+ name = "RAILS_ENV"
89
+ value = local.environment
90
+ },
91
+ {
92
+ name = "REDIS_URL"
93
+ value = module.redis.url
94
+ }
95
+ ]
96
+
97
+ lambda_subnet = module.vpc.private_subnets[0]
98
+ ecs_cluster = module.application.ecs_cluster
99
+ ecs_security_group_id = module.application.application_security_group.id
100
+ ecs_task_definition_family = module.application.one_off_task_definition_name
101
+ ecs_task_definition_name = "one_off"
102
+ deployments = [
103
+ {
104
+ name = "deploy-web"
105
+ service_name = module.application.web_service_name
106
+ file_name = "web_imagedefinitions.json"
107
+ },
108
+ {
109
+ name = "deploy-worker"
110
+ service_name = module.application.worker_service_name
111
+ file_name = "worker_imagedefinitions.json"
112
+ }
113
+ ]
114
+ }
115
+
116
+ module "database" {
117
+ source = "git://github.com/trobrock/terraform-database.git?ref=v1.0.1"
118
+
119
+ name = "${var.short_name}${local.environment}"
120
+ instance_class = "db.t2.small"
121
+ vpc_id = module.vpc.vpc_id
122
+ subnets = module.vpc.private_subnets
123
+ security_groups = [module.application.application_security_group.id]
124
+ username = var.short_name
125
+ password = "database20200207"
126
+ }
127
+
128
+ module "redis" {
129
+ source = "git://github.com/trobrock/terraform-redis.git?ref=v1.0.0"
130
+
131
+ name = "${var.name}-${local.environment}"
132
+ vpc_id = module.vpc.vpc_id
133
+ subnets = module.vpc.private_subnets
134
+ security_groups = [module.application.application_security_group.id]
135
+ }
136
+
137
+ module "application" {
138
+ source = "git://github.com/trobrock/terraform-rails-application.git?ref=v0.0.2"
139
+
140
+ name = "${var.short_name}-${local.environment}"
141
+ app_repository_url = aws_ecr_repository.app.repository_url
142
+ web_repository_url = aws_ecr_repository.web.repository_url
143
+ public_subnets = module.vpc.public_subnets
144
+ task_subnets = module.vpc.private_subnets
145
+ vpc_id = module.vpc.vpc_id
146
+ enable_ssl = var.enable_ssl
147
+ acm_certificate_arn = aws_acm_certificate.cert[0].arn
148
+ key_pair_public_key = var.ssh_public_key
149
+
150
+ app_environment = [
151
+ {
152
+ name = "DATABASE_URL"
153
+ value = module.database.url
154
+ },
155
+ {
156
+ name = "REDIS_URL"
157
+ value = module.redis.url
158
+ }
159
+ ]
160
+
161
+ worker_environment = [
162
+ {
163
+ name = "QUEUE"
164
+ value = "*"
165
+ }
166
+ ]
167
+ }
@@ -0,0 +1,28 @@
1
+ resource "aws_acm_certificate" "cert" {
2
+ count = var.enable_ssl ? 1 : 0
3
+
4
+ domain_name = var.domain_name
5
+ subject_alternative_names = ["*.${var.domain_name}"]
6
+ validation_method = "DNS"
7
+
8
+ lifecycle {
9
+ create_before_destroy = true
10
+ }
11
+ }
12
+
13
+ resource "aws_route53_record" "cert_validation" {
14
+ count = var.enable_ssl ? 1 : 0
15
+
16
+ name = aws_acm_certificate.cert[0].domain_validation_options[0].resource_record_name
17
+ type = aws_acm_certificate.cert[0].domain_validation_options[0].resource_record_type
18
+ zone_id = aws_route53_zone.primary[0].id
19
+ records = [aws_acm_certificate.cert[0].domain_validation_options[0].resource_record_value]
20
+ ttl = 60
21
+ }
22
+
23
+ resource "aws_acm_certificate_validation" "cert" {
24
+ count = var.enable_ssl ? 1 : 0
25
+
26
+ certificate_arn = aws_acm_certificate.cert[0].arn
27
+ validation_record_fqdns = [aws_route53_record.cert_validation[0].fqdn]
28
+ }
@@ -0,0 +1,36 @@
1
+ variable "name" {
2
+ description = "The long name to use on resources"
3
+ type = string
4
+ }
5
+
6
+ variable "short_name" {
7
+ description = "The short name to use on resources"
8
+ type = string
9
+ }
10
+
11
+ variable "github_org" {
12
+ description = "The name of the organization in GitHub"
13
+ type = string
14
+ }
15
+
16
+ variable "github_repo" {
17
+ description = "The name of the repository in GitHub"
18
+ type = string
19
+ }
20
+
21
+ variable "domain_name" {
22
+ description = "The primary domain name to launch the app on"
23
+ type = string
24
+ default = null
25
+ }
26
+
27
+ variable "enable_ssl" {
28
+ description = "Whether the app should be served over SSL"
29
+ type = bool
30
+ default = false
31
+ }
32
+
33
+ variable "ssh_public_key" {
34
+ description = "The public key for the SSH key to use in the SSHable group to access servers"
35
+ type = string
36
+ }
@@ -0,0 +1,41 @@
1
+ variable "name" {
2
+ type = string
3
+ description = "the name of the application"
4
+ }
5
+
6
+ provider "aws" {
7
+ version = "~> 2.31"
8
+ }
9
+
10
+ # PRODUCTION
11
+ resource "aws_s3_bucket" "production" {
12
+ bucket = "${var.name}-terraform-production"
13
+
14
+ versioning {
15
+ enabled = true
16
+ }
17
+
18
+ lifecycle {
19
+ prevent_destroy = true
20
+ }
21
+
22
+ tags = {
23
+ Name = "S3 Remote Terraform State Store for production"
24
+ }
25
+ }
26
+
27
+ resource "aws_dynamodb_table" "production" {
28
+ name = "${var.name}-terraform-production"
29
+ hash_key = "LockID"
30
+ read_capacity = 20
31
+ write_capacity = 20
32
+
33
+ attribute {
34
+ name = "LockID"
35
+ type = "S"
36
+ }
37
+
38
+ tags = {
39
+ Name = "DynamoDB Terraform State Lock Table for production"
40
+ }
41
+ }
@@ -0,0 +1,129 @@
1
+ {
2
+ "version": 4,
3
+ "terraform_version": "0.12.20",
4
+ "serial": 4,
5
+ "lineage": "96f07a4f-a32d-dbcd-f6e5-95a51e93647c",
6
+ "outputs": {},
7
+ "resources": [
8
+ {
9
+ "mode": "managed",
10
+ "type": "aws_dynamodb_table",
11
+ "name": "production",
12
+ "provider": "provider.aws",
13
+ "instances": [
14
+ {
15
+ "schema_version": 1,
16
+ "attributes": {
17
+ "arn": "arn:aws:dynamodb:us-east-1:947651631655:table/net-worth-monitor-terraform-production",
18
+ "attribute": [
19
+ {
20
+ "name": "LockID",
21
+ "type": "S"
22
+ }
23
+ ],
24
+ "billing_mode": "PROVISIONED",
25
+ "global_secondary_index": [],
26
+ "hash_key": "LockID",
27
+ "id": "net-worth-monitor-terraform-production",
28
+ "local_secondary_index": [],
29
+ "name": "net-worth-monitor-terraform-production",
30
+ "point_in_time_recovery": [
31
+ {
32
+ "enabled": false
33
+ }
34
+ ],
35
+ "range_key": null,
36
+ "read_capacity": 20,
37
+ "server_side_encryption": [],
38
+ "stream_arn": "",
39
+ "stream_enabled": false,
40
+ "stream_label": "",
41
+ "stream_view_type": "",
42
+ "tags": {
43
+ "Name": "DynamoDB Terraform State Lock Table for production"
44
+ },
45
+ "timeouts": null,
46
+ "ttl": [
47
+ {
48
+ "attribute_name": "",
49
+ "enabled": false
50
+ }
51
+ ],
52
+ "write_capacity": 20
53
+ },
54
+ "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6NjAwMDAwMDAwMDAwLCJ1cGRhdGUiOjM2MDAwMDAwMDAwMDB9LCJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="
55
+ }
56
+ ]
57
+ },
58
+ {
59
+ "mode": "managed",
60
+ "type": "aws_kms_key",
61
+ "name": "parameter_store",
62
+ "provider": "provider.aws",
63
+ "instances": [
64
+ {
65
+ "schema_version": 0,
66
+ "attributes": {
67
+ "arn": "arn:aws:kms:us-east-1:947651631655:key/d9e991ab-6627-4b87-8377-88d9b44eda0a",
68
+ "customer_master_key_spec": "SYMMETRIC_DEFAULT",
69
+ "deletion_window_in_days": 10,
70
+ "description": "Parameter store kms master key (Chamber CLI)",
71
+ "enable_key_rotation": true,
72
+ "id": "d9e991ab-6627-4b87-8377-88d9b44eda0a",
73
+ "is_enabled": true,
74
+ "key_id": "d9e991ab-6627-4b87-8377-88d9b44eda0a",
75
+ "key_usage": "ENCRYPT_DECRYPT",
76
+ "policy": "{\"Id\":\"key-default-1\",\"Statement\":[{\"Action\":\"kms:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::947651631655:root\"},\"Resource\":\"*\",\"Sid\":\"Enable IAM User Permissions\"}],\"Version\":\"2012-10-17\"}",
77
+ "tags": null
78
+ },
79
+ "private": "bnVsbA=="
80
+ }
81
+ ]
82
+ },
83
+ {
84
+ "mode": "managed",
85
+ "type": "aws_s3_bucket",
86
+ "name": "production",
87
+ "provider": "provider.aws",
88
+ "instances": [
89
+ {
90
+ "schema_version": 0,
91
+ "attributes": {
92
+ "acceleration_status": "",
93
+ "acl": "private",
94
+ "arn": "arn:aws:s3:::net-worth-monitor-terraform-production",
95
+ "bucket": "net-worth-monitor-terraform-production",
96
+ "bucket_domain_name": "net-worth-monitor-terraform-production.s3.amazonaws.com",
97
+ "bucket_prefix": null,
98
+ "bucket_regional_domain_name": "net-worth-monitor-terraform-production.s3.amazonaws.com",
99
+ "cors_rule": [],
100
+ "force_destroy": false,
101
+ "hosted_zone_id": "Z3AQBSTGFYJSTF",
102
+ "id": "net-worth-monitor-terraform-production",
103
+ "lifecycle_rule": [],
104
+ "logging": [],
105
+ "object_lock_configuration": [],
106
+ "policy": null,
107
+ "region": "us-east-1",
108
+ "replication_configuration": [],
109
+ "request_payer": "BucketOwner",
110
+ "server_side_encryption_configuration": [],
111
+ "tags": {
112
+ "Name": "S3 Remote Terraform State Store for production"
113
+ },
114
+ "versioning": [
115
+ {
116
+ "enabled": true,
117
+ "mfa_delete": false
118
+ }
119
+ ],
120
+ "website": [],
121
+ "website_domain": null,
122
+ "website_endpoint": null
123
+ },
124
+ "private": "bnVsbA=="
125
+ }
126
+ ]
127
+ }
128
+ ]
129
+ }
@@ -0,0 +1,4 @@
1
+ name = "<%= app_config.slugified_name %>"
2
+ short_name = "<%= app_config.short_name %>"
3
+ github_org = "<%= app_config.github_org %>"
4
+ github_repo = "<%= app_config.github_repo %>"
@@ -0,0 +1 @@
1
+ name = "<%= app_config.slugified_name %>"