Skip to content
Jonathan Meyer edited this page Sep 6, 2019 · 7 revisions

There are 3 primary steps to launching Scale:

  1. Launch DCOS
  2. Create support and feed AWS resources
  3. Launch Scale

Terraform will allow us to create all the infrastructure with minimal headache. The following files are a good starting point:

dcos.tf

provider "aws" {
}

# Used to determine your public IP for forwarding rules
data "http" "whatismyip" {
  url = "http://whatismyip.akamai.com/"
}

module "dcos" {
  source  = "dcos-terraform/dcos/aws"
  version = "~> 0.2.0"

  providers = {
    aws = "aws"
  }

  cluster_name        = "scale-dcos-demo"
  ssh_public_key_file = "~/.ssh/id_rsa.pub"
  admin_ips           = ["${data.http.whatismyip.body}/32"]

  num_masters        = 1
  num_private_agents = 4
  num_public_agents  = 1

  dcos_version = "1.13.3"
  dcos_variant = "open"

  dcos_instance_os             = "centos_7.6"
  bootstrap_instance_type      = "t2.micro"
  masters_instance_type        = "t2.medium"
  private_agents_instance_type = "t2.xlarge"
  public_agents_instance_type  = "t2.medium"
}

output "masters-ips" {
  value = "${module.dcos.masters-ips}"
}

output "cluster-address" {
  value = "${module.dcos.masters-loadbalancer}"
}

output "public-agents-loadbalancer" {
  value = "${module.dcos.public-agents-loadbalancer}"
}

scale-support.tf

resource "aws_iam_service_linked_role" "es" {
  aws_service_name = "es.amazonaws.com"
}

resource "aws_elasticsearch_domain" "scale" {
  domain_name           = "scale-demo-elasticsearch"
  elasticsearch_version = "6.8"

  cluster_config {
    instance_type = "t2.small.elasticsearch"
  }
  
  ebs_options {
    ebs_enabled = true
    volume_type = "gp2"
    volume_size = "10"
  }

  vpc_options {
    subnet_ids = [ "${element(module.dcos.infrastructure.vpc.subnet_ids,0)}" ]
    security_group_ids = [ "${module.dcos.infrastructure.security_groups.internal}" ]
  }

  tags {
    Domain = "ScaleES"
  }

  depends_on = [
    "aws_iam_service_linked_role.es",
  ]
}

resource "aws_elasticsearch_domain_policy" "main" {
  domain_name = "${aws_elasticsearch_domain.scale.domain_name}"

  access_policies = <<POLICIES
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "es:*",
            "Principal": "*",
            "Effect": "Allow",
            "Resource": "${aws_elasticsearch_domain.scale.arn}/*"
        }
    ]
}
POLICIES
}

resource "aws_db_instance" "scale" {
  allocated_storage       = 20
  max_allocated_storage   = 100
  storage_type            = "gp2"
  engine                  = "postgres"
  engine_version          = "9.6"
  instance_class          = "db.t2.micro"
  name                    = "scaledemo"
  username                = "scaledemo"
  password                = "scaledemo-pass"
  db_subnet_group_name	  = "${aws_db_subnet_group.scale.id}" 
  vpc_security_group_ids  = [ "${module.dcos.infrastructure.security_groups.internal}" ]
  skip_final_snapshot	  = true
}

resource "aws_db_subnet_group" "scale" {
  name       = "scale_db_subnet_group"
  subnet_ids = ["${module.dcos.infrastructure.vpc.subnet_ids}"]
}

resource "aws_sqs_queue" "scale" {
  name = "scale-internal-messages"
}

resource "aws_sqs_queue_policy" "scale" {
  queue_url = "${aws_sqs_queue.scale.id}"
  policy    = <<POLICY
{
  "Version": "2012-10-17",
  "Id": "sqspolicy",
  "Statement": [
    {
      "Sid": "First",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "sqs:*",
      "Resource": "${aws_sqs_queue.scale.arn}"
    }
  ]
}
POLICY
}

output "scale-support-internal-queue" {
  value = "${aws_sqs_queue.scale.name}"
}

output "scale-support-rds" {
  value = "${aws_db_instance.scale.endpoint}"
}

output "scale-support-elasticsearch" {
  value = "${aws_elasticsearch_domain.scale.endpoint}"
}

feeds.tf

##### SET THIS VALUE
## Otherwise you will get a conflict with someone else's bucket names
## since bucket names are AWS global (across all regions)
variable "template_name" {
  type = "string"
  default = "scale-s3-test"
}

resource "random_id" "bucket_suffix" {
  byte_length = 8
}

resource "aws_s3_bucket" "b_i" {
  bucket = "${var.template_name}-input-${random_id.bucket_suffix.hex}"
  force_destroy = true
  acl    = "private"
}

resource "aws_s3_bucket" "b_o" {
  bucket = "${var.template_name}-output-${random_id.bucket_suffix.hex}"
  force_destroy = true
  acl    = "private"
}

resource "aws_s3_bucket_notification" "b_n" {
  bucket = "${aws_s3_bucket.b_i.id}"

  queue {
    queue_arn     = "${aws_sqs_queue.q.arn}"
    events        = ["s3:ObjectCreated:*"]
  }
}

resource "aws_sqs_queue" "q" {
  name = "${var.template_name}"

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "sqs:SendMessage",
      "Resource": "arn:aws:sqs:*:*:${var.template_name}",
      "Condition": {
        "ArnEquals": { "aws:SourceArn": "${aws_s3_bucket.b_i.arn}" }
      }
    }
  ]
}
POLICY
}

resource "aws_iam_policy" "policy" {
  name        = "${var.template_name}"
  path        = "/"
  description = "IAM policy to allow full access to Scale S3 test buckets and queue"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": [
                "arn:aws:sqs:*:*:${var.template_name}"
            ]
        },
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::${var.template_name}*",
                "arn:aws:s3:::${var.template_name}*/*"
            ]
        }
    ]
}
EOF
}

resource "aws_iam_user" "user" {
  name = "${var.template_name}-user"
}


resource "aws_iam_user_policy_attachment" "attach" {
  user       = "${aws_iam_user.user.name}"
  policy_arn = "${aws_iam_policy.policy.arn}"
}

resource "aws_iam_access_key" "k" {
  user = "${aws_iam_user.user.name}"
}

output "scale-iam-access-key-id" {
  value = "${aws_iam_access_key.k.id}"
}

output "scale-iam-secret-access-key" {
  value = "${aws_iam_access_key.k.secret}"
}

output "scale-input-queue-name" {
  value = "${aws_sqs_queue.q.name}"
}

output "scale-input-bucket" {
  value = "${aws_s3_bucket.b_i.id}"
}

output "scale-output-bucket" {
  value = "${aws_s3_bucket.b_o.id}"
}

You'll need to set the region and run the terraform plan / apply phases.

export AWS_DEFAULT_REGION=us-east-1
eval $(ssh-agent)
ssh-add ~/.ssh/id_rsa
terraform plan -out .pf
terraform apply .pf

Once these are created we need to deploy Scale. This can be done by taking the generated marathon.json and dropping into DCOS Admin UI:

echo '{
  "requirePorts": false,
  "healthChecks": [
    {
      "gracePeriodSeconds": 300,
      "intervalSeconds": 30,
      "timeoutSeconds": 20,
      "maxConsecutiveFailures": 3,
      "protocol": "COMMAND",
      "command": {
        "value": "ps -ef | grep scale_scheduler | grep -v grep > /dev/null"
      }
    }
  ],
  "env": {
    "SCALE_VHOST": "scale.marathon.mesos",
    "DCOS_PACKAGE_FRAMEWORK_NAME": "scale",
    "ENABLE_BOOTSTRAP": "true",
    "ADMIN_PASSWORD": "admin",
    "UI_DOCKER_IMAGE": "geoint/scale-ui:v0.8.1",
    "FLUENTD_DOCKER_IMAGE": "geoint/scale-fluentd:7.0.0",
    "SCALE_BROKER_URL": "sqs://us-east-1"
  },
  "cmd": "./entryPoint.sh scale_scheduler",
  "gpus": 0,
  "disk": 0,
  "mem": 1024,
  "cpus": 1,
  "container": {
    "docker": {
      "image": "geointdev/scale",
      "forcePullImage": true,
      "privileged": false
    },
    "type": "DOCKER"
  },
  "instances": 1,
  "id": "/scale"
}' | jq ".env.SCALE_VHOST=\"$(terraform output public-agents-loadbalancer)\"" | jq ".env.ELASTICSEARCH_URL=\"https://$(terraform output scale-support-elasticsearch):443\"" | jq ".env.DATABASE_URL=\"postgis://scaledemo:scaledemo-pass@$(terraform output scale-support-rds)/scaledemo\"" | jq ".env.SCALE_QUEUE_NAME=\"$(terraform output scale-support-internal-queue)\"" | jq ".env.SCALE_BROKER_URL=\"sqs://$AWS_DEFAULT_REGION\""> scale.json
Clone this wiki locally