We are now at a point where we can build our first application that requires some persistence. We are going to start with Tautulli, an application that provides statistics about your Plex server.
We assume that you only have a single server. The state of kubernetes storage is interesting. The easiest way is to simply pass a host path in to the pod, but that doesn’t work when you have multiple nodes. Incidentally, what I do for my day job (Portworx Cloud Architect) is solving these problems for customers. More on that later.
We first need to specify a location to store configuration data. I will use /opt/plexstack/tautulli as an example.
mkdir -p /opt/plexstack/tautulli
Next, let’s take a look at the manifest to install tautulli:
apiVersion: apps/v1
kind: Deployment
metadata:
name: tautulli-deployment
labels:
app: tautulli
spec:
replicas: 1
selector:
matchLabels:
app: tautulli
template:
metadata:
labels:
app: tautulli
spec:
containers:
- name: tautulli
image: ghcr.io/linuxserver/tautulli
env:
- name: PUID
value: "999"
- name: PGID
value: "999"
- name: TZ
value: "America/Los_Angeles"
ports:
- containerPort: 8181
volumeMounts:
- mountPath: /config
name: tautulli-config
volumes:
- name: tautulli-config
hostPath:
path: /opt/plexstack/tautulli
---
kind: Service
apiVersion: v1
metadata:
name: tautulli-service
spec:
selector:
app: tautulli
ports:
- protocol: TCP
port: 8181
targetPort: 8181
type: LoadBalancer
---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ingress-tautulli
namespace: plexstack
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- tautulli.ccrow.org
secretName: tautulli-tls
rules:
- host: tautulli.ccrow.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tautulli-service
port:
number: 8181There is a lot to unpack here:
- The first section is the deployment. It defines the application that will run. Line 19 specifies the image.
- Lines 21 – 26 are environment variables that configure tautulli
- We can see where we specify the /config directory inside the container to be mapped to a host path (lines 29 – 35).
- The next section is the service, which looks for pods with an app selector of tautulli.
- We are also going to provision a load balancer IP address to help with troubleshooting. This could be changed to ClusterIP to be internal only. After all, why go to an ip address when we can use an ingress.
- Tautulli.ccrow.org must resolve to our rancher node through the firewall (a step we already did in the last blog.
Let’s apply the manifest with:
# create the namespace kubectl create namespace plexstack # apply the manifest kubectl -n plexstack apply -f tautulli.yaml # check on the deployment kubectl -n plexstack get all -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/tautulli-deployment-b4d5485df-f28px 1/1 Running 0 45s 10.42.2.30 rke04 <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/tautulli-service LoadBalancer 10.43.36.8 10.0.1.55 8181:31154/TCP 45s app=tautulli NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/tautulli-deployment 1/1 1 1 45s tautulli ghcr.io/linuxserver/tautulli app=tautulli NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR replicaset.apps/tautulli-deployment-b4d5485df 1 1 1 45s tautulli ghcr.io/linuxserver/tautulli app=tautulli,pod-template-hash=b4d5485df
Notice the external IP address that was created for the tautulli-service. You can connect to the app from that IP (be sure to add the 8181 port!) instead of the DNS name.
All configuration data will be stored under /opt/plexstack/tautulli on your node.
Bonus Appplication: smtp
In order for tautulli to send email, we need to set up an SMTP server. This will really show off the power of kubernetes configurations. Take a look at this manifest:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: smtp-deployment
labels:
app: smtp
spec:
replicas: 1
selector:
matchLabels:
app: smtp
template:
metadata:
labels:
app: smtp
spec:
containers:
- name: smtp
image: pure/smtp-relay
env:
- name: SMTP_HOSTNAME
value: "mail.ccrow.org"
- name: RELAY_NETWORKS
value: "10.0.0.0/8"
ports:
- containerPort: 25
---
kind: Service
apiVersion: v1
metadata:
name: smtp-service
spec:
selector:
app: smtp
ports:
- protocol: TCP
port: 25
targetPort: 25
type: ClusterIPYou can apply the above manifest. Be sure to change lines 24 and 26 to match your network. Please note: “Your network” really means your internal kubernetes network. After all, why would we send an email from an external source (well, unless you want to, in which case, change line 41 to loadBalancer).
kubectl -n plexstack apply -f smtp.yaml
We now have a working SMTP server! The coolest part of kubernetes service discovery is being able to simply use the name of our service for any application in the same namespace:

Using the service name means that this configuration is portable, no need to actually plug in the cluster IP address that was assigned.