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