TransWikia.com

How do you get the external ip-address from inside a running Pod in a Kubernetes cluster?

Server Fault Asked by wandawata on November 14, 2021

Some services require their external ip-address as provided by a loadbalancer-object like Metallb at runtime (say for example an LHOST or pasv_address).

Let’s say you have build an image based on Alpine:latest. Attached to the pod, there seems to be no way internal of the running Pod to know which ip-address was assigned to the it by the loadbalancer,

so how do you do get the external ip-address from inside a running Pod in a Kubernetes cluster?

One Answer

And here I'll save you hours of research:

The trick is to use the API provided by the control node in the cluster (which if you are experimenting, is probably the minikube virtualbox vm or a docker container). You can access it as follows:

First create a serviceaccount with which you will gain access to the kubernetes control plane API (the name pod-service-access is completely arbitrary btw):

 kubectl create serviceaccount pod-service-access

Alternatively, you can also create a serviceaccount by applying the following yaml:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-service-access
  namespace: default

Then apply the following ClusterRole and Rolebinding yaml, which will assign permissions to the serviceaccount and bind it to a clusterrole. As you can see, the serviceaccount pod-service-access has read only access to all services in the 'default' namespace. Which is desirable (I presume).

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: read-services
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "watch", "list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-services
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: read-services
subjects:
- kind: ServiceAccount
  name: pod-service-access
  namespace: default

Now you will have to assign the serviceaccount to a deployment, so when the deploynment will spawn pods, these running pods will access the control node api with the permissions of the useraccount. This is an example deployment, pay particular attention the the "serviceAccount: pod-service-access" line and don't forget to install the packages "jq" and "curl" when you build the dockerimage:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vsftpd
  labels:
    app: vsftpd
spec:
  selector:
    matchLabels:
      app: vsftpd
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: vsftpd
    spec:
      serviceAccount: pod-service-access
      containers:
      - image: vsftpd-alpine:v1
        imagePullPolicy: Never
        name: vsftpd
        ports:
        - containerPort: 21
          hostPort: 21
        - containerPort: 21000
          hostPort: 21000
        volumeMounts:
        - name: vsftpd-persistent-storage
          mountPath: /data
        - name: cluster-authentication
          mountPath: /auth
        - name: varlog
          mountPath: /var/log
        - name: certificate
          mountPath: /cert
      volumes:
      - name: vsftpd-persistent-storage
        persistentVolumeClaim:
          claimName: vsftpd-pv-claim
      - name: cluster-authentication
        secret:
          secretName: cluster-authentication
      - name: certificate
        secret:
          secretName: vsftpd-cert
      - name: varlog
        emptyDir: {}

Now, when you have your deployment spawning fresh pods, you'll be able to access the kubernetes control node api. Here is a script which will pull information for the service 'vsftpd' from the api (important: here I assume your service name is the same as your deployment name, as can be seen in the SERVICE= line), and by some jq (json processor) magic extracts the external ip:

#!/bin/sh
# Point to the internal API server hostname
APISERVER=https://kubernetes.default.svc

# Path to ServiceAccount token
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount

# Read this Pod's namespace
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)

# Read the ServiceAccount bearer token
TOKEN=$(cat ${SERVICEACCOUNT}/token)

# Reference the internal certificate authority (CA)
CACERT=${SERVICEACCOUNT}/ca.crt

SERVICE=$(echo $HOSTNAME | cut -d- -f1)

# Explore the API with TOKEN
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/$NAMESPACE/services/$SERVICE/ 2>/dev/null| jq -r '.status | .loadBalancer | .ingress | .[] | .ip'

exit $?

Good luck with ft_services from Codam (ja toch).

Answered by wandawata on November 14, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP