Deploying the Docker Application and mysql with Volume Support into Kubernetes. (From code to Docker Registries like ACR/ECR and then to EKS/AKS)

Deploying Python Flask Rest Application to Kubernetes

  • In this series we would take a simple python flask Application with the architecture as shown below

Preview

  • The code of this application is hosted over here

Understanding Application Execution

  • Before we build the docker image for this application, lets understand the steps for executing this application.
  • Ensure python3 and pip is installed and then execute the following commands in the terminal
git clone https://github.com/DevProjectsForDevOps/StudentCoursesRestAPI.git
cd StudentCoursesRestAPI
pip install -r requirements.txt
python app.py
  • This application is configured to run on port 8080. so navigate to the http://<ip address>:8080. Home page will be launched with swagger ui, where the apis can be executed. Preview

Building Docker Image for this application

  • Based on the steps mentioned over the above section, we need a source docker image with python3 and pip
  • I would be using official python image with tag 3.7-alpine.
  • Dockerfile will have the following contents
FROM python:3.7-alpine
LABEL author=KHAJA
LABEL blog=directdevops.blog
ARG HOME_DIR='/studentcourses'
ADD . $HOME_DIR
ENV MYSQL_USERNAME='directdevops'
ENV MYSQL_PASSWORD='directdevops'
ENV MYSQL_SERVER='localhost'
ENV MYSQL_SERVER_PORT='3306'
ENV MYSQL_DATABASE='test'
EXPOSE 8080
WORKDIR $HOME_DIR
RUN pip install -r requirements.txt
ENTRYPOINT ["python", "app.py"]
  • Now build the image using the following command
docker build image -t studentcourserestservice:1.0 .
  • Now to test this image we need the mysql container from here to be created. Lets create the mysql container using the following command
docker container run -d --name mysql -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test -e MYSQL_USER=directdevops -e MYSQL_PASSWORD=directdevops mysql:5.6
  • Find the ip address of the mysql container using
docker inspect mysql | grep IPAddress

and make the note of ip. (In my case it is 172.17.0.2)

  • Now create a container with studentcourserestservice image using the following command
docker container run -d --name mypythonapp -e MYSQL_SERVER=172.17.0.2 -p 8080:8080 studentcourserestservice:1.0
  • Now navigate to http:<ip address>:8080 and initialize database and select Execute button Preview

  • Now create a sample course by using post request and test it with Get

  • Now if every thing is working we are good for pushing this image to our registry.

  • I will be pushing this images to AWS Elastic container registry

Registry Creation in AWS and pushing image to AWS Elastic Container Registry

  • Create Registry in AWS following instructions from here
  • Install AWS-CLI on the machine by following instructions from here and create the iam user refer here
  • Execute the following command
aws ecr get-login
  • Now execute the docker login command that was returned on the execution of previous command. remove -e None from the previous command in case of errors
  • Create repository in ECR with name studentcourserestservice
  • Create one more repository in ECR with mysql
  • Now lets tag our image with latest and version 1.0
docker image tag studentcourserestservice:1.0 <awsaccountid>.dkr.ecr.us-west-2.amazonaws.com/studentcourserestservice:1.0 <awsaccountid>.dkr.ecr.us-west-2.amazonaws.com/mysql:5.6

docker image tag mysql:5.6
  • Push both the images to ecr registry
docker push <awsaccountid>.dkr.ecr.us-west-2.amazonaws.com/studentcourserestservice:1.0
docker push <awsaccountid>.dkr.ecr.us-west-2.amazonaws.com/mysql:5.6

Registry Creation in Azure and pushing the image to Azure Container Registy

  • Create Registry in Azure following instructions from here
  • Install Azure cli by following instructions from here
  • Now from Azure cli enter the following command with the name of registry (i will be using directdevops)
az acr login --name <nameofrepository>

az acr login --name directdevops
  • Now lets tag our image to azure registry name <acrLoginSever>/<image>:<tag>
docker image tag studentcourserestservice:1.0 directdevops.azurecr.io/studentcourserestservice:1.0
  • Push the image the azure registry
docker image push directdevops.azurecr.io/studentcourserestservice:1.0

Now Create an EKS Cluster and use the Elastic Container Registry

  • Create an eks cluster by following instructions from here
  • In this series i will be using eksctl cli to create the cluster
  • Install eksctl by following instructions from here
  • create a kubernetes cluster with 2 nodes in the us-west-2 region by entering the following command and wait for approximately 10 minutes
eksctl create cluster --name learning --version 1.14 --region us-west-2 \
--nodegroup-name direct-devops --node-type t2.medium --nodes 2 --nodes-min 1 \
--nodes-max 5 --node-ami auto

How about the mysql Storage?

  • We will be using mysql:5.7 as the backend of this application and the data stored in mysql needs to be preserved, so we need to use the Volumes.
  • Once the kubernetes cluster is created we would need the persistent volume for the mysql container.
  • Creating a Storage Class specification with aws-ebs provisioner in a file called aws-storage-class.yml. Refer here for complete info
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
  provisioner: kubernetes.io/aws-ebs
  parameters:
    type: gp2
    fsType: ext4
    zones: us-west-2a, us-west-2b, us-west-2c
  • Now create storage class by kubectl apply command
kubectl apply -f aws-storage-class.yml
  • Now create a Persistent Volume Claim specification in a file called as aws-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-gp2
  labels:
    app: mysql
spec:
  storageClassName: gp2
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  • Now create a mysql deployment specification in a file called aws-mysql-deploy.yml
apiVersion: v1
kind: Pod
metadata:
  name: mysql-pod
  labels:
    app: mysql
  spec:
    containers:
      - name: mysql
        image: 798279872530.dkr.ecr.us-west-2.amazonaws.com/mysql:5.7
        volumeMounts:
          - mountPath: "/var/lib/mysql"
            persistentVolumeClaim:
              claimName: ebs-gp2
        env:
          - name: MYSQL_DATABASE
            value: 'test'
          - name: MYSQL_USER
            value: 'directdevops'
          - name: MYSQL_PASSWORD
            value: 'directdevops'
          - name: MYSQL_ROOT_PASSWORD
            value: 'password'
        ports:
          - name: dbport
            containerPort: 3306
            protocol: TCP
  • Now create a specification for service called aws-backend-svc.yml
apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  labels:
    app: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
  clusterIP: None
  • Better thing would be to combine all of the above in one file called as mysql-aws.yml with following content
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  labels:
    app: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
  clusterIP: None
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  fsType: ext4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-gp2
  labels:
    app: mysql
spec:
  storageClassName: gp2
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
spec:
  replicas: 1
  minReadySeconds: 10
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: 798279872530.dkr.ecr.us-west-2.amazonaws.com/mysql:5.6
          volumeMounts:
            - mountPath: "/var/lib/mysql"
              name: mysql-vol
          env:
            - name: MYSQL_DATABASE
              value: 'test'
            - name: MYSQL_USER
              value: 'directdevops'
            - name: MYSQL_PASSWORD
              value: 'directdevops'
            - name: MYSQL_ROOT_PASSWORD
              value: 'password'
          ports:
            - name: dbport
              containerPort: 3306
              protocol: TCP
      volumes:
        - name: mysql-vol
          persistentVolumeClaim:
            claimName: ebs-gp2

  • Now execute the command kubectl apply -f mysql-aws.yml

  • Now lets create a deployment and service for the python flask application. Remember we need to set the MYSQL_SERVER environment variable and we will be passing the mysql-svc name over here

---
apiVersion: v1
kind: Service
metadata:
  name: studentcourse-svc
  labels:
    app: studentscourse
spec:
  ports:
    - port: 8080
  selector:
    app: studentscourse
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: studentcourse-deploy
  labels:
    app: studentscourse
spec:
  replicas: 5
  selector:
    matchLabels:
      app: studentscourse
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 1
  template:
    metadata:
      labels:
        app: studentscourse
    spec:
      containers:
        - image: 798279872530.dkr.ecr.us-west-2.amazonaws.com/studentcourserestservice
          name: studentscourse
          env:
            - name: MYSQL_SERVER
              value: mysql-svc
          ports:
            - containerPort: 8080
              name: flaskport

  • Now execute the following commands
kubectl apply -f flask-aws.yml
kubectl get svc
  • In the svc command output you should the load balancer ip.
  • Navigate to the application using http:<loadbalancer>:port. In the image shown below, the port exposed on load balancer is 8080 Preview
  • Now delete the kubernetes objects created and delete the cluster using eksctl.
  • Now from the knowledge achieved from this exercise, try creating the similar deployment into Azure Kubernetes Services

Leave a Reply

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

About continuous learner

devops & cloud enthusiastic learner