Portainer with k3s
Here's how to integrate Portainer with your k3s home lab, including proper persistence through your NFS share:
1. Create Portainer Namespace and Service Account
kubectl create namespace portainer
kubectl apply -n portainer -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: portainer-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: portainer-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: portainer-sa
namespace: portainer
EOF2. Create Persistent Volume Claim using NFS
# portainer-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: portainer-data
namespace: portainer
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs
resources:
requests:
storage: 5GiApply with kubectl apply -f portainer-pvc.yaml
3. Install Portainer via Helm
helm repo add portainer https://portainer.github.io/k8s/
helm repo update
helm install portainer portainer/portainer \
--namespace portainer \
--set service.type=NodePort \
--set persistence.existingClaim=portainer-data \
--set service.nodePort=30777 \
--set service.port=9000 \
--set tls=false \
--set serviceAccount.create=false \
--set serviceAccount.name=portainer-sa4. Access Portainer Web UI
# Get access URL
echo "http://$(kubectl get node vm1 -o jsonpath='{.status.addresses[0].address}'):30777"5. Initial Setup Walkthrough
- Access the URL from step 4
- Create admin user
- When prompted to connect to environment:
- Select "Kubernetes"
- Choose "Direct connection to the Kubernetes API"
- Portainer will auto-detect the cluster
6. Configure NFS-Backed Storage (Optional)
To make Portainer manage your NFS storage:
- In Portainer UI:
- Go to Environments
- Select your cluster
- Click "Settings"
- Enable "Enable host management features"
- Add Storage Class:
- Go to Cluster -> Storage Classes
- Verify "nfs" class exists
7. Security Considerations 🔒
# Add to helm values
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
ingress:
enabled: true
hosts:
- host: portainer.yourdomain.com
paths:
- path: /
pathType: ImplementationSpecific
tls:
- secretName: portainer-tls
hosts:
- portainer.yourdomain.com8. Backup Configuration
# CronJob for Portainer backups
kubectl apply -n portainer -f - <<EOF
apiVersion: batch/v1
kind: CronJob
meta<blocked>
name: portainer-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: alpine
command:
- /bin/sh
- -c
- |
apk add rsync &&
rsync -av /data/ /mnt/nfs-share/portainer-backups/$(date +\%Y-\%m-\%d)
volumeMounts:
- name: portainer-data
mountPath: /data
- name: nfs-share
mountPath: /mnt/nfs-share
restartPolicy: OnFailure
volumes:
- name: portainer-data
persistentVolumeClaim:
claimName: portainer-data
- name: nfs-share
nfs:
server: 192.168.123.100
path: /mnt/nfs-share
EOF9. Troubleshooting Tips
# Check Portainer logs
kubectl logs -n portainer deployment/portainer
# Verify PVC status
kubectl get pvc -n portainer
# Check node port accessibility
curl -I http://<node-ip>:30777
# Verify NFS mount in pod
kubectl exec -n portainer deployment/portainer -- df -hThis setup gives you:
- Persistent storage through your existing NFS
- Proper RBAC permissions
- Backup system
- Secure access options
- Cluster management through a web UI
Would you like me to add any specific configurations for your applications (Nextcloud, Vaultwarden, etc.) in Portainer?