Juju 101 - Configure [3/12]

Overview

Duration: 3:00

Before you get started!

Welcome to the world of operators! In this series of tutorials, we will walk you through all the necessary steps to explore and learn operators through some basic examples. Starting with just your laptop, you will learn how to use operators for sophisticated application management at scale, across multiple Kubernetes clusters, cloud virtual machines, and ultimately bare metal.

This tutorial assumes you have successfully completed the previous tutorial - “2. Scale”.

Explore other tutorials >

What are operators?

Operators are pieces of software designed to drive other software. They encapsulate the operational code of applications, shifting the burden of lifecycle management from configuration files and manual steps to an operator instance. Operators are a form of automation that is gaining popularity in the Kubernetes domain where traditional configuration management does not work. However, operators work with traditional virtual and bare metal machines as well.

Learn more about operators >

What is Juju OLM?

Juju is a universal Operator Lifecycle Manager (OLM) which provides services to operators. It provides resources for operators, deploys them, manages their lifecycle, delivers configuration updates, etc. Juju OLM is universal, meaning that it supports container substrates like Kubernetes as well as traditional machine substrates like bare metal, VMware, OpenStack, or public cloud instances.

Learn more about Juju OLM >

In this tutorial, you will learn how to:

  • Display application configuration options set by operators

  • Modify application configuration options with operators

You will only need:

  • A machine with 8 GB of RAM

  • Microk8s and Juju installed

  • Juju controller bootstrapped on MicroK8s

  • Prometheus deployed to MicroK8s with an operator

Manage application configuration

Duration: 7:00

Operators and Juju OLM provide purposeful config capabilities to abstract many low-level application-specific configuration mechanisms and present them in a form of high-level configuration options, reducing the domain knowledge required to operate applications. All applications come with default values of those configuration options which can be overwritten at a deployment time or post-deployment.

In the following steps, we’ll use purposeful config capabilities to display and modify the configuration options of our application applications.

First, let’s see what the current status of the model is:


$ juju status
Model       Controller  Cloud/Region        Version  SLA          Timestamp
monitoring  mk8s        microk8s/localhost  2.9.9    unsupported  11:26:39+01:00

App             Version                 Status  Scale  Charm           Store     Channel  Rev  OS          Address       Message
prometheus-k8s  prom/prometheus:latest  active      2  prometheus-k8s  charmhub  stable     1  kubernetes  10.152.183.7

Unit               Workload  Agent  Address     Ports     Message
prometheus-k8s/0*  active    idle   10.1.98.51  9090/TCP
prometheus-k8s/1   active    idle   10.1.98.5   9090/TCP

You can display all configuration options for an application using the juju config command:

$ juju config prometheus-k8s
application: prometheus-k8s
application-config:
  juju-application-path:
    default: /
    description: the relative http path used to access an application
    source: default
    type: string
    value: /
  juju-external-hostname:
    description: the external hostname of an exposed application
    source: unset
    type: string
  kubernetes-ingress-allow-http:
    default: false
    description: whether to allow HTTP traffic to the ingress controller
    source: default
    type: bool
    value: false
  kubernetes-ingress-class:
    default: nginx
    description: the class of the ingress controller to be used by the ingress resource
    source: default
    type: string
    value: nginx
  kubernetes-ingress-ssl-passthrough:
    default: false
    description: whether to passthrough SSL traffic to the ingress controller
    source: default
    type: bool
    value: false
  kubernetes-ingress-ssl-redirect:
    default: false
    description: whether to redirect SSL traffic to the ingress controller
    source: default
    type: bool
    value: false
  kubernetes-service-annotations:
    description: a space separated set of annotations to add to the service
    source: unset
    type: attrs
  kubernetes-service-external-ips:
    description: list of IP addresses for which nodes in the cluster will also accept
      traffic
    source: unset
    type: string
  kubernetes-service-externalname:
    description: external reference that kubedns or equivalent will return as a CNAME
      record
    source: unset
    type: string
  kubernetes-service-loadbalancer-ip:
    description: LoadBalancer will get created with the IP specified in this field
    source: unset
    type: string
  kubernetes-service-loadbalancer-sourceranges:
    description: traffic through the load-balancer will be restricted to the specified
      client IPs
    source: unset
    type: string
  kubernetes-service-target-port:
    description: name or number of the port to access on the pods targeted by the
      service
    source: unset
    type: string
  kubernetes-service-type:
    description: determines how the Service is exposed
    source: unset
    type: string
  trust:
    default: false
    description: Does this application have access to trusted credentials
    source: default
    type: bool
    value: false
charm: prometheus-k8s
settings:
  evaluation-interval:
    default: 1m
    description: |
      How frequently rules will be evaluated.
    source: default
    type: string
    value: 1m
  external-labels:
    default: '{}'
    description: |
      A JSON string of key-value pairs that specify the labels to
      attach to metrics in this Prometheus instance when they get pulled
      by an aggregating parent. This is useful in the case of federation
      where, for example, you want each datacenter to have its own
      Prometheus instance and then have a global instance that pulls from
      each of these datacenter instances. By specifying a unique set of
      external-labels for each datacenter instance, you can easily determine
      in the aggregating Prometheus instance which datacenter a metric is
      coming from. Note that you are not limited to one instance per
      datacenter. The datacenter example here is arbitrary and you are free
      to organize your federation's hierarchy as you see fit.
      Ex. '{ "cluster": "datacenter1" }'. Both keys and values may be
      arbitrarily chosen as you see fit.
    source: default
    type: string
    value: '{}'
  log-level:
    description: |
      Prometheus server log level (only log messages with the given severity
      or above). Must be one of: [debug, info, warn, error, fatal].
      If not set, the Prometheus default one (info) will be used.
    source: unset
    type: string
  port:
    default: 9090
    description: The port prometheus will be listening on
    source: default
    type: int
    value: 9090
  prometheus-image-password:
    default: ""
    description: |
      The password associated with prometheus-image-username for
      accessing the registry specified in prometheus-image-path.
    source: default
    type: string
    value: ""
  prometheus-image-path:
    default: prom/prometheus:latest
    description: |
      The location of the image to use,
      e.g. "registry.example.com/prometheus:v1".

      This setting is required.
    source: default
    type: string
    value: prom/prometheus:latest
  prometheus-image-username:
    default: ""
    description: |
      The username for accessing the registry specified in
      prometheus-image-path.
    source: default
    type: string
    value: ""
  scrape-interval:
    default: 1m
    description: |
      How frequently to scrape targets by default.
    source: default
    type: string
    value: 1m
  scrape-timeout:
    default: 10s
    description: |
      How long until a scrape request times out.
    source: default
    type: string
    value: 10s
  ssl-cert:
    description: |
      SSL certificate to install and use for Prometheus endpoint.
    source: unset
    type: string
  ssl-key:
    description: |
      SSL key to use with certificate specified as ssl-cert.
    source: unset
    type: string
  tsdb-retention-time:
    default: 15d
    description: |
      How long to retain samples in the storage.
      Units Supported: y, w, d, h, m, s
    source: default
    type: string
    value: 15d
  tsdb-wal-compression:
    default: false
    description: |
      This flag enables compression of the write-ahead log (WAL).
      Depending on your data, you can expect the WAL size to be
      halved with little extra cpu load.
    source: default
    type: boolean
    value: false
  web-external-url:
    default: ""
    description: |
      The URL under which Prometheus is externally reachable (for example,
      if Prometheus is served via a reverse proxy).
      Used for generating relative and absolute links back to
      Prometheus itself. If the URL has a path portion, it will be used to
      prefix all HTTP endpoints served by Prometheus.

      If omitted, relevant URL components will be derived automatically.
    source: default
    type: string
    value: ""

Individual configuration values can be viewed by appending a key to the juju config command:

$ juju config prometheus-k8s web-external-url

You can view the Prometheus web UI by locating the IP address of the Prometheus application and using the browser to navigate to that. Using juju status locate the Prometheus 0 unit IP address.

$ juju status
...
Unit               Workload  Agent  Address     Ports     Message
prometheus-k8s/0*  active    idle   10.1.98.51  9090/TCP
...

Alternatively, you can use jq to programmatically get that value

$ juju status --format=json | jq -r ".applications | .[\"prometheus-k8s\"] | .units | .[\"prometheus-k8s/0\"] | .address"

Then navigate to the following URL “http://$PROMETHEUS_IP:9090”.

Changing a configuration value will cause the application to evaluate the incoming change and react accordingly. Let’s try changing scrape-interval from the default value:

$ juju config prometheus-k8s scrape-interval=30s

You can view the change by running:

$ juju config prometheus-k8s scrape-interval
30s

Prometheus will be attempting to scrap any configured endpoints every 30 seconds instead of once a minute.

Next steps

Duration: 2:00

Congratulations! You have reached the end of this tutorial.

You can now move to the next tutorial - “4. Services and ports”.

In this tutorial you have learnt how to:

  • Display application configuration options set by operators

  • Modify application configuration options with operators

Where to go from here?