├── app1 ├── requirements.txt ├── Dockerfile ├── app.py └── templates │ └── index.html ├── app2 ├── requirements.txt ├── Dockerfile └── app.py ├── skaffold.yaml ├── deploy ├── dev.yaml ├── prod.yaml └── pipeline.yaml ├── kubernetes ├── app1.yaml └── app2.yaml ├── cloudbuild.yaml └── README.md /app1/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | tabulate 3 | google-cloud-logging 4 | -------------------------------------------------------------------------------- /app2/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | tabulate 3 | google-cloud-logging 4 | -------------------------------------------------------------------------------- /app1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | 3 | EXPOSE 8080 4 | WORKDIR /app 5 | 6 | COPY . ./ 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | CMD ["python", "app.py"] -------------------------------------------------------------------------------- /app2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | 3 | EXPOSE 8081 4 | WORKDIR /app2 5 | 6 | COPY . ./ 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | CMD ["python", "app.py"] -------------------------------------------------------------------------------- /skaffold.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: skaffold/v4beta9 2 | kind: Config 3 | build: 4 | tagPolicy: 5 | gitCommit: {} 6 | local: {} 7 | manifests: 8 | rawYaml: 9 | - ./kubernetes/* 10 | deploy: 11 | kubectl: {} 12 | logs: 13 | prefix: container 14 | -------------------------------------------------------------------------------- /deploy/dev.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: deploy.cloud.google.com/v1 2 | kind: Target 3 | metadata: 4 | name: dev 5 | annotations: {} 6 | labels: {} 7 | description: dev 8 | gke: 9 | cluster: projects/prj-poc-001/locations/us-central1-c/clusters/cluster-1 10 | 11 | -------------------------------------------------------------------------------- /deploy/prod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: deploy.cloud.google.com/v1 2 | kind: Target 3 | metadata: 4 | name: prod 5 | annotations: {} 6 | labels: {} 7 | description: prod 8 | requireApproval: true 9 | gke: 10 | cluster: projects/prj-poc-001/locations/us-central1-c/clusters/cluster-2 11 | 12 | -------------------------------------------------------------------------------- /app1/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | # Create a Flask application 4 | app = Flask(__name__) 5 | 6 | # Define a route for the root URL 7 | @app.route('/') 8 | def hello_world(): 9 | return 'Hello, World App 1!' 10 | 11 | # Run the Flask application if this file is executed directly 12 | if __name__ == '__main__': 13 | app.run(debug=True, port=8080,host='0.0.0.0') 14 | -------------------------------------------------------------------------------- /app2/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | # Create a Flask application 4 | app = Flask(__name__) 5 | 6 | # Define a route for the root URL 7 | @app.route('/') 8 | def hello_world(): 9 | return 'Hello, World app 2!' 10 | 11 | # Run the Flask application if this file is executed directly 12 | if __name__ == '__main__': 13 | app.run(debug=True, port=8081,host='0.0.0.0') 14 | -------------------------------------------------------------------------------- /deploy/pipeline.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: deploy.cloud.google.com/v1 2 | kind: DeliveryPipeline 3 | metadata: 4 | name: gke-cicd-pipeline 5 | labels: 6 | app: cicd 7 | description: cicd delivery pipeline 8 | serialPipeline: 9 | stages: 10 | - targetId: dev 11 | # profiles: 12 | # - dev 13 | # - targetId: staging 14 | # profiles: 15 | # - staging 16 | - targetId: prod 17 | # profiles: 18 | # - prod -------------------------------------------------------------------------------- /kubernetes/app1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: my-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | containers: 16 | - name: my-container 17 | image: us-central1-docker.pkg.dev/prj-poc-001/gke-repo/quickstart-image 18 | ports: 19 | - containerPort: 8080 20 | 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: my-service 25 | spec: 26 | selector: 27 | app: my-app 28 | ports: 29 | - protocol: TCP 30 | port: 8080 31 | targetPort: 8080 32 | type: LoadBalancer -------------------------------------------------------------------------------- /kubernetes/app2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: flask-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: flask-app 10 | template: 11 | metadata: 12 | labels: 13 | app: flask-app 14 | spec: 15 | containers: 16 | - name: flask-container 17 | image: us-central1-docker.pkg.dev/prj-poc-001/gke-repo/flask-image 18 | ports: 19 | - containerPort: 8081 20 | 21 | --- 22 | 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: flask-service 27 | spec: 28 | selector: 29 | app: flask-app 30 | ports: 31 | - protocol: TCP 32 | port: 8081 33 | targetPort: 8081 34 | type: LoadBalancer -------------------------------------------------------------------------------- /cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: 'gcr.io/cloud-builders/docker' 3 | args: ['build', '-t', 'us-central1-docker.pkg.dev//gke-repo/quickstart-image', './app1' ] 4 | id: 'Build Docker Image' 5 | 6 | # images: 7 | # - 'us-central1-docker.pkg.dev//gke-repo/quickstart-image' 8 | 9 | - name: 'gcr.io/cloud-builders/docker' 10 | args: ['push', 'us-central1-docker.pkg.dev//gke-repo/quickstart-image' ] 11 | id: 'Push Docker Image' 12 | 13 | - name: 'gcr.io/cloud-builders/docker' 14 | args: ['build', '-t', 'us-central1-docker.pkg.dev//gke-repo/flask-image', './app2' ] 15 | id: 'Build Docker Image2' 16 | 17 | # images: 18 | # - 'us-central1-docker.pkg.dev//gke-repo/quickstart-image' 19 | 20 | - name: 'gcr.io/cloud-builders/docker' 21 | args: ['push', 'us-central1-docker.pkg.dev//gke-repo/flask-image' ] 22 | id: 'Push Docker Image2' 23 | 24 | 25 | - name: 'google/cloud-sdk:latest' 26 | entrypoint: 'sh' 27 | args: 28 | - -xe 29 | - -c 30 | - | 31 | gcloud deploy apply --file deploy/pipeline.yaml --region=us-central1 32 | gcloud deploy apply --file deploy/dev.yaml --region=us-central1 33 | gcloud deploy releases create 'app-release-${SHORT_SHA}' --delivery-pipeline=gke-cicd-pipeline --region=us-central1 --skaffold-file=skaffold.yaml 34 | 35 | 36 | options: 37 | logging: CLOUD_LOGGING_ONLY 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CI/CD Pipeline for Deploying Applications on Google Kubernetes Engine (GKE) 2 | 3 | 4 | ## Introduction 5 | 6 | In the modern software development landscape, Continuous Integration/Continuous Deployment (CI/CD) pipelines play a pivotal role in automating the process of building, testing, and deploying applications. In this blog post, we’ll deep dive into the implementation of a robust CI/CD pipeline to deploy applications on Google Kubernetes Engine (GKE) using Google Cloud Build and Cloud Deploy services. 7 | 8 | Video Tutorial : [![YouTube](https://img.shields.io/badge/YouTube-Video-green)](https://youtu.be/L_1qbt-Iii0?feature=shared) 9 | 10 | ## Requirements 11 | 12 | To achieve our goal, we have the following requirements: 13 | - Deployment of two simple Flask applications (app1 & app2) on the GKE clusters. 14 | - Automation of the entire deployment process, triggered by a developer’s code push. 15 | - Dev-cluster deployment precedes production deployment, allowing for review before promoting to the prod-cluster. 16 | 17 | ## Architecture 18 | 19 | ![image](https://github.com/vishal-bulbule/gke-test/assets/143475073/66c914bb-4466-4a23-b977-f0880e1e1f12) 20 | 21 | ## Technical Stack Summary 22 | 23 | This CI/CD pipeline leverages several key components: 24 | - Google Kubernetes Engine (GKE): Google’s managed Kubernetes service, providing a scalable and reliable platform for deploying containerized applications. 25 | - Cloud Build: A fully managed continuous integration and continuous delivery platform that allows developers to build, test, and deploy applications on Google Cloud Platform. 26 | - Cloud Deploy: A service for continuous delivery that automates the deployment of containerized applications to Google Kubernetes Engine and other platforms. 27 | - GitHub: A popular version control platform where developers collaborate, manage, and version control their codebase. 28 | 29 | ## Solution 30 | 31 | We are going to implement the solution using the following steps to implement the CI/CD pipeline for deploying applications on GKE: 32 | 33 | 1. Create two simple Flask applications (app1 & app2). 34 | 2. Set up a GitHub repository and push the application code. 35 | 3. Create two GKE clusters: dev-cluster and prod-cluster, using Google Kubernetes Engine. 36 | 4. Create Kubernetes manifest files in the Kubernetes folder to deploy the application and expose it as a service. 37 | 5. Create skaffold.yaml file now. 38 | 6. Now Create cloudbuild.yaml file to build and push docker images to Artifact registry for both application and Configure a Cloud Build trigger to initiate the pipeline upon code push events in the GitHub repository. 39 | 7. Implement the necessary code to define the Cloud Deploy pipeline and targets for both dev-cluster and prod-cluster. 40 | 8. Push the updated code to the GitHub repository, triggering the Cloud Build and Cloud Deploy processes. 41 | 42 | If you encounter any confusion, please refer to the [Video](https://youtu.be/L_1qbt-Iii0?feature=shared) 43 | linked at the beginning of the blog. 44 | 45 | 46 | -------------------------------------------------------------------------------- /app1/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cricket Scores 5 | 6 | 40 | 41 | 42 | 43 |
44 |
45 | 46 | TechTrapture Cricket Score 47 |
48 |
49 | 55 |
56 |

Recent Matches

57 |
58 | {% for score in cricket_scores %} 59 |
60 |
61 |
62 | {{ score | safe }} 63 |
64 |
65 |
66 | {% endfor %} 67 |
68 | 69 |

Upcoming Matches

70 |
71 | {% for match in upcoming_matches %} 72 |
73 |
74 |
75 |
    76 |
  • 77 | Date: {{ match['Date'] }}
    78 | Description: {{ match['Description'] }}
    79 | Teams: {{ match['Teams'] }} 80 |
  • 81 |
82 |
83 |
84 |
85 | {% endfor %} 86 |
87 |
88 | 89 | 90 | 91 | --------------------------------------------------------------------------------