Skip to content

11. Installing multiple services on MicroK8s

Original Author: Tuukka Peltomäki
Lastmod: 26.9.2025
Status: Ok?

Notes#

  • This guide demonstrates how to deploy multiple services — in this case KAgent and Apache — in a MicroK8s cluster running on a cPouta VM.
  • The setup uses:
  • The VM's floating IP combined with sslip.io to provide easy DNS access,
  • An ExternalName Service to link services between namespaces,
  • Basic Authentication and TLS certificates for secure external access.

Prerequisites#

  • Product platform instructions v2 steps 3 and 8 have been reviewed.
  • MicroK8s cluster is up and running.
  • KAgent installed

1. Installing kagent#

In the KAgent installation guide, we created a kubernetes secret for HTTP basic authentication in the kagent namespace.

Now we also need to create the same secret in the default namespace, since the Ingress is defined there.

1. Install htpasswd if not already installed

sudo dnf install httpd-tools -y

2. Generate the password file if not already created

htpasswd -c auth <USERNAME>

3. Create the secret in both namespaces (kagent and default)

microk8s kubectl create secret generic kagent-basic-auth -n kagent --from-file=auth

microk8s kubectl create secret generic kagent-basic-auth --from-file=auth

2. Deploy Apache and Configure ExternalName Service#

1. Create the Apache deployment, service, and the KAgent ExternalName service in a single YAML file.

This will also include the Ingress and TLS configuration - Remember to check the correct port for KAgent

# Create the Apache deployment and service in the default namespace
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template:
    metadata:
      labels:
        app: apache
    spec:
      containers:
      - name: apache
        image: httpd:2.4
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: apache-service
  namespace: default
spec:
  selector:
    app: apache
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

---
# Create an ExternalName service for KAgent
apiVersion: v1
kind: Service
metadata:
  name: kagent-ui
  namespace: default
spec:
  type: ExternalName
  externalName: kagent-ui.kagent.svc.cluster.local
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

---
# Create the Ingress (HTTP only)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: combined-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: kagent-basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
  ingressClassName: nginx
  rules:
    - host: apache.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: apache-service
                port:
                  number: 80
    - host: kagent.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kagent-ui
                port:
                  number: 8080

2. Apply the .yaml-file

microk8s kubectl apply -f <YAML-FILE-NAME>.yaml

You should now be able to access: - http://apache.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
- http://kagent.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io

3. Enable HTTPS with Let's Encrypt#

  • Note:
  • Before applying the HTTPS configuration, make sure that:
  • The HTTP version works correctly, and
  • The DNS (sslip.io) resolves to your VM’s floating IP.

This ensures that Let’s Encrypt can verify your domain ownership and issue the certificate successfully.

When HTTP is working, you can add TLS-configuration and ClusterIssuer to enable https Add these to your .yaml-file

# Update the Ingress to enable HTTPS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: combined-ingress
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    acme.cert-manager.io/http01-edit-in-place: "true"
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: kagent-basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
  ingressClassName: nginx
  tls:                                                                 # Add these to enable https
    - hosts:                                                           #
        - apache.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io               #
        - kagent.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io               #
      secretName: combined-tls                                         #
  rules:
    - host: apache.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: apache-service
                port:
                  number: 80
    - host: kagent.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kagent-ui
                port:
                  number: 8080
---
# Add this to enable https
# ClusterIssuer (Let's Encrypt)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: <YOUR-EMAIL>
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

You should now be able to access: - https://apache.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io
- https://kagent.<YOUR-FLOATING-IP-WITH-DASHES>.sslip.io

4. Summary#

  • The Apache and KAgent services run in separate namespaces but share a single Ingress.
  • Basic authentication protects both services.
  • HTTPS is enabled via Let's Encrypt and cert-manager.
  • The setup uses sslip.io for automatic domain resolution of the floating IP.