1

I have been trying to create HTTPS endpoint in Google Cloud K8s environment.

I have built a flask application in Python that serves on the waitress production environment via port 5000.

serve(app, host='0.0.0.0', port=5000, ipv6=False, threads=30)

I created a docker file and pushed this to the google cloud repository. Then, created a Kubernetes cluster with one workload containing this image. After, I exposed this via external IP by creating LoadBalancer. (After pushing the image to the Google repository, everything is managed through the Google Cloud Console. I do not have any configuration file, it should be through the Google Cloud Console.)

Now, I do have an exposed IP and port number to access my application. Let's say this IP address and the port is: 11.111.11.222:1111. Now, I can access this IP via Postman and get a result.

My goal is to implement, If it is possible, to expose this IP address via HTTPS as well, by using any google cloud resources. (redirection, creating ingress, etc)

So, in the end I want to reach the application through http://11.111.11.222:111 and https://11.111.11.222:111

Any suggestions?

Sojimanatsu
  • 619
  • 11
  • 28

3 Answers3

0

A LoadBalancer translates to a network load balancer. You can configure multiple ports for this e.g. 80 and 443. Then your application must handle the TLS part.

The ingress resource creates an HTTP(S) LB

Florian
  • 332
  • 2
  • 15
0

From the GKE perspective you can try to configure Ingress resource with HTTPS enabled:

Steps:

  • Create a basic flask app inside a pod (for example purposes only)
  • Expose an app via service object of type nodePort
  • Create a certificate
  • Create an Ingress resource
  • Test
  • Additional information (added by EDIT)

Create a basic flask app inside a pod (for example purposes only)

Below is a flask script which will respond with <h1>Hello!</h1>:

from flask import Flask

app = Flask(__name__)
@app.route("/")

def index():
    return "<h1>Hello!</h1>"

if __name__ == "__main__":
    from waitress import serve
    serve(app, host="0.0.0.0", port=8080)

By default it will respond on port 8080.

Link to an answer with above script.

Expose an app via service object of type nodePort

Assuming that deployment is configured correctly with working app inside, you can expose it via service object type of nodePort with following YAML definition:

apiVersion: v1
kind: Service
metadata:
  name: flask-service
spec:
  type: NodePort
  selector:
    app: ubuntu
  ports:
  - name: flask-port 
    protocol: TCP
    port: 80
    targetPort: 8080 

Please make sure that:

  • selector is configured correctly
  • targetPort is pointing to port which is app is running on

Create a certificate

For Ingress object to work with HTTPS you will need to provide a certificate. You can create it with GKE official documentation on: Cloud.google.com: Managed certificates

Be aware of a fact that you will need a domain name to do that.

Create an Ingress resource

Below is an example Ingress resource which will point your requests to your flask application:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: flask-ingress
  annotations:
    networking.gke.io/managed-certificates: flask-certificate 
    kubernetes.io/ingress.global-static-ip-name: flask-static-ip
spec:
  rules:
  - host: DOMAIN.NAME
    http:
      paths:
      - path: /
        backend:
          serviceName: flask-service
          servicePort: flask-port

Please take a specific look on part of YAML definition below and change accordingly to your case:

    networking.gke.io/managed-certificates: flask-certificate 
    kubernetes.io/ingress.global-static-ip-name: flask-static-ip

Please wait for everything to configure correctly.

After that you will have access to your application by domain.name with ports:

  • 80(http)
  • 443(https)

Currently the Ingress only supports a single TLS port, 443, and assumes TLS termination.

-- Kubernetes.io: Ingress TLS

Test

You can check if above steps are configured correctly by:

  • entering https://DOMAIN.NAME in your web browser and check if it responds with Hello with HTTPS enabled
  • using a tool curl -v https://DOMAIN.NAME.

Please let me know if this solution works for you.

Additional information (added by EDIT)

You can try to configure service object of type LoadBalancer which will be operate at layer 4 as @Florian said in his answer.

Please refer to official documentation: Kubernetes.io: Create external load balancer

You can also use Nginx Ingress controller and either:

Dawid Kruk
  • 8,982
  • 2
  • 22
  • 45
  • I do not have a domain name. I created the self-signed certificate just to replicate the certification. I changed my entire app, running on gunicorn with certificate parameters. When I locally execute the docker image (via my machine IP), I have the https connection and I can get the response. But when I push the same image to google., it converts it automatically to HTTP (I use LoadBalancer to expose it). Any idea why? – Sojimanatsu Mar 11 '20 at 14:51
  • You can try to deploy your own `Nginx Ingress` controller by following: [Nginx Ingress installation](https://kubernetes.github.io/ingress-nginx/deploy/). You would need to change your `Ingress` resource to add `kubernetes.io/ingress.class: "nginx` and refer to: [Nginx Ingress: SSL Passthrough](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#ssl-passthrough) – Dawid Kruk Mar 11 '20 at 16:09
  • Going back to issue with `LoadBalancer`. It would require you to post `YAML` definitions of all what is connected to your use case (deployment, loadbalancer). – Dawid Kruk Mar 11 '20 at 16:11
  • @Sojimanatsu I updated my answer. Please take a look at it. I put more options to expose your application. – Dawid Kruk Mar 12 '20 at 11:33
  • 1
    Hi, @Dawid Kruk, I found solution by changing the server to gunicorn based instead of waitress and just added self-signed certificate. However, my problem is that the UI does give an error for ERR_CERT_COMMON_NAME_INVALID error. Thanks for your help and effort, but I did not use your solution. Google already generates those YAML file and I do not know how to modify them or even should I modify them. – Sojimanatsu Mar 12 '20 at 11:37
0

After researching, I found the answer in Google Cloud Run. It is very simple to deploy HTTP based flask app in the container. As serve(app, host='0.0.0.0', port=5000, ipv6=False, threads=30)(No need for self-certificate or HTTPS in this part, just make sure the HTTP app works) and then push it Cloud Run.

Adjust the service parameters, depend on how much resources do you need to run it. In the machine settings, set the port that you are using in the docker container to be mapped. for instance, in my case, it is 5000. When you create the service, Google provides you a domain address with HTTPS. You can use that URL and access your resources.

That's it!

For more information on Cloud Run: https://cloud.google.com/serverless-options

The differences between computing platforms: https://www.signalfx.com/blog/gcp-serverless-comparison/

Sojimanatsu
  • 619
  • 11
  • 28