Giter Site home page Giter Site logo

redhat-cop / keepalived-operator Goto Github PK

View Code? Open in Web Editor NEW
117.0 19.0 35.0 8.03 MB

An operator to manage VIPs backed by keepalived

License: Apache License 2.0

Makefile 25.87% Dockerfile 3.21% Shell 1.88% Smarty 8.36% Go 55.98% Mustache 2.73% Python 1.97%
k8s-operator container-cop

keepalived-operator's Introduction

Keepalived operator

build status Go Report Card GitHub go.mod Go version

The objective of the keepalived operator is to allow for a way to create self-hosted load balancers in an automated way. From a user experience point of view the behavior is the same as of when creating LoadBalancer services with a cloud provider able to manage them.

The keepalived operator can be used in all environments that allows nodes to advertise additional IPs on their NICs (and at least for now, in networks that allow multicast), however it's mainly aimed at supporting LoadBalancer services and ExternalIPs on bare metal installations (or other installation environments where a cloud provider is not available).

One possible use of the keepalived operator is also to support OpenShift Ingresses in environments where an external load balancer cannot be provisioned. See this how-to on how to configure keepalived-operator to support OpenShift ingresses

How it works

The keepalived operator will create one or more VIPs (an HA IP that floats between multiple nodes), based on the LoadBalancer services and/or services requesting ExternalIPs.

For LoadBalancer services the IPs found at .Status.LoadBalancer.Ingress[].IP will become VIPs.

For services requesting a ExternalIPs, the IPs found at .Spec.ExternalIPs[] will become VIPs.

Note that a service can be of LoadBalancer type and also request ExternalIPs, it this case both sets of IPs will become VIPs.

Due to a keepalived limitation a single keepalived cluster can manage up to 256 VIP configurations. Multiple keepalived clusters can coexists in the same network as long as they use different multicast ports [TODO verify this statement].

To address this limitation the KeepalivedGroup CRD has been introduced. This CRD is supposed to be configured by an administrator and allows you to specify a node selector to pick on which nodes the keepalived pods should be deployed. Here is an example:

apiVersion: redhatcop.redhat.io/v1alpha1
kind: KeepalivedGroup
metadata:
  name: keepalivedgroup-router
spec:
  image: registry.redhat.io/openshift4/ose-keepalived-ipfailover
  interface: ens3
  nodeSelector:
    node-role.kubernetes.io/loadbalancer: ""
  blacklistRouterIDs:
  - 1
  - 2  

This KeepalivedGroup will be deployed on all the nodes with role loadbalancer. Keepalived requires knowledge of the network device on which the VIPs will be exposed. If the interface name is the same on all nodes, it can be specified in the interface field. Alternatively, the interfaceFromIP field can be set to an IPv4 address to enable interface autodiscovery. In this scenario, the interface field will be ignored and each node in the KeepalivedGroup will expose the VIPs on the interface that would be used to reach the provided IP.

Services must be annotated to opt-in to being observed by the keepalived operator and to specify which KeepalivedGroup they refer to. The annotation looks like this:

keepalived-operator.redhat-cop.io/keepalivedgroup: <keepalivedgroup namespace>/<keepalivedgroup-name>

The image used for the keepalived containers can be specified with .Spec.Image it will default to registry.redhat.io/openshift4/ose-keepalived-ipfailover if undefined.

Requirements

Security Context Constraints

Each KeepalivedGroup deploys a daemonset that requires the privileged scc, this permission must be given to the default service account in the namespace where the keepalived group is created by and administrator.

oc adm policy add-scc-to-user privileged -z default-n <keepalivedgroup namespace>

Cluster Network Operator

In Openshift, use of an external IP address is governed by the following fields in the Network.config.openshift.io CR named cluster

  • spec.externalIP.autoAssignCIDRs defines an IP address block used by the load balancer when choosing an external IP address for the service. OpenShift supports only a single IP address block for automatic assignment.

  • spec.externalIP.policy defines the permissible IP address blocks when manually specifying an IP address. OpenShift does not apply policy rules to IP address blocks defined by spec.externalIP.autoAssignCIDRs

The following patch can be used to configure the Cluster Network Operator:

spec:
  externalIP:
    policy:
      allowedCIDRs:
      - ${ALLOWED_CIDR}
    autoAssignCIDRs:
      - "${AUTOASSIGNED_CIDR}"

Here is an example of how to apply the patch:

export ALLOWED_CIDR="192.168.131.128/26"
export AUTOASSIGNED_CIDR="192.168.131.192/26"
oc patch network cluster -p "$(envsubst < ./network-patch.yaml | yq r -j -)" --type=merge

Additionally, the fields can be edited manually via oc edit Network.config.openshift.io cluster

Blacklisting router IDs

If the Keepalived pods are deployed on nodes which are in the same network (same broadcast domain to be precise) with other keepalived the process, it's necessary to ensure that there is no collision between the used routers it. For this purpose it is possible to provide a blacklistRouterIDs field with a list of black-listed IDs that will not be used.

Spreading VIPs across nodes to maximize load balancing

If a service contains multiple externalIPs or LoadBalancer IPs, it is possible to instruct keepalived-operator to maximize the spread of such VIPs across the nodes in the KeepalivedGroup by specifying the keepalived-operator.redhat-cop.io/spreadvips: "true" annotation on the service. This option ensures that different VIPs for the same service are always owned by different nodes (or, if the number of nodes in the group is less than the number of VIPs, that the VIPs are assigned maximizing the spread), to avoid creating a traffic bottleneck. However, in order to achieve this, keepalived-operator will create a separate VRRP instance per VIP of that service, which could exhaust the 256 available instances faster.

OpenShift RHV, vSphere, OSP and bare metal IPI instructions

When IPI is used for RHV, vSphere, OSP or bare metal platforms, three keepalived VIPs are deployed. To make sure that keepalived-operator can work in these environment we need to discover and blacklist the corresponding VRRP router IDs.

To discover the VRRP router IDs being used, run the following command, you can run this command from you laptop:

podman run quay.io/openshift/origin-baremetal-runtimecfg:4.5 vr-ids <cluster_name>

If you don't know your cluster name, run this command:

podman run quay.io/openshift/origin-baremetal-runtimecfg:4.5 vr-ids $(oc get cm cluster-config-v1 -n kube-system -o jsonpath='{.data.install-config}'| yq -r .metadata.name)

Then use these instructions to blacklist those VRRP router IDs.

Verbatim Configurations

Keepalived has dozens of configurations. At the early stage of this project it's difficult to tell which one should be modeled in the API. Yet, users of this project may still need to use them. To account for that there is a way to pass verbatim options both at the keepalived group level (which maps to the keepalived config global_defs section) and at the service level (which maps to the keepalived config vrrp_instance section).

KeepalivedGroup-level verbatim configurations can be passed as in the following example:

apiVersion: redhatcop.redhat.io/v1alpha1
kind: KeepalivedGroup
metadata:
  name: keepalivedgroup-router
spec:
  interface: ens3
  nodeSelector:
    node-role.kubernetes.io/loadbalancer: ""
  verbatimConfig:  
    vrrp_iptables: my-keepalived

this will map to the following global_defs:

    global_defs {
        router_id keepalivedgroup-router
        vrrp_iptables my-keepalived
    }

Service-level verbatim configurations can be passed as in the following example:

apiVersion: v1
kind: Service
metadata:
  annotations:
    keepalived-operator.redhat-cop.io/keepalivedgroup: keepalived-operator/keepalivedgroup-router
    keepalived-operator.redhat-cop.io/verbatimconfig: '{ "track_src_ip": "" }'

this will map to the following vrrp_instance section

    vrrp_instance openshift-ingress/router-default {
        interface ens3
        virtual_router_id 1  
        virtual_ipaddress {
          192.168.131.129
        }
        track_src_ip
    }

Advanced Users Only: Override Keepalived Configuration Template

NOTE: This config customization feature can only be used via Helm.

Each of the Keepalived daemon pods gets received it's configuration from a ConfigMap that gets generated by the Keepalived Operator from a configuration file template. If you need to customize the configuration for your Keepalived daemon pods, you'll want to use the following steps.

Create a ConfigMap with the full contents of this configuration template file: https://github.com/redhat-cop/keepalived-operator/blob/master/config/templates/keepalived-template.yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: keepalived-template
namespace: {{ .KeepalivedGroup.ObjectMeta.Namespace }}
labels:
  keepalivedGroup: {{ .KeepalivedGroup.ObjectMeta.Name }}    
data: 
keepalived.conf: |
    ...
    # expected merge structure
    # .KeepAlivedGroup
    # .Services
    - apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: {{ .KeepalivedGroup.ObjectMeta.Name }}
        namespace: {{ .KeepalivedGroup.ObjectMeta.Namespace }}
      spec:
    ...

Then in the Helm Chart set keepalivedTemplateFromConfigMap: keepalived-template

This will override the /templates/keepalived-template.yaml config file in the keepalived-operator pod which will allow you to update the configs without having to rebuild/push the operator docker image.

Metrics collection

Each keepalived pod exposes a Prometheus metrics port at 9650. Metrics are collected with keepalived_exporter, the available metrics are described in the project documentation.

When a keepalived group is created a PodMonitor rule to collect those metrics. All PodMonitor resources created that way have the label: metrics: keepalived. It is up to you to make sure your Prometheus instance watches for those PodMonitor rules. Here is an example of a fragment of a Prometheus CR configured to collect the keepalived pod metrics:

  podMonitorSelector:
    matchLabels:
      metrics: keepalived

In order to enable the collection of these metrics by the platform prometheus you have to appropriately label the namespace in which the KeepalivedGroup CR was created:

oc label namespace <keepalived-group namespace> openshift.io/cluster-monitoring="true"

Deploying the Operator

This is a cluster-level operator that you can deploy in any namespace, keepalived-operator is recommended.

It is recommended to deploy this operator via OperatorHub, but you can also deploy it using Helm.

Multiarch Support

Arch Support
amd64
arm64
ppc64le
s390x

Deploying from OperatorHub

Note: This operator supports being installed disconnected environments

If you want to utilize the Operator Lifecycle Manager (OLM) to install this operator, you can do so in two ways: from the UI or the CLI.

Deploying from OperatorHub UI

  • If you would like to launch this operator from the UI, you'll need to navigate to the OperatorHub tab in the console.Before starting, make sure you've created the namespace that you want to install this operator to with the following:
oc new-project keepalived-operator
  • Once there, you can search for this operator by name: keepalived. This will then return an item for our operator and you can select it to get started. Once you've arrived here, you'll be presented with an option to install, which will begin the process.
  • After clicking the install button, you can then select the namespace that you would like to install this to as well as the installation strategy you would like to proceed with (Automatic or Manual).
  • Once you've made your selection, you can select Subscribe and the installation will begin. After a few moments you can go ahead and check your namespace and you should see the operator running.

Keepalived Operator

Deploying from OperatorHub using CLI

If you'd like to launch this operator from the command line, you can use the manifests contained in this repository by running the following:

oc new-project keepalived-operator
oc apply -f config/operatorhub -n keepalived-operator

This will create the appropriate OperatorGroup and Subscription and will trigger OLM to launch the operator in the specified namespace.

Deploying with Helm

Here are the instructions to install the latest release with Helm.

oc new-project keepalived-operator
helm repo add keepalived-operator https://redhat-cop.github.io/keepalived-operator
helm repo update
helm install keepalived-operator keepalived-operator/keepalived-operator

This can later be updated with the following commands:

helm repo update
helm upgrade keepalived-operator keepalived-operator/keepalived-operator

Metrics

Prometheus compatible metrics are exposed by the Operator and can be integrated into OpenShift's default cluster monitoring. To enable OpenShift cluster monitoring, label the namespace the operator is deployed in with the label openshift.io/cluster-monitoring="true".

oc label namespace <namespace> openshift.io/cluster-monitoring="true"

Testing metrics

export operatorNamespace=keepalived-operator-local # or keepalived-operator
oc label namespace ${operatorNamespace} openshift.io/cluster-monitoring="true"
oc rsh -n openshift-monitoring -c prometheus prometheus-k8s-0 /bin/bash
export operatorNamespace=keepalived-operator-local # or keepalived-operator
curl -v -s -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://keepalived-operator-controller-manager-metrics.${operatorNamespace}.svc.cluster.local:8443/metrics
exit

Development

Running the operator locally

Note: this operator build process is tested with podman, but some of the build files (Makefile specifically) use docker because they are generated automatically by operator-sdk. It is recommended remap the docker command to the podman command.

export repo=raffaelespazzoli
docker login quay.io/$repo
oc new-project keepalived-operator
oc project keepalived-operator
tilt up

Test helm chart locally

Define an image and tag. For example...

export imageRepository="quay.io/redhat-cop/keepalived-operator"
export imageTag="$(git -c 'versionsort.suffix=-' ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/redhat-cop/keepalived-operator.git '*.*.*' | tail --lines=1 | cut --delimiter='/' --fields=3)"

Deploy chart...

make helmchart IMG=${imageRepository} VERSION=${imageTag}
helm upgrade -i keepalived-operator-local charts/keepalived-operator -n keepalived-operator-local --create-namespace

Delete...

helm delete keepalived-operator-local -n keepalived-operator-local
kubectl delete -f charts/keepalived-operator/crds/crds.yaml

Building/Pushing the operator image

export repo=raffaelespazzoli #replace with yours
docker login quay.io/$repo/keepalived-operator
make docker-build IMG=quay.io/$repo/keepalived-operator:latest
make docker-push IMG=quay.io/$repo/keepalived-operator:latest

Deploy to OLM via bundle

make manifests
make bundle IMG=quay.io/$repo/keepalived-operator:latest
operator-sdk bundle validate ./bundle --select-optional name=operatorhub
make bundle-build BUNDLE_IMG=quay.io/$repo/keepalived-operator-bundle:latest
docker login quay.io/$repo/keepalived-operator-bundle
docker push quay.io/$repo/keepalived-operator-bundle:latest
operator-sdk bundle validate quay.io/$repo/keepalived-operator-bundle:latest --select-optional name=operatorhub
oc new-project keepalived-operator
oc label namespace keepalived-operator openshift.io/cluster-monitoring="true" --overwrite
operator-sdk cleanup keepalived-operator -n keepalived-operator
operator-sdk run bundle --install-mode AllNamespaces -n keepalived-operator quay.io/$repo/keepalived-operator-bundle:latest

Integration Test

make helmchart-test

Testing

Add an external IP CIDR to your cluster to manage

export CIDR="192.168.130.128/28"
oc patch network cluster -p "$(envsubst < ./test/externalIP-patch.yaml | yq r -j -)" --type=merge

create a project that uses a LoadBalancer Service

oc new-project test-keepalived-operator
oc new-app django-psql-example -n test-keepalived-operator
oc delete route django-psql-example -n test-keepalived-operator
oc patch service django-psql-example -n test-keepalived-operator -p '{"spec":{"type":"LoadBalancer"}}' --type=strategic
export SERVICE_IP=$(oc get svc django-psql-example -n test-keepalived-operator -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

create a keepalivedgroup

oc adm policy add-scc-to-user privileged -z default -n test-keepalived-operator
oc apply -f ./test/keepalivedgroup.yaml -n test-keepalived-operator

annotate the service to be used by keepalived

oc annotate svc django-psql-example -n test-keepalived-operator keepalived-operator.redhat-cop.io/keepalivedgroup=test-keepalived-operator/keepalivedgroup-test

curl the app using the service IP

curl http://$SERVICE_IP:8080

test with a second keepalived group

oc apply -f ./test/test-servicemultiple.yaml -n test-keepalived-operator
oc apply -f ./test/keepalivedgroup2.yaml -n test-keepalived-operator
oc apply -f ./test/test-service-g2.yaml -n test-keepalived-operator

Releasing

git tag -a "<tagname>" -m "<commit message>"
git push upstream <tagname>

If you need to remove a release:

git tag -d <tagname>
git push upstream --delete <tagname>

If you need to "move" a release to the current main

git tag -f <tagname>
git push upstream -f <tagname>

Cleaning up

operator-sdk cleanup keepalived-operator -n keepalived-operator
oc delete operatorgroup operator-sdk-og
oc delete catalogsource keepalived-operator-catalog

keepalived-operator's People

Contributors

cedricmckinnie avatar cnuland avatar crleekwc avatar danielkucera avatar david-igou avatar garethahealy avatar raffaelespazzoli avatar renovate[bot] avatar sabre1041 avatar tbrasser avatar tommasopozzetti avatar trevorbox avatar zefool avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

keepalived-operator's Issues

Don't require interface names to be given, but networks/CIDRs instead

Currently, for every KeepalivedGroup, the name of the interface keepalived should use needs to be provided. However, this name could be unknown, or different per node in a cluster.

In the MetalK8s project we were running keepalived before to provide control-plane address failover, and ran into the same 'issue': from our configuration we knew the network/CIDR that should be used for VRRP traffic and such. keepalived requires the interface name, though, and I wanted to use a static configuration shared across nodes (not in a ConfigMap because we were using a static Pod to run keepalived, not a DaemonSet).

To 'fix' this, I used the following work-around:

Just leaving this here in case you'd be looking for a way to get rid of static interface names being provided and allowing a more flexible by-network/CIDR configuration.

After a Cluster Update there are always some keepalivedgroup Pods in CrashLoopBackOff

After a Cluster Update there are always some keepalivedgroup Pods in CrashLoopBackOff:
The log of the keepalived container shows:

Starting Keepalived v1.3.5 (03/19,2017), git commit v1.3.5-6-g6fa32f2
Opening file '/etc/keepalived.d/keepalived.conf'.
daemon is already running

The reason seems to be a stale PID file:

sh-4.4# ls -la /proc/*/exe
ls: cannot read symbolic link '/proc/35/exe': Permission denied
lrwxrwxrwx. 1 root root 0 Aug  1 07:40 /proc/1/exe -> /usr/bin/pod
lrwxrwxrwx. 1 root root 0 Aug  1 17:21 /proc/22/exe -> /usr/bin/bash
lrwxrwxrwx. 1 root root 0 Aug  1 17:18 /proc/28391/exe -> /usr/bin/bash
lrwxrwxrwx. 1 root root 0 Aug  1 17:27 /proc/28854/exe -> /usr/bin/coreutils
lrwxrwxrwx. 1 1001 root 0 Aug  1 07:40 /proc/35/exe
lrwxrwxrwx. 1 root root 0 Aug  1 17:27 /proc/self/exe -> /usr/bin/coreutils
lrwxrwxrwx. 1 root root 0 Aug  1 17:27 /proc/thread-self/exe -> /usr/bin/coreutils
sh-4.4# cat /etc/keepalived.pid/keepalived.pid 
12

I think keepalived needs to remove the pid file instead of using it to detect a running instance (which will never exist in this container scenario?!)

LoadBalancer type Service not working

When we create a Service with type LoadBalancer, it looks like this:

apiVersion: v1
kind: Service
metadata:
  annotations:
    keepalived-operator.redhat-cop.io/keepalivedgroup: keepalived-operator/shz
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"keepalived-operator.redhat-cop.io/keepalivedgroup":"keepalived-operator/shz"},"name":"lb-test","namespace":"kucera"},"spec":{"externalTrafficPolicy":"Cluster","loadBalancerIP":"10.139.125.70","ports":[{"name":"http","port":80,"protocol":"TCP","targetPort":8080}],"selector":{"app":"abc"},"sessionAffinity":"None","type":"LoadBalancer"}}
  creationTimestamp: "2020-10-02T18:03:44Z"
  name: lb-test
  namespace: kucera
  resourceVersion: "94186695"
  selfLink: /api/v1/namespaces/kucera/services/lb-test
  uid: 5b2de9fb-e83f-4aea-9630-9398fad55880
spec:
  clusterIP: 172.30.98.102
  externalTrafficPolicy: Cluster
  loadBalancerIP: 10.139.125.70
  ports:
  - name: http
    nodePort: 30679
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: abc
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer: {}

although I have set loadBalancerIP in spec, it is not generated into status so keepalived gets configured like this:

vrrp_instance kucera/lb-test {
    interface ens192

    virtual_router_id 7

    virtual_ipaddress {

    }

}

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
Dockerfile
  • golang 1.18
  • registry.access.redhat.com/ubi8/ubi undefined
ci.Dockerfile
  • golang 1.18
  • registry.access.redhat.com/ubi8/ubi undefined
github-actions
.github/workflows/pr.yaml
  • redhat-cop/github-workflows-operators v1.0.6@111e0405debdca28ead7616868b14bdde2c79d57
.github/workflows/push.yaml
  • redhat-cop/github-workflows-operators v1.0.6@111e0405debdca28ead7616868b14bdde2c79d57
gomod
go.mod
  • go 1.19
  • github.com/go-logr/logr v1.2.0
  • github.com/onsi/ginkgo v1.16.5
  • github.com/onsi/gomega v1.18.1
  • github.com/redhat-cop/operator-utils v1.3.4
  • github.com/scylladb/go-set v1.0.2
  • k8s.io/api v0.24.2
  • k8s.io/apimachinery v0.24.2
  • k8s.io/client-go v0.24.2
  • sigs.k8s.io/controller-runtime v0.12.2
kustomize
config/manager/kustomization.yaml
  • quay.io/raffaelespazzoli/keepalived-operator latest

  • Check this box to trigger a request for Renovate to run again on this repository

Multiple IP address created when only 1 is requested.

Working in an openshift environment. Only 1 out of 3 clusters exhibit this problem.

[root@mtaylor-rh81 iperftest]# oc new-project iperftest
Already on project "iperftest" on server "https://api.ocp4dev01.meteorcomm.lan:6443".

You can add applications to this project with the 'new-app' command. For example, try:

oc new-app django-psql-example

to build a new example application in Python. Or use kubectl to deploy a simple Kubernetes application:

kubectl create deployment hello-node --image=gcr.io/hello-minikube-zero-install/hello-node

[root@mtaylor-rh81 iperftest]# oc apply -f iperf1-svc.yaml
service/iperf1 created
[root@mtaylor-rh81 iperftest]# oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
iperf1 LoadBalancer 172.30.151.208 10.22.4.109,10.22.4.104,10.22.4.109 25000:31415/TCP 2s

[root@mtaylor-rh81 iperftest]# cat iperf1-svc.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
keepalived-operator.redhat-cop.io/keepalivedgroup: keepalived-operator/keepalivedgroup-workers
labels:
app: iperf
name: iperf1
namespace: iperftest
spec:
externalIPs:
- 10.22.4.104
ports:

  • port: 25000
    protocol: TCP
    targetPort: 25000
    selector:
    app: iperf1
    sessionAffinity: ClientIP
    type: LoadBalancer

Support for IPv6

I would like to have that. Maybe it is already available, I didn't test it. But I couldn't find any hint on the README.

Not found on operatorhub

Hello,

I can't find keepalived on operatorhub.io, but it is there on dev.operatorhub.io.
Something happened?

Client IP addresses

The pods behind the service seem to see an internal Kubernetes IP address as client instead of the clients real IP.

Is this behavior wanted or changeable?

Thanks!

wrong arg in helmchart for leader-election

I found an issue regarding helmchart keepalived-operator-v1.0.0.tgz. There is a wrong arg inside the Chart-Template :

keepalived-operator/templates/manager.yaml

Does not work:

 containers:
      - command:
        - /manager
        args:
        - --enable-leader-election

Fix to working arg:

containers:
      - command:
        - /manager
        args:
        - --leader-elect


Don't require interface names to be given, but networks/CIDRs instead

Currently, for every KeepalivedGroup, the name of the interface keepalived should use needs to be provided. However, this name could be unknown, or different per node in a cluster.

In the MetalK8s project we were running keepalived before to provide control-plane address failover, and ran into the same 'issue': from our configuration we knew the network/CIDR that should be used for VRRP traffic and such. keepalived requires the interface name, though, and I wanted to use a static configuration shared across nodes (not in a ConfigMap because we were using a static Pod to run keepalived, not a DaemonSet).

To 'fix' this, I used the following work-around:

Just leaving this here in case you'd be looking for a way to get rid of static interface names being provided and allowing a more flexible by-network/CIDR configuration.

New keepalived operator v1.3.2 fails to install in openshift.

New version is trying to replace v1.3.1 and is failing across all of my openshift clusters.

Install strategy failed: Deployment.apps "keepalived-operator-controller-manager" is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"operator":"keepalived-operator"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable

exluding IP address for physical devices in the subnet

We have encountered a problem while trying to set up Keepalived operator in a disconnected environment. The operator receives a subnet of available IP addresses for load balancing from the OpenShift API in order to provide VIP addresses to services of type LoadBalancer. While we are able to set the available subnet CIDR, we can not exclude addresses from the given list at API level as it does not have an appropriate field for exclusion ( gateway for example).

Using Different vlan for LB VIPs

Hi,
Sorry for using github for questions, but wondering whether i can use different vlan for loadbalancer service VIP.Using OpenShift 4 on Vmware ESXi. Implemented & reached LB VIPs when worker nodes' IP and LB VIPs are on the same vlan, but couldn't find a way to move LB VIPs to different vlan. Can it be via a verbatim config? Will you please guide me?
Thanks

Clarify how KeepalivedGroup work in a different Namespace then the Services using it

All examples given in the doc show a KeepalivedGroup CR being created in the same Namespace as the Service referencing and needing it yet the KeepalivedGroup CR seems to have a central role that is more on cluster and admin level.
What's the actual limitation?

  • KeepalivedGroup CR must be in the same Namespace as the Service needing it?
  • If KeepalivedGroup must be in the same Namespace, how is router id conflict avoided between multiple KeepalivedGroup?
  • One KeepalivedGroup CR can be used from multiple Namespaces?
  • If a KeepalivedGroup can be shared from different Namespaces, is a NetworkPolicy needed when running multi-tenant SDN?

Keepalive Operator doesn't work with OKD 4.7

We've successfully deployed this operator on Openshift, but now I've installed the keepalive operator on a cluster running OKD 4.7 and there are issues pulling images. The worker nodes show ImagePullBackoff when trying to access this image:

Back-off pulling image "registry.redhat.io/openshift4/ose-keepalived-ipfailover"

Can this be made to work with OKD and is there a registry which OKD users can use to get an equivalent image? The operator was installed from the marketplace, so I presume it's compatible. Manually pulling the image shows the underlying error is this:

# docker pull registry.redhat.io/openshift4/ose-keepalived-ipfailover
Using default tag: latest
Error response from daemon: Head https://registry.redhat.io/v2/openshift4/ose-keepalived-ipfailover/manifests/latest: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication

Any suggestions / advice?

Allow configuration of router_virtual_id

If the cluster keepalived-operator is deployed on shares an environment with other instances of keepalived, it is possible for conflicts to happen. Operators should be able to override router_virtual_id to prevent this from happening

By default router_virtual_id always starts with "1" as VIPs are assigned, and this cannot be configured. If router_virtual_id is set by adding annotation `keepalived-operator.redhat-cop.io/verbatimconfig: '{ "router_virtual_id": "11" }' It does not overwrite the original entry, instead producing the config:

vrrp_instance helloworld/helloworld {
  interface ens192
  virtual_router_id 1
  virtual_ipaddress {
    13.37.13.37
  }

  virtual_router_id 10
}

Which leads to more issues.

Service spec.loadBalancer not being updated when using static ExternalIPs

Using OCP4.10.47. We've created a service and defined an IP address in spec.ExternalIPs.

Keepalived operator sucessfully brings up the ExternalIP as a VIP, but doesn't write back the service status updating the service.status.loadBalancer.ingress[0].ip.
If dynamic ExternalIP is used, the service.status.loadBalancer.ingress[0].ip does get updated (from what I can tell, not by the keepalived operator).

Is this a missing feature of keepalived operator or is the update of the service.spec when using a static ExternalIP supposed to be done by a different process within openshift? According to redhat support, the updating of the service.status should be done by the external loadbalancer.

VLAN and bridge interfaces

When specifying an interface for the keepalived group, are there anything we should take into consideration for bridge interfaces?

My current setup is:

  • 3 node bare metal OCP cluster
  • 4 integrated 1GBE NICs
    • first NIC is being used as the service network
    • other three NICs are bonded (using network configuration policy)
  • The bond has several VLANs
  • Each VLAN has its own bridge
    This is primarily so I can deploy VMs using OpenShift virtualization into different networks

For external IPS I have set the interface to bridge0.200, being the bridge that is associated with VLAN 200
The externalIP cluster config is as follows (this subnet matches what is on VLAN 200):

  externalIP:
    autoAssignCIDRs:
      - 172.16.0.0/16

keepalived-operator - keepalived-workers seems to find the external IP address associated with a Redis Enterprise Cluster instance and creates a VIP for it, but I can't seem to hit that IP address. It should be routable, and I can see three MAC addresses associated with that VLAN

vrrp_instance rec/rec-ui {
    interface bridge0.200
    
    virtual_router_id 3  
    
    virtual_ipaddress {
      
      172.16.224.156
      
    }
MAC Address VLAN
44:1e:a1:4e:8e:36 OpenShift - ExternalIP(200)
e4:11:5b:d6:78:02 OpenShift - ExternalIP(200)
98:4b:e1:7a:25:52 OpenShift - ExternalIP(200)

Any ideas welcome

Controller panics if service annotation is not of the form namespace/name

A service annotation of the form:

keepalived-operator.redhat-cop.io/keepalivedgroup: group1

Panics the controller as it tries to log the error at https://github.com/redhat-cop/keepalived-operator/blob/master/controllers/keepalivedgroup_controller.go#L406

E0310 17:53:27.189342       1 runtime.go:78] Observed a panic: "invalid memory address or nil pointer dereference" (runtime error: invalid memory address or nil pointer dereference)
goroutine 817 [running]:
k8s.io/apimachinery/pkg/util/runtime.logPanic(0x16ed4a0, 0x247e2e0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:74 +0x95
k8s.io/apimachinery/pkg/util/runtime.HandleCrash(0x0, 0x0, 0x0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:48 +0x89
panic(0x16ed4a0, 0x247e2e0)
	/usr/local/go/src/runtime/panic.go:969 +0x1b9
github.com/redhat-cop/keepalived-operator/controllers.(*enqueueRequestForReferredKeepAlivedGroup).Create(0xc00000c880, 0x1add8e0, 0xc00153b5c0, 0x1accce0, 0xc000be8500)
	/workspace/controllers/keepalivedgroup_controller.go:406 +0x177
sigs.k8s.io/controller-runtime/pkg/source/internal.EventHandler.OnAdd(0x1ab83c0, 0xc00000c880, 0x1accce0, 0xc000be8500, 0xc00070c730, 0x1, 0x1, 0x188fee0, 0xc00153b5c0)
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/source/internal/eventsource.go:63 +0x132
k8s.io/client-go/tools/cache.(*processorListener).run.func1()
	/go/pkg/mod/k8s.io/[email protected]/tools/cache/shared_informer.go:777 +0xc2
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1(0xc00072ff60)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155 +0x5f
k8s.io/apimachinery/pkg/util/wait.BackoffUntil(0xc000734f60, 0x1a7f1e0, 0xc000a3db00, 0x16ba801, 0xc0006586c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156 +0xad
k8s.io/apimachinery/pkg/util/wait.JitterUntil(0xc00072ff60, 0x3b9aca00, 0x0, 0x1, 0xc0006586c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133 +0x98
k8s.io/apimachinery/pkg/util/wait.Until(...)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:90
k8s.io/client-go/tools/cache.(*processorListener).run(0xc000ca6180)
	/go/pkg/mod/k8s.io/[email protected]/tools/cache/shared_informer.go:771 +0x95
k8s.io/apimachinery/pkg/util/wait.(*Group).Start.func1(0xc0006387d0, 0xc000272410)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:73 +0x51
created by k8s.io/apimachinery/pkg/util/wait.(*Group).Start
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:71 +0x65
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x15afdb7]

goroutine 817 [running]:
k8s.io/apimachinery/pkg/util/runtime.HandleCrash(0x0, 0x0, 0x0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:55 +0x10c
panic(0x16ed4a0, 0x247e2e0)
	/usr/local/go/src/runtime/panic.go:969 +0x1b9
github.com/redhat-cop/keepalived-operator/controllers.(*enqueueRequestForReferredKeepAlivedGroup).Create(0xc00000c880, 0x1add8e0, 0xc00153b5c0, 0x1accce0, 0xc000be8500)
	/workspace/controllers/keepalivedgroup_controller.go:406 +0x177
sigs.k8s.io/controller-runtime/pkg/source/internal.EventHandler.OnAdd(0x1ab83c0, 0xc00000c880, 0x1accce0, 0xc000be8500, 0xc00070c730, 0x1, 0x1, 0x188fee0, 0xc00153b5c0)
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/source/internal/eventsource.go:63 +0x132
k8s.io/client-go/tools/cache.(*processorListener).run.func1()
	/go/pkg/mod/k8s.io/[email protected]/tools/cache/shared_informer.go:777 +0xc2
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1(0xc00072ff60)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155 +0x5f
k8s.io/apimachinery/pkg/util/wait.BackoffUntil(0xc0001aff60, 0x1a7f1e0, 0xc000a3db00, 0x16ba801, 0xc0006586c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156 +0xad
k8s.io/apimachinery/pkg/util/wait.JitterUntil(0xc00072ff60, 0x3b9aca00, 0x0, 0x1, 0xc0006586c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133 +0x98
k8s.io/apimachinery/pkg/util/wait.Until(...)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:90
k8s.io/client-go/tools/cache.(*processorListener).run(0xc000ca6180)
	/go/pkg/mod/k8s.io/[email protected]/tools/cache/shared_informer.go:771 +0x95
k8s.io/apimachinery/pkg/util/wait.(*Group).Start.func1(0xc0006387d0, 0xc000272410)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:73 +0x51
created by k8s.io/apimachinery/pkg/util/wait.(*Group).Start
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:71 +0x65

Implement unit testing

To better support integrating new features/enhancements, some sort of unit testing should be implemented in this project.

[Question] Unable to download the default keepalived image

Hi,

I installed keepalived-operator on an on-prem Kubernetes cluster. So far all is installed, but when I add a keepalivedgroup and the pods try to start, they fail, because the default image "registry.redhat.io/openshift4/ose-keepalived-ipfailover" is not free to pull. So do you have another suggestion for such an image that is freely available? And maybe this would be a nice information in the readme as well :-)

Thanks in advance

Christian

Add disclaimer about support from Red Hat

Some users are landing in this repository after reading some recommendations about using this operator for their ExternalIPs and are concerned about the support about it.

It would be very helpful if you can add a disclaimer at the top of the README to say that this repository and the code is considered a 3rd party software and therefore it's not supported by Red Hat and that any issue with it should be reported in this Issues page.

Keepalive conflicting with kube-proxy resulting in 404: no page found error

Upgraded openshift to 4.7 and now get issues where kube-proxy is not properly routing messages from the external IP to the internal service.

For example:
curl 10.22.4.97:10010
404: Page Not Found

kube-proxy claims that the IP is already in use:

Warning listen tcp4 10.22.4.97:10010: bind: address already in use 36s (x39 over 84m) kube-proxy can't open "externalIP for deepa-eetest/zrr-backoffice-rbx-0" (10.22.4.97:10010/tcp), skipping this externalIP: listen tcp4 10.22.4.97:10010: bind: address already in use.

Forcing a specific VRID

Seems that keepalived keeps changing VRID and the numbers keep incrementing. I need to force keepalived to use a specific VRID.

ip address associated with VRID 20 not present in MASTER advert

Can you give me an example of how to do that? I am not able to understand the documented example.

Image not accessible

I tried to pull the keepalived image as used by the operator (docker pull registry.redhat.io/openshift4/ose-keepalived-ipfailover). However, it appears one needs Red Hat Registry credentials to do so (which I don't have, AFAIK). Would it be possible to either use a public image, or (even better?) include a/the Dockerfile to build such image?

Coexistence with vSphere IPI OCP

vSphere IPI is avalable since 4.5 and includes a keepalived component for HA IP for api and ingress.
This is the config:

sh-4.2# cat /etc/keepalived/keepalived.conf 
vrrp_script chk_ocp {
    script "/usr/bin/curl -o /dev/null -kLfs https://localhost:6443/readyz && /usr/bin/curl -o /dev/null -kLfs http://localhost:50936/readyz"
    interval 1
    weight 50
}

# TODO: Improve this check. The port is assumed to be alive.
# Need to assess what is the ramification if the port is not there.
vrrp_script chk_ingress {
    script "/usr/bin/curl -o /dev/null -kLfs http://localhost:1936/healthz"
    interval 1
    weight 50
}

vrrp_instance oc2-yw674_API {
    state BACKUP
    interface ens192
    virtual_router_id 1
    priority 40
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass oc2-yw674_api_vip
    }
    virtual_ipaddress {
        192.168.100.10/24
    }
    track_script {
        chk_ocp
    }
}

vrrp_instance oc2-yw674_INGRESS {
    state BACKUP
    interface ens192
    virtual_router_id 223
    priority 40
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass oc2-yw674_ingress_vip
    }
    virtual_ipaddress {
        192.168.100.11/24
    }
    track_script {
        chk_ingress
    }
}

It is now even more important to allow configuration of router id to avoid collision.
See also #26

[RFE] authentication as a first class parameter of the CR

If one would like to configure Keepalived authentication in a configuration file using block in vrrp_instance section:

   authentication {
       auth_type PASS
       auth_pass passw123
   }

it doesn't work because verbatim configs are not really designed for multi-line configurations.
Maybe this is worth making authentication a first-class parameter of the CR, maybe referencing a secret.

Keepalived VIP conflict

I have a daemon that keeps trying to setup a VIP on a node when that VIP already exists on another node.

Fri Sep 17 16:07:21 2021: (deepa-zrr/backoffice-ip-elm) Receive advertisement timeout
Fri Sep 17 16:07:21 2021: (deepa-zrr/backoffice-ip-elm) Entering MASTER STATE
Fri Sep 17 16:07:21 2021: (deepa-zrr/backoffice-ip-elm) setting VIPs.
Fri Sep 17 16:07:21 2021: (deepa-zrr/backoffice-ip-elm) Sending/queueing gratuitous ARPs on ens192 for 10.22.4.117

This results in kube-proxy failures such as this:
can't open "externalIP for deepa-zrr/backoffice-ip-elm" (10.22.4.117:8010/tcp), skipping this externalIP: listen tcp4 10.22.4.117:8010: bind: cannot assign requested address

I am having this issue across the entire cluster where daemons keep trying to take over a VIP when it is functional and active.

Keepalived Operator with Ingress breaks ip whitelist annotation

Hi,

I tried setting up the keepalived operator together with the default IngressController. Unfortunately I noticed that since the IPs are set as an externalIp on a service source IP received by the default IngressController (HAProxy in OKD 4.7) will only receive the loadbalancer IP instead of a potential external source, which breaks the ip whitelist annotation.

For now I had to completely drop the keepalived Operator and I use a NodePort configuration to bypass the issue.

Is there something I missed with my configuration? Otherwise I think we could add a disclaimer in the how-to-ingress.md to state this point.

config-reloader issue in latest release

Hi all,

There seams to be an issue in the latest keepalived release (keepalived-operator.v1.2.2). The container "config-reloader" crashloops with the following error:

/usr/local/bin/notify.sh: line 20: create_config_only: unbound variable

and yes, the var "create_config_only" is not set in the deamonset. Do i miss something?

Thanks,
Michael

spread VIPs across instances

PR #53 already addresses this concern, but only partially. Its impact is, unfortunately, quite limited. It's quite rare that a service would have multiple VIPs such that they would be balanced.
The current shortcoming is that if one deploys keepalived-operator on OKD/Openshift 4.x, most VIPs would be colocated on a single node. This is especially problematic for services that require quorum, like kafka or mongodb with multiple instances. It's also affecting traffic scalability, as all traffic is mostly handled by a single node.
Ideally, by default, keepalived-operator would try to randomize the VIP distribution across the members. Further, it would be great if based on an annotation, some VIPs are kept on different members (for example, create an "anti-affinity" for kafka broker services, such that they are not placed on the same node).

Auto ExternalIP allocation

Is it possible to configure an K8s operator with CIDR block to be uses as Load Balancer IPs. In many cases specifying ExternalIPs on Service is not possible (3rd party Helm Chart you do not have control of, or even services that gets created dynamically by other operators). Would be very helpful to have a MetalLB style of configuration, something like:
data: config: | address-pools: - name: default addresses: - 192.168.1.240-192.168.1.250

separate one Class C segment per KeepalivedGroup

In our disconnected environment we have a need to separate one Class C segment per KeepalivedGroup. Although we can create an interface per node per segment and specify the appropriate network interface within KeepalivedGroup, all groups take IP addresses from a single pool ('autoAssignedCIDRs' field within the network.config.openshift.io object). Therefore there is no guarantee one KeepalivedGroup won't use an address from a segment designated to another KeepalivedGroup's interface.

Tolerations for KeepalivedGroup

We need to run keepalived on nodes with taints.

This means we either need the operator to create keepalived daemon set with absolute tolerations:

tolerations:
 - operator: Exists

or to be able to specify tolerations in the CRD.

Could you implement this?

keepalivedgroup daemonset has hardcoded images

The main image has been made configurable, but the config-reloader and prometheus-exporter containers are hardcoded with quay.io/redhat-cop/keepalived-operator:latest.
In the case of helm deployments, these could be configured with the same image (registry/repo/tag) as the operator itself was run with.
This would immediately make everything work in an airgapped (to the internet) environment.

ServiceAccount default managed by multiple operators

Hi Guys,

I am encountering the following problem. I have installed in the namespace openshift-operators the operator namespace-configuration-operator, now I try to install the keepalived operator however it starts arguing because the ServiceAccount default is already managed by another operator. The status of keepalived operator is as follows:

requirementStatus:
    - group: apiextensions.k8s.io
      child: CustomResourceDefinition
      message: CRD is present and Established condition is true
      name: keepalivedgroups.redhatcop.redhat.io
      status: Present
      uuid: 1bbc50ee-1419-4f15-8022-6cc4004c4c59
      version: v1
    - group: ''
      child: ServiceAccount
      message: Service account is not owned by this ClusterServiceVersion
      name: default
      status: PresentNotSatisfied
      version: v1

And here is the yaml of the ServiceAccount:

kind: ServiceAccount
apiVersion: v1
metadata:
  name: default
  namespace: openshift-operators
  selfLink: /api/v1/namespaces/openshift-operators/serviceaccounts/default
  uid: 4dafa9ae-6eae-4e93-a36b-0b1f4ce160b5
  resourceVersion: '8624328671'
  creationTimestamp: '2021-02-15T14:50:53Z'
  tags:
    operators.coreos.com/namespace-configuration-operator.openshift-operators: ''
  ownerReferences:
    - apiVersion: operators.coreos.com/v1alpha1
      child: ClusterServiceVersion
      name: namespace-configuration-operator.v1.0.1
      uid: bd32838a-0647-4bf5-9190-1e6199025be8
      controller: false
      blockOwnerDeletion: false
secrets:
  - name: default-token-bfxqm
  - name: default-dockercfg-n2zvz
imagePullSecrets:
  - name: default-dockercfg-n2zvz

The operators now continue to fight whether the ownership

Latest operator container image breaks all instances completely

Observed behavior

All Keepalived containers created by the operator are in InitCrashLoopBackoff with the following error message in the log of the config-setup init container:

bash: /usr/local/bin/notify.sh: No such file or directory

As a result, all managed IPs (and hence all applications on the cluster) are unreachable.

Cause

The latest version of quay.io/redhat-cop/keepalived-operator:latest is missing the notify scripts used in the init container as well as the config-reloader container of the generated keepalived Daemonsets.

This is a problem because

  • The operator hardcodes the image of those containers to quay.io/redhat-cop/keepalived-operator:latest
  • The operator hardcodes the imagePullPolicy to Always
  • the containers can't come up without said scripts.

Workaround

  1. Scale the keepalived-operator-controller-manager deployment to zero
  2. Manually patch all generated keepalived DaemonSets to use quay.io/redhat-cop/keepalived-operator:v1.4.2 instead

This is very brittle as the deployment may be scaled up again at any time by the OLM or whatever.

support more than 255 services

currently each KeepalivedGroup supports up to 255 services.
This limit is due to the way keepalived works and how the operator was designed: each services maps to a keepalived vrrp instance. With a different design where each vrrp instance can carry more than one VIP, it's possible to go beyond that limit.
Here is a possible design:

  1. a function maps services/VIPs to vrrp instance in a way that can be calculated at any point in time, so no state has to be held anywhere. For example sha256(namespace/service/VIP) mod 255. The pseudo randomness of the hash function ensures that VIPs are rather evenly distributed across vrrp groups.
  2. during the reconcile cycle VIPs are assigned via the above function and the keepalived map is computed.

This will allow supporting an unlimited number of VIPs/services. The only downside is that VIPs from different services share the same fail-over dynamic. This is not usually an issue.

Multiple KeepalivedGroups on the same network will break keepalived

Version: 1.2.2

After configuring a second KeepalivedGroup both of the instances keep flapping. Both KeepalivedGroups are constrained to different nodes, but they are still in the same physical network.

The goal is to have different sets of ip adresses assigned to different groups of nodes.

logoutput from one pod:

Thu Apr 29 12:59:52 2021: (namespace/website-test) Receive advertisement timeout
Thu Apr 29 12:59:52 2021: (namespace/website-test) Entering MASTER STATE
Thu Apr 29 12:59:52 2021: (namespace/website-test) setting VIPs.
Thu Apr 29 12:59:52 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: (namespace/website-test) Sending/queueing gratuitous ARPs on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:52 2021: (namespace/website-test) Master received advert from 10.1.2.92 with same priority 100 but higher IP address than ours
Thu Apr 29 12:59:52 2021: (namespace/website-test) Entering BACKUP STATE
Thu Apr 29 12:59:52 2021: (namespace/website-test) removing VIPs.
Thu Apr 29 12:59:53 2021: (namespace/website-test) ip address associated with VRID 1 not present in MASTER advert : 10.1.1.11
Thu Apr 29 12:59:54 2021: (namespace/website-test) ip address associated with VRID 1 not present in MASTER advert : 10.1.1.11
Thu Apr 29 12:59:55 2021: (namespace/website-test) ip address associated with VRID 1 not present in MASTER advert : 10.1.1.11
Thu Apr 29 12:59:56 2021: (namespace/website-test) Receive advertisement timeout
Thu Apr 29 12:59:56 2021: (namespace/website-test) Entering MASTER STATE
Thu Apr 29 12:59:56 2021: (namespace/website-test) setting VIPs.
Thu Apr 29 12:59:56 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: (namespace/website-test) Sending/queueing gratuitous ARPs on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: Sending gratuitous ARP on eth0 for 10.1.1.11
Thu Apr 29 12:59:56 2021: (namespace/website-test) Master received advert from 10.1.2.92 with same priority 100 but higher IP address than ours
Thu Apr 29 12:59:56 2021: (namespace/website-test) Entering BACKUP STATE
Thu Apr 29 12:59:56 2021: (namespace/website-test) removing VIPs.
Thu Apr 29 12:59:57 2021: (namespace/website-test) ip address associated with VRID 1 not present in MASTER advert : 10.1.1.11
Thu Apr 29 12:59:58 2021: (namespace/website-test) ip address associated with VRID 1 not present in MASTER advert : 10.1.1.11

keepalived-template.yaml not matching latest in master branch

I'm not seeing the latest changes from the following merge in the newly released keepalived-operator container v1.5.1.

docker run -it --rm --entrypoint cat quay.io/redhat-cop/keepalived-operator:v1.5.1 /templates/keepalived-template.yaml | grep -i daemonset
  kind: DaemonSet

Running this command does not show the new daemonsetPodsAnnotations field that were included in v1.5.1 release.

{{- with .KeepalivedGroup.Spec.DaemonsetAnnotations }}

Possibility to handle IP address conflicts with internal OpenShift CIDR

Hi,
we have now run into the issue, that a client ip, which accesses the keepalived ip, is in the same CIDR IP range, like the internal OpenShift CIDR and can't access the services exposed by Keepalived. Requests from other Client IP ranges, whch are not in the CIDR of the OpenShift cluster work without any problem.
Our assumption is, that the packets are dropped by the OpenShift firewall, since the rules think, the packets come from the internal CIDR as SRC.

Current situation:
Client IP (10.131.3.x)->Keepalived IP(10.25.178.x) -> OpenShift internal CIDR (10.128.0.0/14)

IPTables:
Chain OPENSHIFT-FIREWALL-FORWARD (1 references)
target prot opt source destination
DROP all -- 10.128.0.0/14 anywhere /* attempted resend after connection close / ctstate INVALID
ACCEPT all -- anywhere 10.128.0.0/14 /
forward traffic from SDN

Question:
Is the keepalived operator working in NAT mode for its ip, so the 10.25.178.x should be the src ip of the packets in the cluster or is it really the problem, that the src ip 10.131.3.x is beeing routed directly ?

Since i din't find any infos about the mode (NAT/DR) in this documentation and only found an annotation in another documentation
https://github.com/munnerz/keepalived-cloud-provider

The kube-keepalived-vip service supports both the NAT and DR methods of IPVS forwarding for the service traffic. The default forwarding method is NAT. Depending on your network topology, you may need to change that to DR (direct routing). To change this globally, you can set the environment variable KEEPALIVED_DEFAULT_FORWARD_METHOD to NAT or DR. To change it on a per service basis, then specify the method via the k8s.co/keepalived-forward-method annotation on the service as shown below:

Can you please give me the info, how the routing works and if it can be changed by a annotation ?

Thanks
Miro

Handling of `Local` `externalTrafficPolicy`

If I understand correctly, currently the LoadBalancer and externalIPs of a Service will be handled in a vrrp_instance that can be running on any Node that's part of the KeepalivedGroup matcher.

However, I believe this poses an issue when this Service is configured to use the Local externalTrafficPolicy, in which case traffic sent to the service on Nodes which have 0 backing Pods running will be dropped (i.e., clients need to time-out), at least for the LoadBalancer IPs (not sure about the externalIPs traffic...).

This seems like an issue.

Luckily, there's the service.spec.healthCheckNodePort for such Services which can be HTTP-queried on /healthz (it's a NodePort). This will return HTTP 200 if there's a backing Pod available on the node (i.e., traffic sent there will be handled, not dropped), and HTTP 503 otherwise (i.e., traffic sent would be dropped).

More background at https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-type-loadbalancer.

As such, for externalTrafficPolicy Local Services, it could make sense to use a Keepalived vrrp_script which queries this healthCheckNodePort on localhost and exits successfully only when this query yields a HTTP 200 result (taking script timeouts etc. into account). If no local Pods are present, the VIP should be migrated to another node which is willing to host the VIP (i.e., has local Endpoints for the Service).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.