Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExternalIPPool API and update Egress API for failover support #2236

Merged
merged 1 commit into from
Jun 10, 2021

Conversation

tnqn
Copy link
Member

@tnqn tnqn commented Jun 3, 2021

  1. Add ExternalIPPool CRD which defines one or multiple IP sets that can
    be used in external network, and the Nodes that can hold the IPs.

  2. Add an optional field "externalIPPool" to Egress spec which specifies
    the IP Pool that the EgressIP should be allocated from.

Signed-off-by: Quan Tian qtian@vmware.com

For #2128

@codecov-commenter
Copy link

codecov-commenter commented Jun 3, 2021

Codecov Report

Merging #2236 (f7391b4) into main (382cd88) will decrease coverage by 21.69%.
The diff coverage is 100.00%.

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #2236       +/-   ##
===========================================
- Coverage   61.95%   40.25%   -21.70%     
===========================================
  Files         276      273        -3     
  Lines       21178    20506      -672     
===========================================
- Hits        13120     8255     -4865     
- Misses       6699    11094     +4395     
+ Partials     1359     1157      -202     
Flag Coverage Δ
kind-e2e-tests 40.25% <100.00%> (-12.87%) ⬇️
unit-tests ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
pkg/apis/crd/v1alpha2/register.go 85.71% <100.00%> (+2.38%) ⬆️
pkg/agent/controller/egress/id_allocator.go 0.00% <0.00%> (-100.00%) ⬇️
pkg/controller/networkpolicy/crd_utils.go 0.00% <0.00%> (-91.57%) ⬇️
pkg/controller/networkpolicy/endpoint_querier.go 2.85% <0.00%> (-88.58%) ⬇️
...agent/flowexporter/connections/deny_connections.go 7.14% <0.00%> (-85.72%) ⬇️
pkg/controller/networkpolicy/status_controller.go 0.00% <0.00%> (-85.17%) ⬇️
...kg/controller/networkpolicy/antreanetworkpolicy.go 0.00% <0.00%> (-85.00%) ⬇️
pkg/controller/egress/controller.go 0.00% <0.00%> (-83.88%) ⬇️
pkg/agent/util/iptables/lock.go 0.00% <0.00%> (-81.82%) ⬇️
pkg/agent/controller/networkpolicy/priority.go 8.49% <0.00%> (-81.70%) ⬇️
... and 134 more

@tnqn
Copy link
Member Author

tnqn commented Jun 3, 2021

/test-all

Copy link
Contributor

@jianjuns jianjuns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question on whether we always enable Node assignment or not.

type ExternalIPPoolSpec struct {
// The IP ranges of this IP pool, e.g. 10.10.0.0/24, 10.10.10.2-10.10.10.20, 10.10.10.30-10.10.10.30.
IPRanges []IPRange `json:"ipRanges"`
// The Nodes that the external IPs can be assigned to. If empty, it means all Nodes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is nil, do you think we can say it means auto-assignement is not enabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it wouldn't be very useful in practice. It seems if users want to manage the egress IPs themselves, providing an ExternalIPPool here and associate it with the Egresses is not as convenient as just specifying the IP in Egress directly. Some benefits when using nil to represent all Nodes in my mind:

  1. For a cluster that all nodes are in same subnet, it's more convinient to use nil to select all Nodes as the Egress Nodes. I don't know a typical expression that selects all Nodes without adding labels to them. (unless using NotIn and DoesNotExist with some meaningless key/value)
  2. Have a clear boundary between enabling assignment/failover and disabling it by the externalIPPool field.
  3. Keep backwards-compatible with the previous static Egresses.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you said make sense to me. But do you think it is a convention to use empty selector (but not nil) to express selecting all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that it's quite unusual for a nil selector to mean "select all". Is there an example in the K8s API of such behavior? On the other hand, it seems that empty (but not nil) to select all is fairly common. My preference if we do not think there will be other mechanisms / fields for selection would be to make this field not optional, with empty meaning "select all" (like the PodSelector field in the NetworkPolicy Spec). As Jianjun mentioned in the meeting, if we plan to have other selector fields (potentially mutually-exclusive), that's potentially a different story...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do go with a pointer, Jianjun's proposal kind of makes sense to me (disabling auto-assignment for nil): the user is responsible for assigning IP addresses to Nodes, but doesn't have to manage individual IPs for different Egress resources? Still, if we don't need other selectors in the future and this is not an actual use case, a non optional field makes more sense to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed the difference between nil and empty, thought they are same somehow. Yes, what you suggested makes sense. Empty is more common to to represent selecting All. I have made the field mandatory in the latest patch. If we have other fields to select Nodes in the future, I think changing a mandatory field to optional is compatible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think last time we discussed changing from mandatory to optional is not a compatible change. But anyway if we see no use case to make it optional, we can keep the current design (otherwise maybe change back to a pointer, but validating it cannot be nil?).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also believe that changing from mandatory to optional is not considered a compatible changes, since it can break older clients which read ExternalIPPoolSpec resources created by a newer client? https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md#on-compatibility

Given that this is an alpha API, maybe we should go with what makes the most sense right now, which I would say is making the field mandatory (current proposal).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, was considering the server side storage only. Agree we should keep what makes the most sense right now when we don't have clear idea about how to extend it.

Comment on lines 213 to 220
// ExternalIPPool specifies the IP Pool that the EgressIP should be allocated from.
// If it's set, the allocated EgressIP will be assigned to a Node specified by the Pool and it will failover to
// another Node if the assigned Node becomes unavailable.
// If it's set with EgressIP, the EgressIP must be in the IP Pool.
ExternalIPPool string `json:"externalIPPool"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have an EgressStatus to report which IP has been assigned (e.g. for troubleshooting) to the Egress resource?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assigned IP will be set to the above EgressIP field. Does it make sense to you? This is similar to Service ClusterIP. It can be specified manually or assigned by server, the field is kept in Spec for unification.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, for troubleshooting and visibility, there is a plan to add a nodeName field to status after the major function is done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. If we want to get fancy, we can even add a status to the EgressIPPool to report the number of allocated vs free IPs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, will create an issue to track it.

Copy link
Member Author

@tnqn tnqn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jianjuns and @antoninbas for the suggestions.

Comment on lines 213 to 220
// ExternalIPPool specifies the IP Pool that the EgressIP should be allocated from.
// If it's set, the allocated EgressIP will be assigned to a Node specified by the Pool and it will failover to
// another Node if the assigned Node becomes unavailable.
// If it's set with EgressIP, the EgressIP must be in the IP Pool.
ExternalIPPool string `json:"externalIPPool"`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assigned IP will be set to the above EgressIP field. Does it make sense to you? This is similar to Service ClusterIP. It can be specified manually or assigned by server, the field is kept in Spec for unification.

pkg/apis/crd/v1alpha2/types.go Outdated Show resolved Hide resolved
type ExternalIPPoolSpec struct {
// The IP ranges of this IP pool, e.g. 10.10.0.0/24, 10.10.10.2-10.10.10.20, 10.10.10.30-10.10.10.30.
IPRanges []IPRange `json:"ipRanges"`
// The Nodes that the external IPs can be assigned to. If empty, it means all Nodes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed the difference between nil and empty, thought they are same somehow. Yes, what you suggested makes sense. Empty is more common to to represent selecting All. I have made the field mandatory in the latest patch. If we have other fields to select Nodes in the future, I think changing a mandatory field to optional is compatible.

jianjuns
jianjuns previously approved these changes Jun 8, 2021
type ExternalIPPoolSpec struct {
// The IP ranges of this IP pool, e.g. 10.10.0.0/24, 10.10.10.2-10.10.10.20, 10.10.10.30-10.10.10.30.
IPRanges []IPRange `json:"ipRanges"`
// The Nodes that the external IPs can be assigned to. If empty, it means all Nodes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think last time we discussed changing from mandatory to optional is not a compatible change. But anyway if we see no use case to make it optional, we can keep the current design (otherwise maybe change back to a pointer, but validating it cannot be nil?).

antoninbas
antoninbas previously approved these changes Jun 8, 2021
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// ExternalIPPool defines one or multiple IP sets that can be used in external network. For instance, the IPs can be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"in the external network"?
or "in external networks"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

type ExternalIPPoolSpec struct {
// The IP ranges of this IP pool, e.g. 10.10.0.0/24, 10.10.10.2-10.10.10.20, 10.10.10.30-10.10.10.30.
IPRanges []IPRange `json:"ipRanges"`
// The Nodes that the external IPs can be assigned to. If empty, it means all Nodes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also believe that changing from mandatory to optional is not considered a compatible changes, since it can break older clients which read ExternalIPPoolSpec resources created by a newer client? https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md#on-compatibility

Given that this is an alpha API, maybe we should go with what makes the most sense right now, which I would say is making the field mandatory (current proposal).

1. Add ExternalIPPool CRD which defines one or multiple IP sets that can
   be used in external network, and the Nodes that can hold the IPs.

2. Add an optional field "externalIPPool" to Egress spec which specifies
   the IP Pool that the EgressIP should be allocated from.

Signed-off-by: Quan Tian <qtian@vmware.com>
@tnqn
Copy link
Member Author

tnqn commented Jun 9, 2021

/test-all

@tnqn
Copy link
Member Author

tnqn commented Jun 10, 2021

/test-networkpolicy
/test-e2e
/test-conformance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants