Skip to content

Helm charts with Terraform Integration

Omnistrate supports integrating Terraform IaC steps as part of a Helm chart deployment to build a unified deployment workflow. A good example of such a use-case is when you need auxiliary services like Databases or Caches through managed services like AWS RDS, Elasticache, MongoDB Atlas, etc. to be deployed as part of your Helm chart deployment. Additionally, you may want to reference the output of the Terraform IaC steps in the Helm chart configuration (e.g. the database connection string, cache endpoint, etc.).

In this guide, we will show you how to deploy an Umbrella Helm chart that deploys a simple app that depends on a Postgres Helm chart with an S3 bucket and a DynamoDB table. You can define any number of such compositions and Omnistrate powers all of them through its idempotent, scalable workflow engine.

The following diagram lays out the composition and the end goal for this SaaS deployment: Arch Diagram

At the end of this exercise, you will have an Nginx "app" deployment that is configured to talk to a Postgres database through a Kubernetes Service. The app also will have environment variables configured with the S3 bucket ARN and the DynamoDB Table ARN. To secure access to these services, we will leverage IRSA for federated access. We will leverage the power and versatility of System Parameters to inject the right context of the EKS cluster and OIDC configuration.

Variant: Fully Hosted Deployment

In this variant, we will deploy the entire composition for your tenants in your account. We will slice up your AWS account and EKS cluster into multiple tenant environments with isolation across the stack including dedicated IAM roles for each tenant deployment.

Build a new SaaS service plan / composition

The first step is to model the above composition as a specification on Omnistrate. Following the earlier examples of onboarding a SaaS service based on Helm charts, you can use the Omnistrate CLI to build the SaaS service plan. Make sure to replace the <AWS_ID> with your AWS account and connect your AWS account to Omnistrate.

# yaml-language-server: $schema=https://api.omnistrate.cloud/2022-09-01-00/schema/service-spec-schema.json

name: Web App # Service Plan Name
deployment:
  hostedDeployment:
    AwsAccountId: "<AWS_ID>"
    AwsBootstrapRoleAccountArn: arn:aws:iam::<AWS_ID>:role/omnistrate-bootstrap-role

services:
  - name: Web App
    dependsOn:
      - dataInfraTerraform
    compute:
      instanceTypes:
        - apiParam: instanceType
          cloudProvider: aws
        - apiParam: instanceType
          cloudProvider: gcp
    network:
      ports:
        - 80
    helmChartConfiguration:
      chartName: private-umbrella-chart
      chartVersion: 0.1.2
      chartRepoName: private-umbrella-repo
      chartRepoURL: https://raw.githubusercontent.com/omnistrate-community/helm-private-example/main
      authProvider:
        username: <PAT>
        password: <PAT>
      chartValues:
        serviceAccount:
          name: "web-app-sa"
        s3BucketARN: "{{ $dataInfraTerraform.out.s3_bucket_arn }}"
        lambdaFunctionName: "{{ $dataInfraTerraform.out.lambda_function_name }}"
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
                - matchExpressions:
                  - key: omnistrate.com/managed-by
                    operator: In
                    values:
                    - omnistrate
                  - key: topology.kubernetes.io/region
                    operator: In
                    values:
                    - $sys.deploymentCell.region
                  - key: node.kubernetes.io/instance-type
                    operator: In
                    values:
                    - $sys.compute.node.instanceType
                  - key: omnistrate.com/resource
                    operator: In
                    values:
                    - $sys.deployment.resourceID
          podAntiAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: omnistrate.com/schedule-mode
                  operator: In
                  values:
                  - exclusive
              namespaceSelector: {}
              topologyKey: kubernetes.io/hostname
    apiParameters:
      - key: instanceType
        description: Instance Type
        name: Instance Type
        type: String
        modifiable: true
        required: false
        export: true
        defaultValue: "t4g.small"
  - name: dataInfraTerraform
    internal: true
    terraformConfigurations:
      configurationPerCloudProvider:
        aws:
          terraformPath: /
          gitConfiguration:
            reference: refs/heads/demo
            repositoryUrl: https://github.com/omnistrate-community/terraform-private-example.git
            accessToken: <ACCESS_TOKEN>

Apply changes to the service

For this we will run the same command that was used to setup the service the first time.

omnistrate-ctl build -f spec.yaml --name 'UmbrellaHelm' --release-as-preferred --spec-type ServicePlanSpec

# Example output shown below
 Successfully built service
Check the service plan result at: https://omnistrate.cloud/product-tier?serviceId=s-dEhutaDa2X&environmentId=se-92smpU2YAm
Access your SaaS offer at: https://saasportal.instance-w6vidhd14.hc-pelsk80ph.us-east-2.aws.f2e0a955bb84.cloud/service-plans?serviceId=s-dEhutaDa2X&environmentId=se-92smpU2YAm