{"id":13839340,"url":"https://github.com/doitintl/kubeip","last_synced_at":"2025-10-23T02:27:11.045Z","repository":{"id":34832476,"uuid":"136438044","full_name":"doitintl/kubeip","owner":"doitintl","description":"Assign static public IPs to Kubernetes nodes (GKE, EKS)","archived":false,"fork":false,"pushed_at":"2025-04-16T21:45:46.000Z","size":598,"stargazers_count":437,"open_issues_count":12,"forks_count":75,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-08T03:49:25.819Z","etag":null,"topics":["aws","eks","eks-cluster","elastic","elastic-ips","gke","gke-cluster","golang","google-cloud","google-cloud-platform","kubernetes","kubernetes-addons","static-ip"],"latest_commit_sha":null,"homepage":"https://kubeip.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doitintl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-07T07:20:27.000Z","updated_at":"2025-04-25T08:22:11.000Z","dependencies_parsed_at":"2022-08-08T02:01:08.579Z","dependency_job_id":"c6c0bea1-7772-4ca3-b412-b191970e3e16","html_url":"https://github.com/doitintl/kubeip","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fkubeip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fkubeip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fkubeip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fkubeip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doitintl","download_url":"https://codeload.github.com/doitintl/kubeip/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374401,"owners_count":22060609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","eks","eks-cluster","elastic","elastic-ips","gke","gke-cluster","golang","google-cloud","google-cloud-platform","kubernetes","kubernetes-addons","static-ip"],"created_at":"2024-08-04T17:00:19.479Z","updated_at":"2025-10-23T02:27:10.940Z","avatar_url":"https://github.com/doitintl.png","language":"Go","funding_links":[],"categories":["Go","NetWork"],"sub_categories":[],"readme":"![build](https://github.com/doitintl/kubeip/workflows/build/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/doitintl/kubeip)](https://goreportcard.com/report/github.com/doitintl/kubeip) ![Docker Pulls](https://img.shields.io/docker/pulls/doitintl/kubeip-agent)\n\n# KubeIP v2\n\nWelcome to KubeIP v2, a complete overhaul of the popular [DoiT](https://www.doit.com/)\nKubeIP [v1-main](https://github.com/doitintl/kubeip/tree/v1-main) open-source project, originally developed\nby [Aviv Laufer](https://github.com/avivl).\n\nKubeIP v2 expands its support beyond Google Cloud (as in v1) to include AWS and Oracle Cloud Infrastructure(OCI), and it's designed to be extendable to other cloud providers\nthat allow assigning static public IP to VMs. We've also transitioned from a Kubernetes controller to a standard DaemonSet, enhancing\nreliability and ease of use.\n\n## What happens with KubeIP v1\n\nKubeIP v1 is still available in the [v1-main](https://github.com/doitintl/kubeip/tree/v1-main) branch. No further development is planned. We\nwill fix critical bugs and security issues, but we will not add new features.\n\n## What KubeIP v2 does?\n\nKubernetes' nodes don't necessarily need their own public IP addresses to communicate. However, there are certain situations where it's\nbeneficial for nodes in a node pool to have their own unique public IP addresses.\n\nFor instance, in gaming applications, a console might need to establish a direct connection with a cloud virtual machine to reduce the\nnumber of hops.\n\nSimilarly, if you have multiple agents running on Kubernetes that need a direct server connection, and the server needs to whitelist all\nagent IPs, having dedicated public IPs can be useful. These scenarios, among others, can be handled on a cloud-managed Kubernetes cluster\nusing Node Public IP.\n\nKubeIP is a utility that assigns a static public IP to each node it manages. The IP is allocated to the node's primary network interface,\nchosen from a pool of reserved static IPs using platform-supported filtering and ordering.\n\nIf there are no static public IPs left, KubeIP will hold on until one becomes available. When a node is removed, KubeIP releases the static\npublic IP back into the pool of reserved static IPs.\n\n## How to use KubeIP?\n\nDeploy KubeIP as a DaemonSet on your desired nodes using standard\nKubernetes [mechanism](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). Once deployed, KubeIP will assign a static\npublic IP\nto each node it operates on. If no static public IP is available, KubeIP will wait until one becomes available. When a node is deleted,\nKubeIP will release the static public IP and reassign ephemeral public IP to the node.\n\n### IPv6 Support\n\nKubeIP supports dual-stack IPv4/IPv6 GKE clusters and Google Cloud static public IPv6 addresses.\nTo enable IPv6 support, set the `ipv6` flag (or set `IPV6` environment variable) to `true` (default is `false`).\n\n### Kubernetes Service Account\n\nKubeIP requires a Kubernetes service account with at least the following permissions:\n\n```yaml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: kubeip-service-account\n  namespace: kube-system\n---\n\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: kubeip-cluster-role\nrules:\n  - apiGroups: [ \"\" ]\n    resources: [ \"nodes\" ]\n    verbs: [ \"get\" ]\n  - apiGroups: [ \"coordination.k8s.io\" ]\n    resources: [ \"leases\" ]\n    verbs: [ \"create\", \"get\", \"delete\" ]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: kubeip-cluster-role-binding\nsubjects:\n  - kind: ServiceAccount\n    name: kubeip-service-account\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: kubeip-cluster-role\n  apiGroup: rbac.authorization.k8s.io\n```\n\n### Kubernetes DaemonSet\n\nDeploy KubeIP as a DaemonSet on your desired nodes using standard Kubernetes selectors. Once deployed, KubeIP will assign a static public IP\nto the node's primary network interface, selected from a list of reserved static IPs using platform-supported filtering. If no static public\nIP is available, KubeIP will wait until one becomes available. When a node is deleted, KubeIP will release the static public IP.\n\n```yaml\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: kubeip\nspec:\n  selector:\n    matchLabels:\n      app: kubeip\n  template:\n    metadata:\n      labels:\n        app: kubeip\n    spec:\n      serviceAccountName: kubeip-service-account\n      terminationGracePeriodSeconds: 30\n      priorityClassName: system-node-critical\n      nodeSelector:\n        kubeip.com/public: \"true\"\n      containers:\n        - name: kubeip\n          image: doitintl/kubeip-agent\n          resources:\n            requests:\n              cpu: 100m\n          env:\n            - name: NODE_NAME\n              valueFrom:\n                fieldRef:\n                  fieldPath: spec.nodeName\n            - name: FILTER\n              value: PUT_PLATFORM_SPECIFIC_FILTER_HERE\n            - name: LOG_LEVEL\n              value: debug\n            - name: LOG_JSON\n              value: \"true\"\n```\n\n### Node Taints\n\nKubeIP can be configured to attempt removal of a Taint Key from its node once the static IP has been successfully assigned, preventing\nworkloads from being scheduled on the node until it has successfully received a static IP address. This can be useful, for example, in cases\nwhere the workload must call resources with IP-whitelisting, to prevent race conditions between KubeIP and the workload on newly provisioned\nnodes.\n\nTo enable this feature, set the `taint-key` configuration parameter (See [How to run KubeIP](#how-to-run-kubeip)) to the taint key that\nshould be removed. Then add a toleration to the KubeIP DaemonSet, so that it itself can be scheduled on the tainted nodes. For example,\ngiven that new nodes are created with a taint key of `kubeip.com/not-ready`:\n\n```yaml\nkind: DaemonSet\nspec:\n  template:\n    spec:\n      serviceAccountName: kubeip-service-account\n      tolerations:\n        - key: kubeip.com/not-ready\n          operator: Exists\n          effect: NoSchedule\n      securityContext:\n        runAsNonRoot: true\n        runAsUser: 1001\n        runAsGroup: 1001\n        fsGroup: 1001\n      containers:\n        - name: kubeip\n          image: doitintl/kubeip-agent\n          env:\n            - name: TAINT_KEY\n              value: kubeip.com/not-ready\n          securityContext:\n            privileged: false\n            allowPrivilegeEscalation: false\n            capabilities:\n              drop:\n                - ALL\n            readOnlyRootFilesystem: true\n```\n\nThe parameter has no default value, and if not set, KubeIP will not attempt to remove any taints. If the provided Taint Key is not present\non the node, KubeIP will simply log this fact and continue normally without attempting to remove it. If the Taint Key is present, but\nremoving it fails for some reason, KubeIP will release the IP address back into the pool before restarting and trying again.\n\nUsing this feature requires KubeIP to have permission to patch nodes. To use this feature, the `ClusterRole` resource rules need to be\nupdated. **Note that if this configuration option is not set, KubeIP will not attempt to patch any nodes, and the change to the rules is not\nnecessary.**\n\nPlease keep in mind that this will give KubeIP permission to make updates to any node in your cluster, so please make sure that this aligns\nwith your security requirements before enabling this feature!\n\n```yaml\nrules:\n  - apiGroups: [ \"\" ]\n    resources: [ \"nodes\" ]\n    verbs: [ \"get\", \"patch\" ]\n```\n\n### AWS\n\nMake sure that KubeIP DaemonSet is deployed on nodes that have a public IP (node running in public subnet) and uses a Kubernetes service\naccount [bound](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to the IAM role with the following\npermissions:\n\n```yaml\nVersion: '2012-10-17'\nStatement:\n  - Effect: Allow\n    Action:\n      - ec2:AssociateAddress\n      - ec2:DisassociateAddress\n      - ec2:DescribeInstances\n      - ec2:DescribeAddresses\n    Resource: '*'\n```\n\nKubeIP supports filtering of reserved Elastic IPs using tags and Elastic IP properties. To use this feature, add the `filter` flag (or\nset `FILTER` environment variable) to the KubeIP DaemonSet:\n\n```yaml\n- name: FILTER\n  value: \"Name=tag:env,Values=dev;Name=tag:app,Values=streamer\"\n```\n\nKubeIP AWS filter supports the same filter syntax as the AWS `describe-addresses` command. For more information,\nsee [describe-addresses](https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-addresses.html#options). If you specify multiple\nfilters, they are joined with an `AND`, and the request returns only results that match all the specified filters. Multiple filters must be\nseparated by semicolons (`;`).\n\n### Google Cloud\n\nEnsure that the KubeIP DaemonSet is deployed on nodes with a public IP (nodes in a public subnet) and uses a Kubernetes service\naccount [bound](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) to an IAM role with the following permissions:\n\n```yaml\ntitle: \"KubeIP Role\"\ndescription: \"KubeIP required permissions\"\nstage: \"GA\"\nincludedPermissions:\n  - compute.instances.addAccessConfig\n  - compute.instances.deleteAccessConfig\n  - compute.instances.get\n  - compute.addresses.get\n  - compute.addresses.list\n  - compute.addresses.use\n  - compute.zoneOperations.get\n  - compute.subnetworks.useExternalIp\n  - compute.projects.get\n```\n\nKubeIP Google Cloud filter supports the same filter syntax as the Google Cloud `gcloud compute addresses list` command. For more\ninformation, see [gcloud topic filter](https://cloud.google.com/sdk/gcloud/reference/topic/filters). If you specify multiple filters, they\nare joined with an `AND`, and the request returns only results that match all the specified filters. Multiple filters must be separated by\nsemicolons (`;`).\n\nTo use this feature, add the `filter` flag (or set `FILTER` environment variable) to the KubeIP DaemonSet:\n\n```yaml\n- name: FILTER\n  value: \"labels.env=dev;labels.app=streamer\"\n```\n\n### Oracle Cloud Infrastructure (OCI)\n\nMake sure that KubeIP DaemonSet is deployed on nodes that have a public IP (node running in public subnet). Set the [compartment OCID](https://docs.oracle.com/en-us/iaas/Content/GSG/Tasks/contactingsupport_topic-Locating_Oracle_Cloud_Infrastructure_IDs.htm#Finding_the_OCID_of_a_Compartment) in the `project` flag (or\nset `FILTER` environment variable) to the KubeIP DaemonSet:\n\n```yaml\n- name: PROJECT\n  value: \"ocid1.compartment.oc1..test\"\n```\n\nKubeIP will also need certain permissions to communicate with the OCI APIs. Follow these steps to set up the necessary permissions and generate the required API key and place it in the KubeIP DaemonSet:\n\n1. Create a [user and group](https://docs.oracle.com/en/cloud/paas/integration-cloud/oracle-integration-gov/create-iam-group.html) in the OCI console and add the following [policy](https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingpolicies.htm) to the group:\n\n   ```\n   Allow group \u003cgroup_ocid\u003e to manage public-ips in compartment id \u003ccompartment_ocid\u003e\n   Allow group \u003cgroup_ocid\u003e to manage private-ips in compartment id \u003ccompartment_ocid\u003e\n   Allow group \u003cgroup_ocid\u003e to manage vcns in compartment id \u003ccompartment_ocid\u003e\n   ```\n\n2. Generate an [API Key](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#two) for the user and download the private key. Config file will look like this:\n\n   ```\n   [DEFAULT]\n   user=ocid1.user.oc1..test\n   fingerprint=\n   key_file=/root/.oci/oci_api_key.pem\n   tenancy=ocid1.tenancy.oc1..test\n   region=us-ashburn-1\n   ```\n\n3. Add the following [secret](https://kubernetes.io/docs/concepts/configuration/secret/) to the KubeIP DaemonSet:\n\n   ```yaml\n   apiVersion: v1\n   kind: Secret\n   metadata:\n     name: kubeip-oci-secret\n     namespace: kube-system\n   type: Opaque\n   data:\n     config: \u003cbase64_encoded_oci_config\u003e\n     oci_api_key.pem: \u003cbase64_encoded_oci_api_key\u003e\n   ```\n\n4. Create a volume and mount in the KubeIP DaemonSet to mount the secret:\n\n   ```yaml\n   volumes:\n     - name: oci-config\n       secret:\n         secretName: kubeip-oci-secret\n   ```\n\n   ```yaml\n   volumeMounts:\n     - name: oci-config\n       mountPath: /root/.oci\n   ```\n\n5. Add the following environment variables to the KubeIP DaemonSet:\n   ```yaml\n   - name: OCI_CONFIG_FILE\n     value: /root/.oci/config\n   ```\n\nKubeIP supports filtering of reserved Public IPs using tags. To use this feature, add the `filter` flag (or\nset `FILTER` environment variable) to the KubeIP DaemonSet:\n\n```yaml\n- name: FILTER\n  value: \"freeformTags.env=dev\"\n```\n\nKubeIP OCI filter supports the following filter syntax:\n\n- `freeformTags.\u003ckey\u003e=\u003cvalue\u003e`\n\nTo specify multiple filters, separate them with a semicolon (`;`). For example:\n\n```yaml\n- name: FILTER\n  value: \"freeformTags.env=dev;freeformTags.app=streamer\"\n```\n\nIn the case of multiple filters, they are joined with an `AND`, and the request returns only results that match all the specified filters.\n\n## How to contribute to KubeIP?\n\nKubeIP is an open-source project, and we welcome your contributions!\n\n## How to build KubeIP?\n\nKubeIP is written in Go and can be built using standard Go tools. To build KubeIP, run the following command:\n\n```shell\nmake build\n```\n\n## How to run KubeIP?\n\nKubeIP is a standard command-line application. To explore the available options, run the following command:\n\n```shell\nkubeip-agent run --help\n```\n\n```text\nNAME:\n   kubeip-agent run - run agent\n\nUSAGE:\n   kubeip-agent run [command options] [arguments...]\n\nOPTIONS:\n   Configuration\n\n   --filter value [ --filter value ]  filter for the IP addresses [$FILTER]\n   --ipv6                             enable IPv6 support (default: false) [$IPV6]\n   --kubeconfig value                 path to Kubernetes configuration file (not needed if running in node) [$KUBECONFIG]\n   --node-name value                  Kubernetes node name (not needed if running in node) [$NODE_NAME]\n   --order-by value                   order by for the IP addresses [$ORDER_BY]\n   --project value                    name of the GCP project or the AWS account ID (not needed if running in node) or OCI compartment OCID (required for OCI) [$PROJECT]\n   --region value                     name of the GCP region or the AWS region or the OCI region (not needed if running in node) [$REGION]\n   --release-on-exit                  release the static public IP address on exit (default: true) [$RELEASE_ON_EXIT]\n   --taint-key value                  specify a taint key to remove from the node once the static public IP address is assigned [$TAINT_KEY]\n   --retry-attempts value             number of attempts to assign the static public IP address (default: 10) [$RETRY_ATTEMPTS]\n   --retry-interval value             when the agent fails to assign the static public IP address, it will retry after this interval (default: 5m0s) [$RETRY_INTERVAL]\n   --lease-duration value             duration of the kubernetes lease (default: 5) [$LEASE_DURATION]\n   --lease-namespace value            namespace of the kubernetes lease (default: \"default\") [$LEASE_NAMESPACE]\n\n   Development\n\n   --develop-mode  enable develop mode (default: false) [$DEV_MODE]\n\n   Logging\n\n   --json             produce log in JSON format: Logstash and Splunk friendly (default: false) [$LOG_JSON]\n   --log-level value  set log level (debug, info(*), warning, error, fatal, panic) (default: \"info\") [$LOG_LEVEL]\n```\n\n## How to test KubeIP?\n\nTo test KubeIP, create a pool of reserved static public IPs, ensuring that the pool has enough IPs to assign to all nodes that KubeIP will\noperate on. Use labels to filter the pool of reserved static public IPs.\n\nNext, create a Kubernetes cluster and deploy KubeIP as a DaemonSet on your desired nodes. Ensure that the nodes have a public IP (nodes in a\npublic subnet). Configure KubeIP to use the pool of reserved static public IPs, using filters and order by.\n\nFinally, scale the number of nodes in the cluster and verify that KubeIP assigns a static public IP to each node. Scale down the number of\nnodes in the cluster and verify that KubeIP releases the static public IP addresses.\n\n#### AWS EKS Example\n\nThe [examples/aws](examples/aws) folder contains a Terraform configuration that creates an EKS cluster and deploys KubeIP as a DaemonSet on\nthe cluster nodes in a public subnet. The Terraform configuration also creates a pool of reserved Elastic IPs and configures KubeIP to use\nthe pool of reserved static public IPs.\n\nTo run the example, follow these steps:\n\n```shell\ncd examples/aws\nterraform init\nterraform apply\n```\n\n#### Google Cloud GKE Example\n\nThe [examples/gcp](examples/gcp) folder contains a Terraform configuration that creates a GKE cluster and deploys KubeIP as a DaemonSet on\nthe cluster nodes in a public subnet. The Terraform configuration also creates a pool of reserved static public IPs and configures KubeIP to\nuse the pool of reserved static public IPs.\n\nTo run the example, follow these steps:\n\n```shell\ncd examples/gcp\nterraform init\nterraform apply -var=\"project_id=\u003cyour-project-id\u003e\"\n```\n\nTo run the example with GKE dual-stack IPv4/IPv6 cluster, follow these steps:\n\n```shell\ncd examples/gcp\nterraform init\nterraform apply -var=\"project_id=\u003cyour-project-id\u003e\" -var=\"ipv6_support=true\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoitintl%2Fkubeip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoitintl%2Fkubeip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoitintl%2Fkubeip/lists"}