Integrating External APIs and Services with Kubernetes

Scenario: A developer wants to learn how to integrate external APIs and services with applications deployed on Kubernetes. In this example, we will explore the use of Ingress and Kubernetes ConfigMaps to enable communication between external services and Kubernetes applications.

First, let’s review the official Kubernetes documentation on integrating external APIs and services:

  1. Ingress: https://kubernetes.io/docs/concepts/services-networking/ingress/
  2. ConfigMaps: https://kubernetes.io/docs/concepts/configuration/configmaps/

Now, let’s dive into the example.

Assume we have an external API, example-api.com, which our Kubernetes application needs to communicate with. We will create an Ingress resource and a ConfigMap to configure the application.

Step 1: Create a ConfigMap

Create a file named example-api.yaml with the following content:

apiVersion: v1
kind: ConfigMap
metadata:
name: example-api-config
data:
EXTERNAL_API_URL: "https://example-api.com"

Apply the ConfigMap using kubectl:

$ kubectl apply -f example-api.yaml

Step 2: Create an Ingress resource

Create a file named example-api-ingress.yaml with the following content:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-api-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: example-api.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-app
port:
name: http

Replace example-app with the name of your application. This Ingress resource will route all traffic to example-api.com to the example-app service.

Apply the Ingress resource using kubectl:

$ kubectl apply -f example-api-ingress.yaml

Step 3: Update the application

Update your application to use the EXTERNAL_API_URL from the ConfigMap. This can be done by mounting the ConfigMap as a volume or environment variable, depending on your application’s requirements.

For example, if your application is written in Go, you can mount the ConfigMap as a volume:

package main

import (
"fmt"
"io/ioutil"
"os"
)

func main() {
apiURL, _ := os.Getenv("EXTERNAL_API_URL")
if apiURL == "" {
data, _ := ioutil.ReadFile("/etc/config/example-api-config.yaml")
apiURL = string(data)
}
fmt.Println("External API URL:", apiURL)
// Your application logic here
}

Step 4: Test the integration

You can test the integration by accessing your application’s endpoint and making requests to the external API through the Ingress.

$ kubectl get service example-app -o jsonpath='{.status.loadBalancer.ingress[0].ip}' > external-api-ip.txt
$ curl -X GET http://$(cat external-api-ip.txt)/ -H "API-Key: <your-api-key>"

Replace <your-api-key> with a valid API key for the external API.

Tests:

To verify the integration, you can write tests to ensure that your application is correctly accessing the external API through the Ingress and ConfigMap. These tests can include checking the application’s logs for successful API calls or testing the application’s functionality with the external API.

For example, you can write a test script in Go to check the application’s logs for successful API calls:

package main

import (
"context"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"testing"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

func TestExampleApp(t *testing.T) {
// Initialize the Kubernetes client
config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig.yaml")
if err != nil {
t.Fatalf("Failed to build config: %v", err)
}
client, err := kubernetes.NewForConfig(config)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}

// Get the ConfigMap data
configMap, err := client.CoreV1().ConfigMaps("default").Get("example-api-config", metav1.GetOptions{})
if err != nil {
t.Fatalf("Failed to get ConfigMap: %v", err)
}
apiURL := configMap.Data["EXTERNAL_API_URL"]

// Start the application
cmd := exec.Command("go", "run", "./main.go")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
t.Fatalf("Failed to start application: %v", err)
}
defer cmd.Process.Kill()

// Wait for the application to start
time.Sleep(10 * time.Second)

// Send a request to the external API
response, err := http.Get(apiURL)
if err != nil {
t.Fatalf("Failed to send request to external API: %v", err)
}
defer response.Body.Close()

// Check the response status code
if response.StatusCode != http.StatusOK {
t.Fatalf("Received unexpected status code: %d", response.StatusCode)
}

// Check the application's logs for successful API calls
logs, err := cmd.Output()
if err != nil {
t.Fatalf("Failed to read application logs: %v", err)
}
if !strings.Contains(string(logs), "Successfully called external API") {
t.Fatalf("Application logs do not contain 'Successfully called external API'")
}

t.Log("Test passed")
}

Replace /path/to/kubeconfig.yaml with the path to your Kubernetes configuration file. This test script starts the application, sends a request to the external API, and checks the application’s logs for successful API calls.