Levant Documentation

repository·main·Indexed 21 days ago

https://github.com/hashicorp/levant

Levant is an open-source templating and deployment tool specifically designed for HashiCorp Nomad jobs. It provides real-time feedback, advanced job status checking, and detailed failure inspection to improve the deployment workflow. Key features include support for variable declaration via .json, .tf, .yaml, and .yml files, canary auto-promotion, and commands for deploying, planning, rendering, dispatching, and scaling Nomad jobs.

Tokens
12.2K
Snippets
39
Records
42
Agent score
63%

What's inside Levant

  1. Overview of Levant features

    main

    Levant is an open source templating and deployment tool for HashiCorp Nomad jobs. It is designed to provide high visibility into the deployment lifecycle through several key features:

    • Realtime Feedback: Uses watchers to provide live updates on Nomad job deployments.
    • Advanced Job Status Checking: Monitors jobs, evaluations, and allocations to ensure they reach the desired state (critical for system and batch jobs).
    • Dynamic Job Group Counts: Automatically updates rendered templates with current job group counts if the job is already running in the cluster.
    • Failure Inspection: Automatically inspects allocations and logs events upon deployment failure to assist in debugging.
    • Canary Auto Promotion: Supports a canary-auto-promote time period to automatically promote healthy canaries after a threshold is met.
    • Variable Support: Supports template variable declaration using .json, .tf, .yaml, and .yml files.
    • Auto Revert Checking: Tracks rollback deployments if a job fails to pass its healthy threshold and has auto-revert enabled.
  2. How template substitution works in Levant

    main

    Levant allows you to use the same Nomad job files across different environments by using template variables. To avoid clashing with Nomad's native {{ }} interpolation, Levant uses double squared brackets [[ ]] for its own template syntax.

    Supported variable file formats include:

    • JSON (.json): Highly flexible and organized.
    • YAML (.yaml, .yml): Highly flexible and organized.
    • Terraform (.tf): Provides a descriptive, consistent format if you already use Terraform for infrastructure.

    Variables are accessed within the job template using dot notation (e.g., [[ .variable_name ]] or [[ .nested.key ]]).

    # Example job template
    resources {
        cpu    = [[.resources.cpu]]
        memory = [[.resources.memory]]
    
        network {
            mbits = [[.resources.network.mbits]]
        }
    }
  3. Use JSON, YAML, or Terraform for variable files

    main

    You can declare template variables using JSON, YAML, or Terraform files. Levant will inject these values into your job templates using the [[ ]] syntax.

    JSON Example

    Variable file (vars.json):

    {
        "resources":{
            "cpu":250,
            "memory":512,
            "network":{
                "mbits":10
            }
        }
    }

    Job Template:

    resources {
        cpu    = [[.resources.cpu]]
        memory = [[.resources.memory]]
    }

    YAML Example

    Variable file (vars.yaml):

    ---
    resources:
      cpu: 250
      memory: 512
      network:
        mbits: 10

    Terraform Example

    Variable file (vars.tf):

    variable "resources_cpu" {
      description = "the CPU in MHz to allocate to the task group"
      type        = "string"
      default     = 250
    }

    Job Template:

    resources {
        cpu = [[.resources_cpu]]
    }
  4. Install Levant

    main

    You can install Levant using several methods depending on your environment:

    Via Go

    Use the Go toolkit to download and install the binary:

    go get github.com/hashicorp/levant && go install github.com/hashicorp/levant

    Via Docker

    Pull the latest official image from Docker Hub:

    docker pull hashicorp/levant

    From Source

    Clone the repository and use make to build the binary:

    git clone git://github.com/hashicorp/levant.git
    cd levant
    make dev

    The resulting binary will be located at ./bin/levant.

    Pre-built Binaries

    Official binaries are available on the HashiCorp releases site. For older versions (0.2.9 and earlier), you can download them from the GitHub releases page. For example, to download the 0.2.9 linux-amd64 binary:

    curl -L https://github.com/hashicorp/levant/releases/download/0.2.9/linux-amd64-levant -o levant
    go get github.com/hashicorp/levant && go install github.com/hashicorp/levant
  5. Configure the Consul Client

    main

    Levant uses the Consul Default API Client. You can configure the Consul HTTP address via CLI flags, but all other Consul client parameters (such as TLS settings and ACL tokens) must be configured using environment variables.

    # Example: Configuring Consul with an address and ACL token
    export CONSUL_HTTP_ADDR="127.0.0.1:8500"
    export CONSUL_HTTP_TOKEN="your-consul-token"
    levant <command>
  6. Configure the Nomad Client

    main

    Levant uses the Nomad Default API Client. While you can configure the HTTP address via CLI flags, all other Nomad client parameters must be configured using environment variables. This allows you to control connection settings, TLS/SSL verification, namespaces, and ACL authentication.

    # Example: Configuring Nomad with a specific address, token, and TLS certificate
    export NOMAD_ADDR="https://nomad.example.com:4646"
    export NOMAD_TOKEN="your-acl-token"
    export NOMAD_CACERT="/path/to/ca.pem"
    levant <command>
  7. Force deployment of periodic jobs

    main

    If you need to force a new instance of a periodic job to run immediately, even if it violates the job's prohibit_overlap settings, use the -force-batch flag.

    Note: This flag can only be used with jobs that are configured as periodic in Nomad.

    levant deploy my-periodic-job.nomad -force-batch
  8. Handle deployments with no changes in CI/CD

    main

    By default, if Levant detects no changes between the rendered template and the running Nomad job, it exits with status 1. This is intended to signal that no deployment occurred.

    To prevent CI/CD pipelines from failing when no changes are detected, use the -ignore-no-changes flag. When this flag is used, Levant will exit with status 0 if no changes are detected.

    levant deploy my-job.nomad -ignore-no-changes
  9. Parse JSON from Consul KV for complex templates

    main

    If you store a complex JSON object in Consul, you can use parseJSON to inject its structure into your job template. This allows you to use dot notation to access nested keys within the JSON blob.

    Consul KV at service/config/variables:

    {"resources":{"cpu":250,"memory":512,"network":{"mbits":10}}}

    Job Template:

    [[ with $data := consulKey "service/config/variables" | parseJSON ]]
    resources {
        cpu    = [[.resources.cpu]]
        memory = [[.resources.memory]]
    
        network {
            mbits = [[.resources.network.mbits]]
        }
    }
    [[ end ]]

    Rendered Output:

    resources {
        cpu    = 250
        memory = 512
    
        network {
            mbits = 10
        }
    }
  10. How to use loops and parsed integers together

    main

    You can combine parseInt with the loop function to create dynamic configurations based on values retrieved from Consul or variables.

    Example: Creating a dynamic list of connection pool IDs If Consul has service/config/conn_pool set to 3, the following template will generate 3 connection pool IDs:

    [[ with $i := consulKey "service/config/conn_pool" | parseInt ]]
    [[ range $d := loop $i ]]
    conn-pool-id-[[ $d ]]
    [[ end ]]
    [[ end ]]

    Rendered Output:

    conn-pool-id-0
    conn-pool-id-1
    conn-pool-id-2
  11. Query Consul values using template functions

    main

    Levant provides built-in functions to interact with Consul KV during template rendering. These functions use the [[ ]] syntax.

    • consulKey "path": Returns the value at the given Consul KV path.
    • consulKeyExists "path": Returns true if the key exists, false otherwise. Useful for conditional logic.
    • consulKeyOrDefault "path" "default": Returns the value at the path, or the provided default if the key does not exist.

    Examples

    Get a value: [[ consulKey "service/config/cpu" ]] $\rightarrow$ 250

    Conditional logic:

    [[ if consulKeyExists "service/config/alerting" ]]
      <configure alerts>
    [[ else ]]
      <skip configure alerts>
    [[ end ]]

    With default value: [[ consulKeyOrDefault "service/config/database-addr" "localhost:3306" ]] $\rightarrow$ localhost:3306

    [[ consulKey "service/config/cpu" ]]