Get rid of hard-coded IPs in your Helm charts

DNS resolution in Helm charts can be achieved using the network function getHostByName. Follow this blog post to find out how to do this.

Get rid of hard-coded IPs in your Helm charts
Photo by Lars Kienle / Unsplash

If you don't want to hard-code IP addresses in the values of your Helm Chart you can use the only network function available in Helm called getHostByName. This function enables a dynamic resolution of the IP address for a given Hostname. Follow this blog post to find out how to achieve this for your own Helm charts.

Defining the Template

First, let's take a look at how to define the Template that will use the getHostByName function. In this example I will use a NetworkPolicy to allow external (egress) traffic to a single host. As the default NetworkPolicy object of Kubernetes doesn't allow us to use the fully qualified domain name (FQDN) of the host, we have to use the IP address in the CIDR format.

The CIDR format for a single IP address is the IP address followed by /32 - e.g. 127.0.0.1/32 for localhost. The IP address of our host - that is defined by its FQDN in the attribute hostname - will be resolved using the getHostByName function, which is used like any other function in Helm:

{{ .Values.hostname | getHostByName }}

Next, we need to concatenate these two values to get the full CIDR block for the host. This can be done using the printf function of Helm:

{{ printf "%s/%s" (.Values.hostname | getHostByName) "32" }}

Resolving the hostname

To make Helm resolve the IP address for a given FQDN, you have to add the --enable-dns flag to the helm command used to render the Helm templates, like:

helm template --enable-dns .

Example

Let's assume we want to define a NetworkPolicy like stated above. We would end up with a Helm template like the following:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: networkpolicy-with-dns-resolution
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: {{ printf "%s/%s" (.Values.hostname | getHostByName) "32" | quote }}

If we set the hostname to blog.knell.it using the command helm template --enable-dns --set hostname=blog.knell.it ., it will be resolved during the templating process and a NetworkPolicy using the IP address will be created:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: networkpolicy-with-dns-resolution
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: "172.67.166.85/32"

You can find the source code used in this blog post in my public GitHub Repository.

💡
Want to learn more about Helm or Kubernetes? Then check out my other blog posts for Helm and Kubernetes.