Skip to content

Openstack Docker Deployment

This Terraform example provides one stop approach to deploy the CogStack platform with its core components and observability stack in an OpenStack environment. It is specifically designed to simplify and automate the provisioning and configuration needed to run CogStack reliably and securely.

This example:

  • Provisions Ubuntu VMs in openstack
  • Installs Docker and Portainer on the VMs using Cloud-Init to manage containers easily
  • Uses Ansible for Configuration Management to deploy necessary CogStack configuration files and system setup
  • Deploys the MedCAT Service enabling natural language processing on an API
  • Sets up Observability Tools by deploying Prometheus for metrics collection and Grafana dashboards for monitoring the health and performance of CogStack services.
  • Runs Integration Tests after the infrastructure is created, asserting that services are running on the created IP addresses.

Usage

Requirements

1. Get the configuration files

Get the Terraform files for this example (the ZIP contains all deployment-examples; use the openstack-docker folder for this guide).

Download all deployment examples (ZIP)

Alternatively you can view the file contents here:

openstack-vms terraform files

This module provisions OpenStack VMs and networking for the stack.

module "openstack_cogstack_infra" {
  source = "github.com/CogStack/cogstack-platform-toolkit//deployment/terraform/modules/openstack-cogstack-infra?ref=terraform-modules-v0.1.0"
  host_instances = [
    { name = "cogstack-docker-controller", is_controller = true },
    { name = "cogstack-docker-medcat-nlp" }
  ]
  allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr
  ubuntu_immage_name       = var.ubuntu_immage_name
}
output "created_controller_host" {
  value = module.openstack_cogstack_infra.created_controller_host
}

output "created_hosts" {
  value = module.openstack_cogstack_infra.created_hosts
}

output "ssh_keys" {
  sensitive = true
  value     = module.openstack_cogstack_infra.compute_keypair
}

output "portainer_instance" {
  sensitive = true
  value     = module.openstack_cogstack_infra.portainer_instance
}
terraform {
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 3.0.0"
    }
  }
}

provider "openstack" {
  insecure                      = true
  enable_logging                = true
  auth_url                      = var.openstack_environment.openstack_auth_url
  application_credential_id     = var.openstack_environment.openstack_application_credential_id
  application_credential_secret = var.openstack_environment.openstack_application_credential_secret
  region                        = var.openstack_environment.region
}
variable "openstack_environment" {
  type = object({
    openstack_auth_url                      = string,
    openstack_application_credential_secret = string,
    openstack_application_credential_id     = string,
    region                                  = string
  })
  description = <<EOT
openstack_application_credential_id     = OpenStack application credential ID. Scoped to a project
openstack_application_credential_secret = OpenStack application credential secret. Scoped to a project
openstack_auth_url    = OpenStack Auth URL. Scoped accross projects
EOT
}

variable "allowed_ingress_ips_cidr" {
  description = "The CIDR block to grant access to cogstack services to. For example, grant access to internal users in the VPN"
  type        = string
}

variable "ubuntu_immage_name" {
  type        = string
  description = "Name of an available Machine Image running ubuntu in the openstack environment"
}

docker-deployment terraform files

This module deploys Docker-based CogStack services.

module "cogstack_docker_services" {
  source = "github.com/CogStack/cogstack-platform-toolkit//deployment/terraform/modules/cogstack-docker-services?ref=terraform-modules-v0.1.0"
  hosts  = var.hosts
  service_targets = {
    observability  = { hostname = "cogstack-docker-controller" }
    medcat_service = { hostname = "cogstack-docker-medcat-nlp" }
  }
  ssh_private_key_file = var.ssh_private_key_file
}
output "created_services" {
  value = module.cogstack_docker_services
}
terraform {
  required_providers {
    portainer = {
      source  = "portainer/portainer"
      version = "~> 1.10.0"
    }
    ansible = {
      version = "~> 1.3.0"
      source  = "ansible/ansible"
    }
  }
}


provider "portainer" {
  endpoint        = var.portainer_instance.endpoint
  api_user        = var.portainer_instance.username
  api_password    = var.portainer_instance.password
  skip_ssl_verify = true # optional (default value is `false`)
}
# Variables for Docker Deployment
# It's recommended to follow the README.md and use the output of the openstack-vms module

variable "portainer_instance" {
  type = object({
    endpoint = string
    username = string
    password = string
  })

  description = <<EOT
endpoint = API to call portainer on
username        = Portainer username
password        = Portainer password to use
EOT
}

variable "ssh_private_key_file" {
  type        = string
  description = "A filepath to a SSH Private key that is used to SSH login to created hosts"
}

variable "hosts" {
  type = map(object({
    ip_address  = string,
    unique_name = string,
    name        = string
  }))
  description = "Created Hosts: A map of { hostname: { data } }"
}

2. Add required secrets for your environment

Create a terraform.tfvars file, based on terraform.tfvars.example, containing the secrets for your environment.

3. Run Terraform

terraform init
terraform apply

Initial provisioning takes up to 10 minutes, where time is mostly downloading large docker images

4. Accessing the CogStack Platform

Once the deployment is complete and all services are running, you can access the CogStack platform and its components using the following URLs:

terraform output service_urls

Troubleshooting

unsupported protocol scheme

If you make changes to the created VM infrastructure, and want to reapply, you can run into this error

│ Error: Get "/api/endpoints/4": unsupported protocol scheme ""
│ 
│   with module.cogstack_docker_services.portainer_environment.portainer_envs["cogstack-devops"],
│   on ../../modules/cogstack-docker-services/environments.tf line 3, in resource "portainer_environment" "portainer_envs":
│    3: resource "portainer_environment" "portainer_envs" {

Fix by targetting just the infra module first:

terraform apply -target=module.openstack_cogstack_infra
terraform apply

For details: the error specifically occurs after making a change to the controller host, forcing it to be deleted and recreated, however terraform still uses the IP address in the portainer provider. Targetting just the infra module first, means terraform wont call any APIs during the plan stage using the old IP address.