Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could I add a new host to the existing Ingress in kubernetes?

Tags:

kubernetes

As I can see the below page, I can set up two or three hosts in one Ingress. https://kubernetes.io/docs/concepts/services-networking/ingress/#name-based-virtual-hosting

But how do I add a new host to existing ingress? I tried the commands like apply or patch, but it didn't work.

Is there anyone who know this solution?

kubectl patch -f sample-ingress.yml -p ' 
  {"metadata": {"name": "sample-ingress"}, "spec": [{
    "host": "39500000.sample.com",
    "http": {"paths": [{
      "backend": {"serviceName": "39500000", "servicePort": 8080}
    }]
  }}]
}'
The Ingress "sample-ingress" is invalid: spec.backend.serviceName: Required value
like image 705
masudak Avatar asked Apr 24 '17 20:04

masudak


People also ask

What is hosts in ingress?

Ingress host rules The Host field defines the host where the request was sent to. This field is optional and if left blank will match all hosts. The Add Path button adds a new mapping between a request path and the Service resource port. The Path field is the path of the request to match.

Can you have multiple ingress controllers?

If all ingress controllers respect IngressClasses (e.g. multiple instances of ingress-nginx v1. 0), you can deploy two Ingress controllers by granting them control over two different IngressClasses, then selecting one of the two IngressClasses with ingressClassName .


2 Answers

I personally prefer to use PATCH as my preferred approach to add an new host to an existing kubernetes ingress.

The command is going to look like this: kubectl patch ingress my-ingress --type json --patch "$(cat patch.json)"

where patch.json is

[
    {
        "op" : "add" ,
        "path" : "/spec/rules/-" ,
        "value" : {
            "host": "evil.facebook.com",
            "http": {
                "paths": [
                    {
                        "backend": {
                            "serviceName": "tracker-app",
                            "servicePort": 80
                        }
                    }
                ]
            }
        }
    }
]

A few notes: - my-ingress is the name of the deployed ingress in the cluster - one can just paste the json instead of using this trick "$(cat patch.json)"

Also, the main thing about this solution is that it leverages kubernetes own capabilities to merge json according to these rules.

More information patching from an official source can be found here.

like image 168
Leandro Avatar answered Nov 15 '22 08:11

Leandro


Here is my un-edited bash solution for this.

If there is any interest, I can re-write this to make it more transferable. I will leave comments in the script to guide you.

#!/bin/bash
# Update ingress with potential new hosts
# REQUIREMENTS: [An existing ingress with at least one host, and jq installed on host]
kubectl get ingress laravel-ingress -n=gitlab-ci -o json > original_json #CHANGE THIS VALUE TO QUERY YOUR EXISTING INGRESS
existing_hosts=()
exisiting_host_names=()

 # I pass 3 arguments into the script. The first 2 are potential new hosts (if they aren't in the ingress already, and the 3rd arg helps me build the service name)
 API_HOST=$1
 DASHBOARD_HOST=$2
 NAME=$3

name="$NAME"
potential_new_hosts=(
     "$API_HOST"
     "$DASHBOARD_HOST"
)
new_hosts=()

while read -r value
do
  existing_host_names+=("$value")
done < <(cat original_json | jq ['.spec.rules[] | .host'])

# Loop through potential new hosts and add any non-existing ones to a new array.
for potential_new_host in "${potential_new_hosts[@]}"; do
    i=0
    for existing_host in "${existing_host_names[@]}"; do
       if [[ "$existing_host" == "\"$potential_new_host\"," ]] ; then
           i=1
       fi
    done
    if [[ "$i" == 0 ]] ; then
        # A non-existing host, add to an array
        new_hosts+=("$potential_new_host")
    fi
done

while read -r value2
do
  existing_hosts+=("$value2")
done < <(cat original_json | jq ['.spec.rules[] | .'])

# Enable for debugging
#echo "Original json"
#cat original_json
#echo "Existing host names"
#printf '%s\n' "${existing_host_names[@]}"
#echo "New hosts"
#printf '%s\n' "${new_hosts[@]}"
#echo "Existing hosts before adding"
#printf '%s\n' "${existing_hosts[@]}"
#echo "Hosts after adding new ones"
########    

# Begin building of hosts json to patch ingress with
output_json=""
for existing_host in "${existing_hosts[@]}"; do
    output_json=("$output_json$existing_host")
done

# Truncate the last char in our json string (it's a ']', and we want to potentially add to this array for patching
output_json=${output_json::-1}

i=0
for new_host in "${new_hosts[@]}"; do
    # Add to our json object the new host names with my hard-coded config
    output_json=("$output_json,{\"host\":\"$new_host\",\"http\":{ \"paths\": [{ \"backend\":{ \"serviceName\":\"$name-laravel-web\",\"servicePort\":80} } ]} }")
i=1
done
printf '%s]\n' "$output_json" > new_json

if [[  "$i" == 1 ]] ; then
    echo "Ingress json has changed and should be updated."
    echo "OLD:"
    cat original_json
    echo "PATCH: \"spec\": {\"rules\": $output_json]}"
    kubectl patch ingress laravel-ingress -n=gitlab-ci -p="\"spec\": {\"rules\": $output_json]}"
else
    echo "Ingress json has not changed and will not be updated."
fi

Edit (fixed bugs and converted to single host per script execution)

#!/bin/bash
# Update ingress with potential new host
NEW_HOST=$1
INGRESS_NAME=$2
SERVICE_NAME=$3

echo "Running update-ingress for New host: $NEW_HOST, ingress: $INGRESS_NAME, service: $SERVICE_NAME"
echo " Downloading existing ingress config"
kubectl get ingress "$INGRESS_NAME" -n=gitlab-ci -o json > original_json
existing_hosts=()
exisiting_host_names=()

echo " $ kubectl get ingress $INGRESS_NAME -n=gitlab-ci -o json > original json && cat original_json"
cat original_json

name="$SERVICE_NAME"
potential_new_host="$NEW_HOST"
new_hosts=()

echo "Looping through json values1"
cat original_json | jq ['.spec.rules[] | .host']
for value in $(cat original_json | jq ['.spec.rules[] | .host']); 
do 
  # Replace all commas with ""
  value=${value/,/""}
  existing_host_names+=("$value")
  echo "Looping v1: value:$value"
  #printf 'Array: %s' "${existing_host_names[*]}"
done
echo "Right after values1"
i=0
for existing_host in "${existing_host_names[@]}"; do
   echo "Looping through existing host: $existing_host == $potential_new_host"
   if [[ "$existing_host" == "\"$potential_new_host\"" ]] ; then
       i=1
   fi
done
if [[ "$i" == 0 ]] ; then
    new_hosts+=("$potential_new_host")
fi

echo "Looping through json values2"
for value2 in $(cat original_json | jq ['.spec.rules[] | .']);
do
  existing_hosts+=("$value2")
  #echo "existing host! $values2"
  #printf 'Array: %s' "{existing_hosts[*]}"
done

echo "Original json"
#cat original_json

echo "Existing host names"
printf '%s\n' "${existing_host_names[@]}"
echo "New hosts"
printf '%s\n' "${new_hosts[@]}"
echo "Existing hosts before adding"
printf '%s\n' "${existing_hosts[@]}"
echo "Hosts after adding new ones"

output_json=""
for existing_host in "${existing_hosts[@]}"; do
    output_json=("$output_json$existing_host")
done

output_json=${output_json::-1}

i=0
for new_host in "${new_hosts[@]}"; do
    output_json=("$output_json,{\"host\":\"$new_host\",\"http\":{ \"paths\": [{ \"backend\":{ \"serviceName\":\"$SERVICE_NAME-laravel-web\",\"servicePort\":80} }, { \"backend\":{ \"serviceName\":\"$SERVICE_NAME-laravel-web\",\"servicePort\":443} } ]} }")
i=1
done
printf '%s]\n' "$output_json" > new_json

if [[  "$i" == 1 ]] ; then
    echo "Ingress json has changed and should be updated."
    echo "OLD:"
    cat original_json
    echo "PATCH: \"spec\": {\"rules\": $output_json]}"
    kubectl patch ingress "$INGRESS_NAME" -n=gitlab-ci -p="\"spec\": {\"rules\": $output_json]}"
else
    echo "Ingress json has not changed and will not be updated."
fi
like image 29
PoorBob Avatar answered Nov 15 '22 09:11

PoorBob