Table of contents
Create a Service in GKE and expose it via Endpoint
In this blog we will deploy a sample Service in GKE (Google Kubernetes Service) and to expose it via a custom domain or Google provided domain we will create an Endpoint and expose it publicly.
GCP Services used
- GKE
- Endpoint
Steps Summary
- Create sample FastAPI Service
- Create and build docker image
- Push to docker image to DockerHub
- use GKE kubectl and edit/configure the deployment.yaml file as per our docker image
- Deploy the service
- Create ClusterIP to get public IP
- configure the OpenAPI.yaml file to deploy the Endpoint
- attach the cluster IP with the endpoint
- Test the Endpoint URL in postman or using curl command
Step 1
- Create sample Flask API with a route
First create or install required packages from requirements.txt
pip install -r requirements.txt
requirements.txt
Flask
gunicorn
from flask import Flask,jsonify
app = Flask(__name__)
@app.route("/")
def health():
return jsonify("healthy")
@app.route('/notes')
def hello_world():
data = {
"id":1,
"note":"sample note",
"completed":"true"
}
return jsonify(data)
if __name__ == '__main__':
app.run(host="0.0.0.0")
Once the required packages and code is ready, run it locally and test
python main.py
Step 2 Create Docker file and build the docker image Place all the codes and files in the following structure
sample-api/
--Dockerfile
--requirements.txt
--app/
--main.py
Create a docker file and place the below code Dockerfile
# Select Image
FROM python:3.7.12-slim
# mode to code dir
WORKDIR /code
# copy the requirement.txt file
COPY ./requirements.txt /code/requirements.txt
# run the pip install command
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# copy the app dir
COPY ./app /code/app
# expose the port
EXPOSE 5000
# run the service using uvicorn
CMD ["python","app/main.py"]
to build the docker image run the command , make sure to be in the same directory as the Dockerfile
sudo docker build -t sample-notes:0.1 .
check if the image is build
sudo docker images
to run the docker image and test
sudo docker run -d -p 5000:5000 sample-notes:0.1
a container will be created and to check and list the container id, run the command
sudo docker ps
then to test the api run the curl command
curl -v http://0.0.0.0/notes
the curl will respond back with
{
"id":1,
"note":"sample note",
"completed":"true"
}
if you get similar response then the docker image is built and running
Step 3 Push the docker image to dockerhub to push first you should have a account in dockerhub hub.docker.com and then create a new public repository in my case the repo name is : amanulla1997/sample-notes:0.4
to push docker image to dockerhub run the command
# sudo docker tag local-image:tag docker-repo/repo-name:tag
sudo docker tag sample-notes:0.1 amanulla1997/sample-notes:0.4
# sudo docker push docker-repo/repo-name:tag
sudo docker push amanulla1997/sample-notes:0.4
Step 4 Deploy OpenAPI to create an Endpoint Launch Google Cloud Shell and check if kubectl works create a openapi.yaml file with the following configuration openapi.yaml
# [START swagger]
swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Notes Get Endpoint"
version: "1.0.0"
# host: "<any-string-you-want>.endpoints.<project-id>.cloud.goog"
host: "echo-api.endpoints.<gcp-project-id>.cloud.goog"
# [END swagger]
consumes:
- "application/json"
produces:
- "application/json"
schemes:
# Uncomment the next line if you configure SSL for this API.
# - "https"
- "http"
paths:
"/notes":
get:
description: "Returns the notes information."
operationId: "get_all_notes"
produces:
- "application/json"
responses:
200:
description: "Notes info."
schema:
$ref: "#/definitions/notesResponse"
security:
- api_key: []
google_jwt: []
definitions:
notesResponse:
type: "object"
properties:
id:
title: Id
type: integer
text:
title: Text
type: string
completed:
title: Completed
type: string
According to our service we have one route /notes and we need to create swagger and mention all the routes its types and response type
To deploy the endpoint run the openapi.yaml file using gcloud
gcloud endpoints services deploy openapi.yaml
Once the endpoint is deployed then ignore all the warning and in the end we must see a status something like below
Service Configuration [2017-02-13r0] uploaded for service [echo-api.endpoints.example-project-12345.cloud.goog]
Enable all the services
gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com
gcloud services enable endpoints.googleapis.com
Now we can deploy the Pod using deployment.yaml file
apiVersion: v1
kind: Service
metadata:
name: notes-service
spec:
ports:
- port: 80
targetPort: 5000
protocol: TCP
name: http
selector:
app: notes-service
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: notes-service
spec:
replicas: 1
template:
metadata:
labels:
app: notes-service
spec:
containers:
- name: echo
image: amanulla1997/sample-notes:0.4
ports:
- containerPort: 5000
Deploy this using kubectl
kubectl apply -f deployment.yaml
Once the service is deployed then list the service and get the External IP
kubeclt get svc
Copy the External IP and make changes to the OpenAPI.yaml file and add the host
# [START swagger]
swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Notes Get Endpoint"
version: "1.0.0"
# host: "<any-string-you-want>.endpoints.<project-id>.cloud.goog"
host: "echo-api.endpoints.<gcp-project-id>.cloud.goog"
x-google-endpoints:
# name: "<any-string-you-want>.endpoints.<project-id>.cloud.goog"
- name: "echo-api.endpoints.<gcp-project-id>.cloud.goog"
# target: "External IP"
target: "35.193.26.124"
# [END swagger]
consumes:
- "application/json"
produces:
- "application/json"
schemes:
# Uncomment the next line if you configure SSL for this API.
# - "https"
- "http"
paths:
"/notes":
get:
description: "Returns the notes information."
operationId: "get_all_notes"
produces:
- "application/json"
responses:
200:
description: "Notes info."
schema:
$ref: "#/definitions/notesResponse"
security:
- api_key: []
google_jwt: []
definitions:
notesResponse:
type: "object"
properties:
id:
title: Id
type: integer
text:
title: Text
type: string
completed:
title: Completed
type: string
deploy the openapi endpoint using gcloud
gcloud endpoints services deploy openapi.yaml
copy the endpoint url and create a new container with the endpoint url as service as shown below in deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: notes-service
spec:
ports:
- port: 80
targetPort: 5000
protocol: TCP
name: http
selector:
app: notes-service
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: notes-service
spec:
replicas: 1
template:
metadata:
labels:
app: notes-service
spec:
containers:
# [START esp]
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:1
args: [
"--http_port=80",
"--backend=127.0.0.1:5000",
# --service=endpoint url
"--service=echo-api.endpoints.<gcp-project-id>.cloud.goog",
"--rollout_strategy=managed",
]
# [END esp]
ports:
- containerPort: 5000
- name: echo
image: amanulla1997/sample-notes:0.4
ports:
- containerPort: 5000
deploy the deployment.yaml file again using kubectl
kubectl apply -f deployment.yaml
After this test the service using endpoint url
curl -v echo-api.endpoints.<gcp-project-id>.cloud.goog/notes