Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kubernetes - Pass Public IP of Load Balance as Environment Variable into Pod

Gist

I have a ConfigMap which provides necessary environment variables to my pods:

apiVersion: v1
kind: ConfigMap
metadata:
  name: global-config
data:
  NODE_ENV: prod
  LEVEL: info

  # I need to set API_URL to the public IP address of the Load Balancer
  API_URL: http://<SOME IP>:3000

  DATABASE_URL: mongodb://database:27017
  SOME_SERVICE_HOST: some-service:3000

I am running my Kubernetes Cluster on Google Cloud, so it will automatically create a public endpoint for my service:

apiVersion: v1
kind: Service
metadata:
  name: gateway
spec:
  selector:
    app: gateway
  ports:
    - name: http
      port: 3000
      targetPort: 3000
      nodePort: 30000
  type: LoadBalancer

Issue

I have an web application that needs to make HTTP requests from the client's browser to the gateway service. But in order to make a request to the external service, the web app needs to know it's ip address.

So I've set up the pod, which serves the web application in a way, that it picks up an environment variable "API_URL" and as a result makes all HTTP requests to this url.

So I just need a way to set the API_URL environment variable to the public IP address of the gateway service to pass it into a pod when it starts.

like image 905
Flo Avatar asked Oct 16 '19 06:10

Flo


People also ask

How do you pass environment variables in pod?

When you create a Pod, you can set dependent environment variables for the containers that run in the Pod. To set dependent environment variables, you can use $(VAR_NAME) in the value of env in the configuration file.

How do I set a static IP address for Kubernetes LoadBalancer?

To create a LoadBalancer service with the static public IP address, add the loadBalancerIP property and the value of the static public IP address to the YAML manifest. Create a file named load-balancer-service. yaml and copy in the following YAML. Provide your own public IP address created in the previous step.

Can we assign static IP to pod?

All pod IPs must be in the CIDR range for Kubernetes to function correctly. IP pools are ranges of IP addresses from which Calico assigns pod IPs. Static IPs must be in an IP pool.


2 Answers

I know this isn't the exact approach you were going for, but I've found that creating a static IP address and explicitly passing it in tends to be easier to work with.

First, create a static IP address:

gcloud compute addresses create gke-ip --region <region>

where region is the GCP region your GKE cluster is located in.

Then you can get your new IP address with:

gcloud compute addresses describe gke-ip --region <region>

Now you can add your static IP address to your service by specifying an explicit loadBalancerIP.1

apiVersion: v1
kind: Service
metadata:
  name: gateway
spec:
  selector:
    app: gateway
  ports:
    - name: http
      port: 3000
      targetPort: 3000
      nodePort: 30000
  type: LoadBalancer
  loadBalancerIP: "1.2.3.4"

At this point, you can also hard-code it into your ConfigMap and not worry about grabbing the value from the cluster itself.

1If you've already created a LoadBalancer with an auto-assigned IP address, setting an IP address won't change the IP of the underlying GCP load balancer. Instead, you should delete the LoadBalancer service in your cluster, wait ~15 minutes for the underlying GCP resources to get cleaned up, and then recreate the LoadBalancer with the explicit IP address.

like image 140
supersam654 Avatar answered Sep 27 '22 17:09

supersam654


You are trying to access gateway service from client's browser.

I would like to suggest you another solution that is slightly different from what you are currently trying to achieve but it can solve your problem.

From your question I was able to deduce that your web app and gateway app are on the same cluster.

In my solution you dont need a service of type LoadBalancer and basic Ingress is enough to make it work.

You only need to create a Service object (notice that option type: LoadBalancer is now gone)

apiVersion: v1
kind: Service
metadata:
name: gateway
spec:
selector:
  app: gateway
ports:
  - name: http
    port: 3000
    targetPort: 3000
    nodePort: 30000

and you alse need an ingress object (remember that na Ingress Controller needs to be deployed to cluster in order to make it work) like one below: More on how to deploy Nginx Ingress controller you can finde here and if you are already using one (maybe different one) then you can skip this step.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: gateway-ingress
annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
  - host: gateway.foo.bar.com
    http:
      paths:
      - path: /
          backend:
            serviceName: gateway
            servicePort: 3000

Notice the host field.

The same you need to repeat for your web application. Remember to use appropriate host name (DNS name) e.g. for web app: foo.bar.com and for gateway: gateway.foo.bar.com and then just use the gateway.foo.bar.com dns name to connect to the gateway app from clients web browser.

You also need to create a dns entry that points *.foo.bar.com to Ingress's public ip address as Ingress controller will create its own load balancer.

The flow of traffic would be like below:

+-------------+   +---------+   +-----------------+   +---------------------+
| Web Browser |-->| Ingress |-->| gateway Service |-->| gateway application |
+-------------+   +---------+   +-----------------+   +---------------------+

This approach is better becaues it won't cause issues with Cross-Origin Resource Sharing (CORS) in clients browser.

Examples of Ingress and Service manifests I took from official kubernetes documentation and modified slightly.

More on Ingress you can find here and on Services here

like image 32
Matt Avatar answered Sep 27 '22 18:09

Matt