This is an old revision of the document!
Table of Contents
Demonstrate App on k8s
In our previous step we installed Kubernetes (k8s) on our Stack of NUCs.
Now we are going to install a web app and expose it to our internal network.
Purpose:
- Demonstrate a running a web application on Kubernetes
References
Step 1 - Connect to the Kubernetes Master node
Step 2 - Deploy a Distribution
- Create the YAML file to create the distribution
- speedtester-deployment.yml
apiVersion: apps/v1 kind: Deployment metadata: name: speedtester labels: run: speedtester namespace: default spec: selector: matchLabels: run: speedtester replicas: 2 template: metadata: labels: run: speedtester spec: containers: - name: speedtester image: docker.io/doritoes/speedtester:latest livenessProbe: httpGet: path: /favicon.ico port: 80 initialDelaySeconds: 3 periodSeconds: 3
- Apply the definition deployment
kubectl apply -f speedtester-deployment.yml
- View distribution information
kubectl get pods,deployments
kubectl describe deployments speedtester
kubectl get deployment speedtester -o yaml
- Increase number of replicas
- Edit the file speedtester-deployment.yaml to set the number of replicas to the number of Kubernetes worker nodes you have
kubectl apply-f speedtester-deployment.yaml
kubectl get pods -w
kubectl get deployments
kubectl describe deployments speedtester
kubectl get deployment speedtester -o yaml
Step 3 - Create a Service
- Create a service
- Using expose
kubectl expose deployment speedtester --port=8080 --name=speedtester-service --target-port=80
- Removing it
kubctl get svc kubecgtl delete svc speedtester-service
- Using a manifest
- speedtester-service.yml
apiVersion: v1 kind: Service metadata: name: speedtester-service spec: selector: run: speedtester type: NodePort ports: - protocol: TCP port: 8080 targetPort: 80 nodePort: 30080
kubectl apply -f speedtester-service.yml
kubectl get all
kubectl describe svc speedtester-service
Step 4 - Testing Access
Point your web browser on NUC 1 to the IP address of any node and the port we selected, port 300080
Next Step
Congratulations, you have a working Web application on your Kubernetes cluster. Now continue to Install HAProxy.
Optional
Managing Kubernetes using Ansible
Ansible can be used for managing Kubernetes.
https://docs.ansible.com/ansible/latest/collections/kubernetes/core/k8s_module.html
Run from the Ansible control node, NUC 2, in /home/ansible/my-project/k8s/
.
Install python module kubernetes on all nodes
- install-python-kubernetes.yml
--- - hosts: all become: true tasks: - name: Install pip apt: name: python-pip - name: Copy kube-config copy: src: /etc/kubernetes/admin.conf dest remote_src: true - name: Install Kubernetes python package ansible.builtin.pip: name: kubernetes
Creating Namespaces
This an example use case from the documentation.
- namespace.yml
--- - hosts: master become_user: ansible tasks: - name: Create namespace k8s: name: my-namespace api_version: v1 kind: Namespace state: present
ansible-playbook namespace.yml
Deploy with Ansible
This section uses the standard set out at https://opensource.com/article/20/9/ansible-modules-kubernetes.
Note the alternative approach at https://shashwotrisal.medium.com/kubernetes-with-ansible-881f32b8c53e, where the YAML files are copied and used.
Example standard deployment file:
apiVersion: apps/v1 kind: Deployment metadata: name: speedtester labels: run: speedtester spec: selector: matchLabels: run: speedtester replicas: 2 template: metadata: labels: run: speedtester spec: containers: - name: speedtester image: docker.io/doritoes/speedtester:latest livenessProbe: httpGet: path: /favicon.ico port: 80 initialDelaySeconds: 3 periodSeconds: 3
Now we move that YAML into a definition element in your Ansible playbook:
- ansible-deployment.yml
--- - hosts: master become_user: ansible collections: - kubernetes.core tasks: - name: Deploy speedtester2 k8s: state: present definition: api_version: 1 kind: Deployment metadata: name: speedtester2 labels: run: speedtester2 spec: selector: matchLabels: run: speedtester2 replicas: 2 template: metadata: labels: run: speedtester2 spec: containers: - name: speedtester2 image: docker.io/doritoes/speedtester:latest livenessProbe: httpGet: path: /favicon.ico port: 80 initialDelaySeconds: 3 periodSeconds: 3
ansible-playbook ansible-deployment.yml
kubectl get pods
Chaos Testing
Chaos engineering exercises the resiliency of a service by means of randomly or continually interrupting service.
Proper chaos testing: https://opensource.com/article/21/6/chaos-kubernetes-kube-monkey
Some small scale chase testing is outlined below.
Kill Pods
You can watch what's happening a couple of ways:
watch kubectl get pods
kubectl get pods -w
Killing pods:
- watch pods terminating and creating
Rebooting nodes:
- worker nodes show status unknown on pods, then return to running
- once in a while the random selection hits the master node
- watch to see what happens then
Literally kill the first pod in the list
kubectl delete pod $(kubectl get pods -l run=speedtester -o jsonpath='{.items[0].metadata.name}')
Forever loop to keep killing the first pod on the list
while true; do kubectl delete pod $(kubectl get pods -l run=speedtester -o jsonpath='{.items[0].metadata.name}') done
Kill all the current pods
This is slow because the loop structure is sequential.
ansible-playbook deletepod.yml
- deletepod.yml
--- - name: Delete current pods matching speedtester hosts: master become: true become_user: ansible vars: pod_filter: - speedtester # beginning of the pod name gather_facts: false tasks: - name: Get a list of all pods from the namespace command: kubectl get pods --no-headers -o custom-columns=":metadata.name" register: pod_list - name: Print pod names debug: msg: "{{ item }}" loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|')) - name: Delete matching pods command: kubectl delete pod "{{ item }}" loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|'))
Using async we can limit the waiting to see if the command returns.
ansible-playbook deletepod-async.yml
- deletepod-async.yml
--- - name: Delete current pods matching speedtester hosts: master become: true become_user: ansible vars: pod_filter: - speedtester # beginning of the pod name gather_facts: false tasks: - name: Get a list of all pods from the namespace command: kubectl get pods --no-headers -o custom-columns=":metadata.name" register: pod_list - name: Print pod names debug: msg: "{{ item }}" loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|')) - name: Delete matching pods command: kubectl delete pod "{{ item }}" async: 5 # timeout in seconds poll: 1 # poll every second loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|'))
Crash Pods
ansible-playbook killpod-webservice.yml
- killpod-webservice.yml
--- - name: Crash current pods matching speedtester hosts: master become: true become_user: ansible vars: pod_filter: - speedtester # beginning of the pod name gather_facts: false tasks: - name: Get a list of all pods from the namespace command: kubectl get pods --no-headers -o custom-columns=":metadata.name" register: pod_list - name: Print pod names debug: msg: "{{ item }}" loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|')) - name: Crash container by killing supervisord command: kubectl exec "{{ item }}" -- pkill supervisord loop: "{{ pod_list.stdout_lines }}" when: item is match(pod_filter|join('|'))
Reboot a Random Ansible Node
- randomreboot.yml
--- - hosts: localhost connection: local gather_facts: no tasks: - add_host: name: "{{ item }}" groups: limited_selection loop: "{{ (groups['all'] | shuffle)[0:1] }}" - hosts: limited_selection gather_facts: no tasks: - reboot: