-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Support set user-defined port to queue-proxy #2190
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
Changes from all commits
e5b5c56
064bf3c
5fe7fb8
7fabfe6
4a19099
98428ad
dbe33ae
ad4bec8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,17 +48,6 @@ var ( | |
| MountPath: "/var/log", | ||
| } | ||
|
|
||
| userPorts = []corev1.ContainerPort{{ | ||
| Name: userPortName, | ||
| ContainerPort: int32(userPort), | ||
| }} | ||
|
|
||
| // Expose containerPort as env PORT. | ||
| userEnv = corev1.EnvVar{ | ||
| Name: userPortEnvName, | ||
| Value: strconv.Itoa(userPort), | ||
| } | ||
|
|
||
| userResources = corev1.ResourceRequirements{ | ||
| Requests: corev1.ResourceList{ | ||
| corev1.ResourceCPU: userContainerCPU, | ||
|
|
@@ -81,7 +70,7 @@ var ( | |
| } | ||
| ) | ||
|
|
||
| func rewriteUserProbe(p *corev1.Probe) { | ||
| func rewriteUserProbe(p *corev1.Probe, userPort int) { | ||
| if p == nil { | ||
| return | ||
| } | ||
|
|
@@ -101,19 +90,24 @@ func makePodSpec(rev *v1alpha1.Revision, loggingConfig *logging.Config, observab | |
| // update the validations in pkg/webhook.validateContainer. | ||
| userContainer.Name = userContainerName | ||
| userContainer.Resources = userResources | ||
| userContainer.Ports = userPorts | ||
| userContainer.VolumeMounts = append(userContainer.VolumeMounts, varLogVolumeMount) | ||
| userContainer.Lifecycle = userLifecycle | ||
| userContainer.Env = append(userContainer.Env, userEnv) | ||
|
|
||
| userPort, found := getUserPort(rev) | ||
| if !found { | ||
| createAndSetDefaultUserPort(userContainer) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic here seems a bit strange that you return the default port when not found, but then don't use in createAndSetDefaultUserPort. To me it would feel a bit more natural if getUserPort returned 0 for userPort when false, and createAndSetDefaultUserPort returned the default userPort. Otherwise you are relying on userPort to be equal to what createAndSetDefaultUserPort set which could easily become a bug.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get your point.
get port from revision, used in two places, userPort need to get default port if can't find userport. |
||
| } | ||
| userContainer.Env = append(userContainer.Env, buildUserPortEnv(userPort)) | ||
| userContainer.Env = append(userContainer.Env, getKnativeEnvVar(rev)...) | ||
|
|
||
| // Prefer imageDigest from revision if available | ||
| if rev.Status.ImageDigest != "" { | ||
| userContainer.Image = rev.Status.ImageDigest | ||
| } | ||
|
|
||
| // If the client provides probes, we should fill in the port for them. | ||
| rewriteUserProbe(userContainer.ReadinessProbe) | ||
| rewriteUserProbe(userContainer.LivenessProbe) | ||
| rewriteUserProbe(userContainer.ReadinessProbe, int(userPort)) | ||
| rewriteUserProbe(userContainer.LivenessProbe, int(userPort)) | ||
|
|
||
| podSpec := &corev1.PodSpec{ | ||
| Containers: []corev1.Container{ | ||
|
|
@@ -133,6 +127,33 @@ func makePodSpec(rev *v1alpha1.Revision, loggingConfig *logging.Config, observab | |
| return podSpec | ||
| } | ||
|
|
||
| func createAndSetDefaultUserPort(userContainer *corev1.Container) { | ||
| defaultUserPort := &corev1.ContainerPort{ | ||
| Name: v1alpha1.RevisionContainerUserPortName, | ||
| ContainerPort: int32(v1alpha1.RevisionContainerUserPortDefaultValue), | ||
| } | ||
| userContainer.Ports = append(userContainer.Ports, *defaultUserPort) | ||
| } | ||
|
|
||
| func getUserPort(rev *v1alpha1.Revision) (int32, bool) { | ||
| for _, port := range rev.Spec.Container.Ports { | ||
| if port.Name == v1alpha1.RevisionContainerUserPortName { | ||
| return port.ContainerPort, true | ||
| } | ||
| } | ||
|
|
||
| return v1alpha1.RevisionContainerUserPortDefaultValue, false | ||
| } | ||
|
|
||
| func buildUserPortEnv(userPort int32) corev1.EnvVar { | ||
| // Expose containerPort as env PORT. | ||
| userPortEnv := corev1.EnvVar{ | ||
| Name: userPortEnvName, | ||
| Value: strconv.Itoa(int(userPort)), | ||
| } | ||
| return userPortEnv | ||
| } | ||
|
|
||
| func MakeDeployment(rev *v1alpha1.Revision, | ||
| loggingConfig *logging.Config, networkConfig *config.Network, observabilityConfig *config.Observability, | ||
| autoscalerConfig *autoscaler.Config, controllerConfig *config.Controller) *appsv1.Deployment { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should actually enforce that there is no name on the port for now. We can preserve the name 'user-port' on the deployment; however, the name is intended to be used for HTTP negotiation when specified on Configuration. Allowing it or requiring it to be 'user-port' would not allow us to implement the runtime contract. See https://github.com/knative/serving/blob/master/docs/runtime-contract.md#inbound-network-connectivity
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so it means accept any name of the port ?
hmm, it's about how to set user-port by user, it seems we didn't discuss about that clearly. @mattmoor @evankanderson Do you have any suggestions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify my understanding of the contract, there should only ever be 1 port in the Configuration Spec (or configuration section of Service Spec). Configuration.Spec.Container.Ports[0].Name should either be "" or "http1" or "h2c". Since we currently only implement automatic detection it probably makes sense to only accept "" for Name.
When the revision is created by Knative, the revision creates a K8s Deployment object from the spec. The port name on the Deployment is currently being set to 'user-port', and I think it makes sense to keep this set for clarity that the 'user-port' containerPort on the deployment was set from Configuration.Spec.Container.Ports[0].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To quote the spec (because apparently I had deep discussions about this 6 months ago, and was smarter than I am when looking at this issue for 10 minutes today):
All of the above is about the Container object specified in the Revision. The underlying implementation (e.g. creating a Deployment to back the Revision) can use whatever names it wants. The content-negotiation information needs to be forwarded to queue-proxy (this is not done today).