HomeLab – Namespaces, Limits & Quotas in k3s – Day 5

Goal: Create an apps namespace in k3s, enforce sane defaults with LimitRange and ResourceQuota, and validate behavior via kubectl. All steps run from the control host with Ansible, executing kubectl directly on the master node.

Reference environment: Kubuntu 25 host (fullstacklab.site), SSH user stackadmin; k3s master 192.168.56.10. No kubectl on the host; kubectl runs on the master via Ansible.

Day 5 — Namespaces, Limits & Quotas in k3s
Apply LimitRange & ResourceQuota to the apps namespace

Ansible playbook — bootstrap namespace & policies on master

---
- name: Bootstrap apps namespace and policies on k3s-master (runs kubectl on master)
  hosts: k3s_master
  become: true

  vars:
    ns_name: "apps"
    limitrange_path: "/tmp/limitrange_apps.yaml"
    resourcequota_path: "/tmp/resourcequota_apps.yaml"

  tasks:
    - name: Check if namespace exists
      ansible.builtin.command: kubectl get ns {{ ns_name }}
      register: ns_check
      failed_when: false
      changed_when: false

    - name: Create namespace if missing
      ansible.builtin.command: kubectl create ns {{ ns_name }}
      when: ns_check.rc != 0

    - name: Drop corrected LimitRange manifest (no namespace field)
      ansible.builtin.copy:
        dest: "{{ limitrange_path }}"
        mode: '0644'
        content: |
          apiVersion: v1
          kind: LimitRange
          metadata:
            name: default-limits
          spec:
            limits:
            - type: Container
              default:
                cpu: "500m"
                memory: "256Mi"
              defaultRequest:
                cpu: "100m"
                memory: "128Mi"

    - name: Apply LimitRange into target namespace
      ansible.builtin.command:
        argv:
          - kubectl
          - apply
          - -n
          - "{{ ns_name }}"
          - -f
          - "{{ limitrange_path }}"

    - name: Drop ResourceQuota manifest (no namespace field)
      ansible.builtin.copy:
        dest: "{{ resourcequota_path }}"
        mode: '0644'
        content: |
          apiVersion: v1
          kind: ResourceQuota
          metadata:
            name: apps-quota
          spec:
            hard:
              requests.cpu: "2"
              requests.memory: 2Gi
              limits.cpu: "4"
              limits.memory: 4Gi
              pods: "50"

    - name: Apply ResourceQuota into target namespace
      ansible.builtin.command:
        argv:
          - kubectl
          - apply
          - -n
          - "{{ ns_name }}"
          - -f
          - "{{ resourcequota_path }}"

    - name: Show ns policies summary
      ansible.builtin.command:
        argv:
          - kubectl
          - -n
          - "{{ ns_name }}"
          - get
          - limitrange,resourcequota
      register: ns_summary
      changed_when: false

    - name: Print summary
      ansible.builtin.debug:
        var: ns_summary.stdout

Validation — prove limits & quotas work

ssh stackadmin@192.168.56.10 '
  kubectl -n apps run lr-test --image=nginx --restart=Never -- sleep 3600 && \
  kubectl -n apps wait --for=condition=Ready pod/lr-test --timeout=90s && \
  echo "--- resources (describe)" && \
  kubectl -n apps describe pod lr-test | sed -n "/Limits:/,/Environment:/p" && \
  echo "--- effective resources (jsonpath)" && \
  kubectl -n apps get pod lr-test -o jsonpath="{{.spec.containers[0].resources}}" && echo
  echo "--- quota status" && \
  kubectl -n apps get resourcequota apps-quota -o wide
  cat > /tmp/too-big.yaml << "YAML"
apiVersion: v1
kind: Pod
metadata:
  name: too-big
spec:
  containers:
  - name: c
    image: nginx
    resources:
      requests:
        cpu: "3"
        memory: "200Mi"
      limits:
        cpu: "3"
        memory: "200Mi"
YAML
  kubectl -n apps apply -f /tmp/too-big.yaml || true
  echo "--- recent events" && kubectl -n apps get events --sort-by=.lastTimestamp | tail -n 10
  kubectl -n apps delete pod lr-test --ignore-not-found
  kubectl -n apps delete pod too-big --ignore-not-found
'

Troubleshooting

  • Validation pod never Ready: check node status, image pull, or cluster DNS.
  • Quota math looks wrong: run kubectl -n apps describe resourcequota apps-quota to see exact accounting.
  • kubectl not found on master: ensure k3s installed correctly (Day 4).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.