-
Notifications
You must be signed in to change notification settings - Fork 39.6k
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
Services with same port, different protocol display wrongly in kubectl and have wrong merge key #39188
Comments
@thockin The validation code doesn't allow me to create two ports with names unspecified.
What version did the user use? |
It looks like the user deleted the comment where they claimed this, so
probably realized they made a mistake (sorry for not seeing that). Still,
the port name seems like the more correct merge key
…On Tue, Dec 27, 2016 at 4:11 PM, Mengqi Yu ***@***.***> wrote:
@thockin <https://github.com/thockin> The validation code
<https://github.com/kubernetes/kubernetes/blob/master/pkg/api/validation/validation.go#L2481>
doesn't allow me to create two ports with names unspecified.
The Service "my-service" is invalid:
* spec.ports[0].name: Required value
* spec.ports[1].name: Required value
What version did the user use?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVH8_TwXVE7sudwh4kZl230-wkIPgks5rMalGgaJpZM4LUkwV>
.
|
Agree. @thockin This is a breaking change. So we should make this change in 1.6, right? cc: @pwittrock |
Names are unique. We can't require that name not be empty for the
single-port case, and we already demand it in the multi-port case. Can ""
be a valid value for the case of single port?
I guess changing merge key is technically a breaking change, but is there
any real impact?
…On Tue, Dec 27, 2016 at 4:40 PM, Mengqi Yu ***@***.***> wrote:
Still, the port name seems like the more correct merge key
Agree.
If we want to use name as mergeKey, we should add some validation code to
make sure the names are unique. And we need to take care of an empty name
if there is a single port only.
@thockin <https://github.com/thockin> This is a breaking change. So we
should make this change in 1.6, right?
cc: @pwittrock <https://github.com/pwittrock>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVFEiLbxVHCgP4QtVUV4t9PML2OC2ks5rMa_7gaJpZM4LUkwV>
.
|
Don't know yet. I need to look into it.
Yes, like #36024( |
yuck
…On Tue, Dec 27, 2016 at 5:00 PM, Mengqi Yu ***@***.***> wrote:
Can "" be a valid value for the case of single port?
Don't know yet. I need to look into it.
I guess changing merge key is technically a breaking change, but is there
any real impact?
Yes, like #36024 <#36024>(
kubectl is broken, even with minor version skew)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVI2Vj195GZZg7oyCZwmm4SaqQaOZks5rMbSzgaJpZM4LUkwV>
.
|
The mergeKey must present in the go struct to calculate patch. But object round tripping will drop empty field, which is
We should to change the apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
ports:
- protocol: UDP
port: 30420
name: updport
nodePort: 30420
- protocol: TCP
port: 30420
name: tcpport
nodePort: 30420
selector:
app: MyApp Make change to - protocol: TCP
port: 30420
name: tcpport
nodePort: 30000 # Change this nodePort
apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"my-service","creationTimestamp":null},"spec":{"ports":[{"name":"updport","protocol":"UDP","port":30420,"targetPort":0,"nodePort":30420},{"name":"tcpport","protocol":"TCP","port":30420,"targetPort":0,"nodePort":30000}],"selector":{"app":"MyApp"},"type":"NodePort"},"status":{"loadBalancer":{}}}
name: my-service
...
spec:
clusterIP: 10.0.0.249
ports:
- name: updport
nodePort: 30000 # Wrong change
port: 30420
protocol: UDP
targetPort: 30420
- name: tcpport
nodePort: 30420
port: 30420
protocol: TCP
targetPort: 30420
selector:
app: MyApp
sessionAffinity: None
type: NodePort
status:
loadBalancer: {} The change goes to the wrong place. |
I agree we should change it, but how can we do that if name is optional?
Can we have an empty mergekey automatically become a random string?
…On Wed, Dec 28, 2016 at 2:20 PM, Mengqi Yu ***@***.***> wrote:
Can "" be a valid value for the case of single port?
The mergeKey must present in the go struct to calculate patch. But object
round tripping will drop empty field, which is name in this case. So
simply change the mergeKeywill break the no-name single-port case.
We should to change the mergeKey, otherwise kubectl apply will do
something wrong.
e.g. Creating a service using kubectl apply
apiVersion: v1kind: Servicemetadata:
name: my-servicespec:
type: NodePort
ports:
- protocol: UDP
port: 30420
name: updport
nodePort: 30420
- protocol: TCP
port: 30420
name: tcpport
nodePort: 30420
selector:
app: MyApp
Make change to tcpport and apply the change
- protocol: TCP
port: 30420
name: tcpport
nodePort: 30000 # Change this nodePort
kubectl get the service back
apiVersion: v1kind: Servicemetadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: | {"kind":"Service","apiVersion":"v1","metadata":{"name":"my-service","creationTimestamp":null},"spec":{"ports":[{"name":"updport","protocol":"UDP","port":30420,"targetPort":0,"nodePort":30420},{"name":"tcpport","protocol":"TCP","port":30420,"targetPort":0,"nodePort":30000}],"selector":{"app":"MyApp"},"type":"NodePort"},"status":{"loadBalancer":{}}} name: my-service...spec:
clusterIP: 10.0.0.249
ports:
- name: updport
nodePort: 30000 # Wrong change
port: 30420
protocol: UDP
targetPort: 30420
- name: tcpport
nodePort: 30420
port: 30420
protocol: TCP
targetPort: 30420
selector:
app: MyApp
sessionAffinity: None
type: NodePortstatus:
loadBalancer: {}
The change goes to the wrong place.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVB00_aCZ2pF7mjyy3y2f810VjtMaks5rMuDGgaJpZM4LUkwV>
.
|
Yes, it's possible but it will make the logic complicated. Because I'm not sure if @pwittrock @bgrant0607 will like this. Need their comments before going further. |
"Random" string -- no. We have other cases where a single field isn't sufficient as a merge key, such as lists of object references. I think treating all fields specified by the user's config as the key works in all cases I've thought of. I'd probably make that a new patch strategy. It would probably even be backward compatible. |
@bgrant0607 Are you thinking this would support only the primitive fields as part of the unique/merge key? Or would this strategy only be valid for types that contain only primitive fields? Based on your description, the merge key for this strategy would be dynamic and defined by the client. Have we considered supporting merge keys that are multiple values, but otherwise treated the same as single-value merge keys (in this case it could be <port,protocol> or <port,destinationport,protocol>)? |
@pwittrock No, I was thinking we'd use all fields specified by the user as the key, including nested maps. Multiple keys would also work and may be less error-prone. |
For this particular case "" is a valid name in only in the case of a single
entry, and that is enforced by validation, so if "" was allowed it would
just work?
…On Wed, Jan 11, 2017 at 7:10 PM, Brian Grant ***@***.***> wrote:
@pwittrock <https://github.com/pwittrock> No, I was thinking we'd use all
fields specified by the user as the key, including nested maps. Multiple
keys would also work and may be less error-prone.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVDqLA1mRB-bEcODC1TQDuFNPXi_7ks5rRZmmgaJpZM4LUkwV>
.
|
@thockin I was thinking something similar yesterday. Something like: If len(patch list) == 1 && merge key is missing from patch list entry && len(dest list) == 1 && merge key is missing from dest list entry My biggest hesitation here was that it adds some complexity to the already poorly understood merge semantics. There would probably be some weird edge cases like what happens when we add the merge key to the existing entry. e.g. If len(patch list) == 1 && merge key exists in the list entry && len(dest list) == 1 && merge key is missing from dest list entry |
@ymqytw Can you make sure this gets resolved in 1.7? |
@pwittrock If using the approach in #39188 (comment), then yes. |
Lets sync up with @thockin to determine the minimal requirements for correctness. I don't want to introduce a partial solution since it will create a maintenance burden. Once the merge-key audit is complete, lets come up with a proposal. I think it is ok if we write a design proposal. I will make sure it gets appropriately reviewed within ~weeks. |
I've run into a lot of issues with ports being PATCHed wrongly through 1.6. Do we believe these issues are fixed now? I can't seem to repro them, but I wasn't dilligent in cataloging them all... |
I guess the pain you have when PATCHing the ports is caused by the bug of using the wrong json pkg in the api server (#42488). It has been fixed by #42489. issues with ports:
|
Has this been fixed? I'm seeing both ports on describe: › kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP: 10.0.0.133
Port: udp 30420/UDP
NodePort: udp 30420/UDP
Endpoints: 172.17.0.4:30420
Port: tcp 30420/TCP
NodePort: tcp 30420/TCP
Endpoints: 172.17.0.4:30420
Session Affinity: None
Events: <none> |
@jamiehannaford Not yet. |
God! I scratched my head so many times and never thought this could actually be a real bug... one assumes basics like this would never be broken for so long 😅 |
Amazing. How can one vote up for this bug? |
This person's blog describes the issue and a workaround: https://ben-lab.github.io/kubernetes-UDP-TCP-bug-same-port/ Seems like this works fine as long as the service is created initially with both ports, it's only adding a matching port after the fact which triggers the bug. This was also my experience setting up a TCP and UDP DNS server. |
This was originally added in #409 due to an upstream bug (kubernetes/kubernetes#39188). It turns out, however, that we and many others misinterpreted the scope of that bug - it really only applies for updating an existing service with a new port definition. It does not apply for creating a new service. Our customers are affected by this, and this validation is overly restrictive compared to errors the Load Balancers API actually returns during its validation. As such, the validation we do here can be relaxed.
This was originally added in #409 due to an upstream bug (kubernetes/kubernetes#39188). It turns out, however, that we and many others misinterpreted the scope of that bug - it really only applies for updating an existing service with a new port definition. It does not apply for creating a new service. Our customers are affected by this, and this validation is overly restrictive compared to errors the Load Balancers API actually returns during its validation. As such, the validation we do here can be relaxed.
Yeah, amazing that this bug is with us since 2016. I believe to express your support you can upvote the initial post. |
We should re-title this (or close and open new one) describing the problem.
Client-side So can someone tell me what the current problem is, other than client-side apply being broken? |
Looks like server-side apply is the future, so I think we may have to stop expecting it to get fixed in client-side but I too wonder why such thing is left unresolved for so many years... |
@thockin That client-side The Server Side Apply Is Great And You Should Be Using It blog post says: "Soon we (SIG API Machinery) hope to make this the default and remove the “client side” apply completely!". I expect that this issue can finally be closed once that happens. In the meantime documenting issues like this in the Comparison with Client Side Apply section of the documentation might help. |
@mateuszdrab - lots of people use dual-protocol (~everyone - DNS). It works fine EXCEPT FOR patch/apply/edit. Fixing it has not been possible because that could be an API break for things that actually work today. I've spent a bit of time looking into it more this weekend, and I can't actually tell if it is POSSIBLE to specify a compound key. I think it is not. @erwbgy - that doc is about the feature of apply, not about specific bugs. Still, I don't know if this hole is documented anywhere |
DNS is exactly what I use and struggled with this issue so many times... Until I found this issue 😂🤦🏼♂️ |
I'm confused about "so many times" - `kubectl create` works and `kubectl
apply` should work when there's not an existing resource (I think? Now
that I type it out, I am not so sure). Help me understand?
…On Mon, Jan 16, 2023 at 11:00 AM Mateusz Drab ***@***.***> wrote:
@mateuszdrab <https://github.com/mateuszdrab> - lots of people use
dual-protocol (~everyone - DNS). It works fine EXCEPT FOR patch/apply/edit.
Fixing it has not been possible because that could be an API break for
things that actually work today. I've spent a bit of time looking into it
more this weekend, and I can't actually tell if it is POSSIBLE to specify a
compound key. I think it is not.
@erwbgy <https://github.com/erwbgy> - that doc is about the feature of
apply, not about specific bugs. Still, I don't know if this hole is
documented anywhere
DNS is exactly what I use and struggled with this issue so many times...
Until I found this issue
—
Reply to this email directly, view it on GitHub
<#39188 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABKWAVHRNJ5ZPNGCOFKWRDTWSWLGPANCNFSM4C2SJQKQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I use flux which was applying the manifest server side, but when I was making changes to my deployment I'd apply things manually via kubectl and didn't notice things were broken for some time. |
I'm accumulating some details in #105610 |
i just fall in the same issue. I was trying to understand why my DNS queries goes to port 53 instead of 5353 and only in TCP. The service was doing only TCP 53->53. Editing TCP port on the service edited the UDP port (if not the same than UDP port), very weird. |
Kubectl client-side apply breaks coredns on upgrade because the old and the new version are not resolved correctly (see kubernetes/kubernetes#39188 (comment)) TL;DR: the merge key for the port array is only the port number, not port+protocol. Server-side apply solves this issue, but our custom kube module is not server-side apply ready. While we could improve our custom kube module, it will be a lesser maintenance load going forward to progressively drop it and switch to kubernetes.core.k8s, which has more features and is maintained by upstream. Do that now for coredns manifests. Add the python k8s client on the control plane (no need for it elsewhere), and the python-venv on distributions which need it to create a virtualenv.
Kubectl client-side apply breaks coredns on upgrade because the old and the new version are not resolved correctly (see kubernetes/kubernetes#39188 (comment)) TL;DR: the merge key for the port array is only the port number, not port+protocol. Server-side apply solves this issue, but our custom kube module is not server-side apply ready. While we could improve our custom kube module, it will be a lesser maintenance load going forward to progressively drop it and switch to kubernetes.core.k8s, which has more features and is maintained by upstream. Do that now for coredns manifests. Add the python k8s client on the control plane (no need for it elsewhere), and the python-venv on distributions which need it to create a virtualenv.
rh-pre-commit.version: 2.2.0 rh-pre-commit.check-secrets: ENABLED
I also had to delete and redeploy our entire NGINX ingress controller deployment for it work, not only the desired application's service and deployment. |
User reported:
I am running a service with both TCP and UDP:
but kubectl describe service shows only UDP.
When I change the order then it shows only TCP.
This looks like using the wrong mergeKey, and indeed the code backs that up:
2508 type ServiceSpec struct {
2509 // The list of ports that are exposed by this service.
2510 // More info: http://kubernetes.io/docs/user-guide/services#virtual-ips-and-service-proxies
2511 Ports []ServicePort
json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"port" protobuf:"bytes,1,rep,name=ports"
The key should probably be "name", though that can be empty if there is a single port only - is that a problem? @ymqytw ?
The text was updated successfully, but these errors were encountered: