Docker + Kubernetes + Ansible
-----------------------------------------------------------------------------------------------------------------------------
Web Application Deployment using Kubernetes and Ansible
A Flask application named "application.py" is given in the path
Run the given setup.sh file given in the path to install the required dependencies be the challenge.
1. Start Minikube and sync host Docker with Minikube Docker.
Note: If you get any errors while starting Minikube, please do try again by running the command to start Minikube.
2. Create a Dockerfile in the path and dockerize the given 'Flask' application as 'webapp-img'
using 'python:alpine3.7' as its base image.
3. Create a 'deployment.yml' file in the path to create a Kubernetes deployment object named "web-deployment" with 3 replicas which uses the 'webapp-img' and runs a container named "webapp-container". Add Label "app=webapp" and namespace 'web' to this deployment object.
4. Create a 'service.yml' file in the path to create a Kubernetes service named 'web-service' of type LoadBalancer to expose the Flask application: Add a namespace 'web' to this service.
5. Create a 'statefulset.yml' file in the path to create a Kubernetes statefulset named "db-statefulset" with 3 replicas and service name 'db'. This should use the 'mysql:5.6' image and run a container named 'db-container' on port 3386
Set environmental variables "MYSQL_ROOT_PASSWORD" and "MYSQL_USER" by referencing Kubernetes secrets and "MYSQL_DATABASE" as 'db application'. Mount it to a volume named 'db-persistent-storage' which claims the storage using a persistent volume claim named 'db-persistent-claim' and add label 'app-db-mysql' and namespace 'web' to this statefulset.
6. Create an Ansible playbook named 'playbook.yml' in the path to automate the following tasks. Creates a Kubernetes namespace named 'web' using inline definition.
- Create a Kubernetes immutable secret named 'deploy-secret of type basic authentication with username as "admin" and password as "admin123" using inline definition.
- Create a Kubernetes Persistent volume claim named 'db-persistent-claim with a storage size of 2061, RWD access mode, add label 'app-db-mysql' and namespace 'web' using inline definition.
Create a Statefulset object by invoking the statefulset.yml file. Create a deployment object by invoking the 'deployment.yml' file.
Create a service by invoking the service.yml file.
7. Finally, run the Ansible playbook and check whether the kubernetes objects are created and the application has been deployed & exposed externally using LoadBalancer.
-----------------------------------------------------------------------------------------------------------------------------
SOLUTION:
-----------------------------------------------------------------------------------------------------------------------------
Dockerfile
FROM python:alpine3.7
WORKDIR /app
COPY ./app /app
RUN pip install -r requirements.txt
EXPOSE 8080
# ENV FLASK_APP=app.py
# ENV FLASK_RUN_HOST=0.0.0.0
# ENV FLASK_RUN_PORT=5005
# CMD ["flask", "run"]
CMD ["python3", "app.py"]
deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
namespace: web
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: web-container
image: webapp-img:latest
imagePullPolicy: Never
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 8080
# command: ["flask", "run"]
service.yml
apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: web
spec:
selector:
app: webapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
externalIPs:
- 192.168.49.2
seceret.yml (optional)
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
mysql-user: bXlzcWx1c2Vy
mysql-password: bXlzcWxwd2Q=
statefulset.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: db-persistent-storage
spec:
capacity:
storage: 500Mi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /home/ubuntu1804/mysql
server: localhost
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db-statefulset
# namespace: web
spec:
replicas: 1
serviceName: db
selector:
matchLabels:
app: db-mysql
template:
metadata:
labels:
app: db-mysql
spec:
containers:
- name: db-container
image: mysql:5.6
ports:
- containerPort: 3306
name: web
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: mysql-password
name: deploy-secret
- name: MYSQL_USER
valueFrom:
secretKeyRef:
key: mysql-user
name: deploy-secret
- name: MYSQL_DATABASE
value: db_application
volumeMounts:
- name: db-persistent-claim
mountPath: /home/ubuntu1804/mysql
volumeClaimTemplates:
- metadata:
name: db-persistent-claim
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
playbook.yml
# code: language=ansible
---
- name: Automate Docker and K8 build and deploy
hosts: localhost
vars:
dockerimg: webapp-img
tasks:
- name: Build Docker Image
ansible.builtin.docker_image:
path: .
name: "{{ dockerimg }}"
tag: latest
state: present
- name: Check if minikube running
command: minikube status
register: minikube_status
ignore_errors: true
- name: Start minikube if not running
command: minikube start
when: "'Running' not in minikube_status.stdout"
- name: Load Docker image to minikube
command: "minikube image load {{ dockerimg }}"
ignore_errors: true
- name: Create 'web' namespace in k8
command: minikube kubectl -- create namespace web
ignore_errors: true
- name: Create Service in k8
command: minikube kubectl -- apply -f service.yml
ignore_errors: true
- name: Create Deployment in k8
command: minikube kubectl -- apply -f deployment.yml
ignore_errors: true
- name: Create Secrets in k8
command: minikube kubectl -- create secret generic deploy-secret --from-literal=mysql-user=admin --from-literal=mysql-password=admin123
ignore_errors: true
- name: Create Statefulset in k8
command: minikube kubectl -- apply -f statefulset.yml
ignore_errors: true
Commands
# docker
docker build -t webapp-img .
docker ps -a
# minikube
minikube start
minikube image load webapp-img
alias kubectl="minikube kubectl --"
kubectl create namespace web
kubectl apply -f service.yml
kubectl apply -f deployment.yml
# check if external ip is present
kubectl get all -n web
kubectl create secret generic deploy-secret --from-literal=mysql-user=admin --from-literal=mysql-password=admin123
kubectl apply -f statefulset.yml
kubectl get statefulset db-statefulset
Comments