We are going to deploy Alertmanager to handle alerts sent by our Prometheus server. We will also configure Alertmanager to send alert notifications to our Slack channel using Incoming Webhooks.
Pre-requisites
We are using our Kubernetes homelab to deploy Alertmanager.
A working NFS server is required to create persistent volumes. Note that NFS server configuration is not covered in this article, but the way we set it up can be found here.
Our NFS server IP address is 10.11.1.20, and we have the following export configured for Alertmanager:
/mnt/storage-k8s/nfs/alertmanager
The owner:group of the NFS folder is set to 65534:65534, because of Alertmanager deployment runAsUser: 65534.
Alertmanager and Slack Integration with Incoming Webhooks
Alertmanager uses Incoming Webhooks to post messages into Slack. Add an Incoming Webhooks to your Slack workspace and copy the Webhook URL.
See here for more info: https://lisenet.slack.com/apps/A0F7XDUAZ-incoming-webhooks
Download Files from GitHub
Configuration files used in this article are hosted on GitHub. Clone the following repository:
$ git clone https://github.com/lisenet/kubernetes-homelab.git $ cd ./kubernetes-homelab/
TLDR; Install and Configure Alertmanager: All in One Go
Create a monitoring namespace:
$ kubectl create ns monitoring
Add your Slack Webhook URL to the config map.
Create everything with a single command:
$ kubectl apply -f ./kubernetes/alertmanager/
Note to self: this can be a Helm chart.
Install and Configure Alertmanager: Step by Step
Step by step instructions. Note that this homelab project is under development, therefore please refer to GitHub for any source code changes.
Create a Namespace
Create a monitoring namespace:
$ kubectl create ns monitoring
Create a Cluster Role and a Service Account
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-cluster-role.yml
This is what the code looks like:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: alertmanager
labels:
app: alertmanager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alertmanager
labels:
app: alertmanager
subjects:
- kind: ServiceAccount
name: alertmanager
namespace: monitoring
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alertmanager
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: alertmanager
namespace: monitoring
labels:
app: alertmanager
secrets:
- name: alertmanager-token
Create a Config Map
Configure Alertmanager to use Slack to send alerts. Add your Slack Webhook URL to the config map.
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-config-map.yml
This is what the code looks like:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager
namespace: monitoring
labels:
app: alertmanager
data:
alertmanager.yml: |
global: {}
route:
group_by: ['alertname', 'job']
group_wait: 30s # how long to wait to buffer alerts of the same group before sending a notification initially
group_interval: 1h # how long to wait before sending an alert that has been added to a group for which there has already been a notification
repeat_interval: 30s # how long to wait before re-sending a given alert that has already been sent in a notification
receiver: 'slack_homelab' # default/fallback request handler
# Send severity=warning alerts to slack
routes:
- receiver: slack_homelab
match:
severity: warning
# See https://lisenet.slack.com/apps/A0F7XDUAZ-incoming-webhooks
receivers:
- name: 'slack_homelab'
slack_configs:
- api_url: https://hooks.slack.com/services/XYZXYZXYZ/ABCABCABC/1234567890
channel: '#homelab'
Create a Persistent Volume
We want to keep Alertmanager data and store it on a persistent volume.
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-pv.yml
This is what the code looks like:
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-alertmanager
namespace: monitoring
labels:
app: alertmanager
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /mnt/storage-k8s/nfs/alertmanager
server: 10.11.1.20
Create a Persistent Volume Claim
Allow Alertmanager to request persistent storage.
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-pvc.yml
This is what the code looks like:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc-alertmanager
namespace: monitoring
labels:
app: alertmanager
spec:
storageClassName: nfs
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Create a Deployment Configuration
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-deployment.yml
This is what the code looks like:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: alertmanager
namespace: monitoring
labels:
app: alertmanager
spec:
replicas: 1
selector:
matchLabels:
app: alertmanager
template:
metadata:
labels:
app: alertmanager
spec:
serviceAccountName: alertmanager
serviceAccount: alertmanager
securityContext:
runAsUser: 65534
runAsGroup: 65534
runAsNonRoot: true
fsGroup: 65534
containers:
- name: alertmanager
image: prom/alertmanager:v0.21.0
imagePullPolicy: IfNotPresent
args:
- '--config.file=/etc/config/alertmanager.yml'
- '--storage.path=/data'
- '--cluster.advertise-address=$(POD_IP):6783'
- '--web.external-url=http://localhost:9093'
ports:
- containerPort: 9093
protocol: TCP
env:
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
resources: {}
volumeMounts:
- name: alertmanager-config-volume
mountPath: /etc/config
- name: alertmanager-storage-volume
mountPath: /data
readinessProbe:
httpGet:
path: /-/ready
port: 9093
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 30
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
# See https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
#initContainers:
# - name: fix-nfs-permissions
# image: busybox
# command: ["sh", "-c", "chown -R 65534:65534 /data"]
# securityContext:
# runAsUser: 0
# runAsNonRoot: false
# volumeMounts:
# - name: alertmanager-storage-volume
# mountPath: /data
restartPolicy: Always
terminationGracePeriodSeconds: 30
volumes:
- name: alertmanager-config-volume
configMap:
name: alertmanager
defaultMode: 420
- name: alertmanager-storage-volume
persistentVolumeClaim:
claimName: nfs-pvc-alertmanager
Create a Service
$ kubectl apply -f ./kubernetes/alertmanager/alertmanager-service.yml
This is what the code looks like:
---
apiVersion: v1
kind: Service
metadata:
name: alertmanager
namespace: monitoring
labels:
app: alertmanager
spec:
selector:
app: alertmanager
type: NodePort
ports:
- port: 9093
targetPort: 9093
nodePort: 32093
Check Monitoring Namespace
$ kubectl -n monitoring get all -l app=alertmanager NAME READY STATUS RESTARTS AGE pod/alertmanager-7c698c7668-pjxds 1/1 Running 0 6d1h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/alertmanager NodePort 10.106.163.152 none 9093:32093/TCP 6d4h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/alertmanager 1/1 1 1 6d4h NAME DESIRED CURRENT READY AGE replicaset.apps/alertmanager-7c698c7668 1 1 1 6d4h
Access Alertmanager Dashboard
We can access Alertmanager dashboard by using its service node port 32093.

Slack alerts should look something like this:

