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.
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-quotato see exact accounting. - kubectl not found on master: ensure k3s installed correctly (Day 4).