Local Cluster with minikube

On this page

Having the capability to deploy applications in a local Kubernetes environment allows engineers to quickly develop, test, and demo without the operational overhead of a full-blown cluster. This is precisely what minikube is designed for: it runs a single-node cluster on your machine.

This guide shows you how to install and start minikube, then deploy the PostgreSQL database and Elasticsearch service that FusionAuth needs. After that, you deploy FusionAuth itself with the Deploy with k8s guide.

minikubeTLSBasic authenticationFusionAuthPostgreSQLElasticsearch

The minikube cluster you will create.

Requirements#

Before you begin, you will need to have the following installed.

  • Docker Desktop - The container environment you will use to run minikube.
  • helm - Package manager used for installing and managing Kubernetes applications. The FusionAuth deployment guide uses a Helm chart to install FusionAuth. For more information, see Installing Helm.
  • kubectl - Command line tool that interacts with the Kubernetes API server and is useful for managing Kubernetes clusters. Before proceeding, follow the installation documentation that corresponds to your platform found here. Use a kubectl version within one minor version of your cluster's Kubernetes version.

Install minikube#

Navigate to minikube start and complete step one by selecting the options that apply to your local machine.

For example, on macOS, Homebrew is a popular installer type:

Install minikube
brew install minikube

Start minikube#

Since you will be deploying multiple applications, you will want to start minikube using some additional resource considerations.

Caution

Before proceeding, make sure Docker Desktop has sufficient resources allocated. These settings can be found in Docker Desktop by navigating to Settings -> Resources . You need to have at least as much memory allocated to Docker Desktop as you give to minikube below.

Start minikube by additionally specifying cpus and memory.

Start minikube
minikube start --cpus 4 --memory 5g

When the command finishes, it will configure kubectl to point to the minikube cluster. You can confirm this by checking the status:

Get minikube status
minikube status
Output
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

Deploy PostgreSQL#

This guide runs PostgreSQL from the official postgres image. When the database starts, it creates a self-signed certificate, so FusionAuth can connect to it over TLS with the settings in the deployment guide.

Note

The database keeps its data inside the container, so you lose the data when the pod restarts. This is fine for local testing. For anything else, use a managed database or a PersistentVolume.

First, store a password for the postgres superuser in a Secret. Choose your own password, and note it, because you will use it again when you deploy FusionAuth:

Create a Secret for the PostgreSQL superuser
kubectl create secret generic postgres-credentials --from-literal=password='<superuser-password>'

Then create a file named postgres.yaml with a Deployment that runs PostgreSQL and a Service that exposes it to the rest of the cluster:

PostgreSQL configuration
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:18.1-bookworm
          # creates a self-signed certificate so FusionAuth can connect over TLS
          command: ["bash", "-c"]
          args:
            - >-
              openssl req -x509 -newkey rsa:2048 -nodes -days 365 -subj "/CN=postgres"
              -keyout /tmp/server.key -out /tmp/server.crt &&
              chown postgres /tmp/server.key /tmp/server.crt && chmod 600 /tmp/server.key &&
              exec docker-entrypoint.sh postgres -c ssl=on -c ssl_cert_file=/tmp/server.crt -c ssl_key_file=/tmp/server.key
          env:
            - name: POSTGRES_USER
              value: postgres
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-credentials
                  key: password
          ports:
            - containerPort: 5432
          readinessProbe:
            exec:
              command: ["pg_isready", "-U", "postgres"]
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  selector:
    app: postgres
  ports:
    - port: 5432

Apply the file:

Deploy PostgreSQL
kubectl apply -f ./postgres.yaml

Deploy Elasticsearch#

FusionAuth supports Elasticsearch 7.6.1 through 7.17.x. This guide runs a single Elasticsearch 7.17 node with security enabled, so FusionAuth has to authenticate as the elastic user.

Store a password for the elastic user in a Secret, and note it as well:

Create a Secret for the elastic user
kubectl create secret generic elasticsearch-credentials --from-literal=password='<search-password>'

Then create a file named elasticsearch.yaml:

Elasticsearch configuration
apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
        - name: elasticsearch
          image: docker.elastic.co/elasticsearch/elasticsearch:7.17.29
          env:
            - name: discovery.type
              value: single-node
            - name: xpack.security.enabled
              value: "true"
            - name: ES_JAVA_OPTS
              value: -Xms512m -Xmx512m
            - name: ELASTIC_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: elasticsearch-credentials
                  key: password
          ports:
            - containerPort: 9200
          readinessProbe:
            exec:
              command: ["bash", "-c", "curl -sf -u \"elastic:$ELASTIC_PASSWORD\" localhost:9200/_cluster/health"]
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
spec:
  selector:
    app: elasticsearch
  ports:
    - port: 9200

Apply the file:

Deploy Elasticsearch
kubectl apply -f ./elasticsearch.yaml

Verify the Deployments#

It may take a minute or two for the pods to reach a READY state. Check them with kubectl:

Get pods
kubectl get pods -o wide
Output
NAME                             READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
elasticsearch-5ccc6b7c77-vm76w   1/1     Running   0          38s   10.244.0.6   minikube   <none>           <none>
postgres-78cf4d89f8-ppkdj        1/1     Running   0          38s   10.244.0.5   minikube   <none>           <none>

When a Pod is in a status of READY, it means that it is available to serve requests and should be added to load balancing pools of all matching services. You can read more about Pod lifecycles here.

Each Deployment has a Service that exposes it to the rest of the cluster:

Get services
kubectl get services
Output
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
elasticsearch   ClusterIP   10.96.9.215    <none>        9200/TCP   38s
kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP    58s
postgres        ClusterIP   10.96.179.62   <none>        5432/TCP   38s

The kubernetes Service directs traffic to the Kubernetes API server.

Kubernetes DNS#

Kubernetes assigns each Service a DNS name that other pods in the cluster can use:

  • postgres.default.svc.cluster.local
  • elasticsearch.default.svc.cluster.local

For more information, see the Kubernetes documentation for DNS for Services and Pods.

Next Steps#

You now are running all the necessary infrastructure to deploy FusionAuth to minikube. Next up, Deploy FusionAuth in Kubernetes. When you configure the chart in that guide, use these values:

  • database.host: postgres.default.svc.cluster.local
  • database.rootUser.username: postgres, with the PostgreSQL password you chose above as the superuser password
  • search.host: elasticsearch.default.svc.cluster.local
  • search.protocol: http, because this Elasticsearch node doesn't use a certificate
  • The search username elastic, with the Elasticsearch password you chose above