Create  a Service in GKE and expose it via Google Endpoint

Create a Service in GKE and expose it via Google Endpoint

Create a Service in GKE and expose it via Endpoint

GKE and 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

main.py

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

2.png 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