Repository: knative/serving
Pull request #12095 (2021-10-06 09:57:31)

Allow readiness probe to be empty in Queue Proxy
Slowly moving us towards supporting StartupProbe by allowing readiness probe to be empty. Note: serving still defaults in a readiness probe if not present, so this code path is not yet actually used.

/assign @psschwei @markusthoemmes

knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/12095#" title="Author self-approved">julz</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fserving).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[cmd/queue/OWNERS](https://github.com/knative/serving/blob/main/cmd/queue/OWNERS)~~ [julz]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) Report
> Merging [#12095](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (a31f35a) into [main](https://codecov.io/gh/knative/serving/commit/ebeebd962771f33d5a534100440695793291499a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (ebeebd9) will **decrease** coverage by `0.01%`.
> The diff coverage is `0.00%`.

[![Impacted file tree graph](https://codecov.io/gh/knative/serving/pull/12095/graphs/tree.svg?width=650&height=150&src=pr&token=MPpDfAj4Ui&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)

```diff
@@            Coverage Diff             @@
##             main   #12095      +/-   ##
==========================================
- Coverage   87.44%   87.42%   -0.02%     
==========================================
  Files         196      196              
  Lines        9531     9536       +5     
==========================================
+ Hits         8334     8337       +3     
- Misses        923      925       +2     
  Partials      274      274              
```


| [Impacted Files](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) | Coverage Δ | |
|---|---|---|
| [cmd/queue/main.go](https://codecov.io/gh/knative/serving/pull/12095/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-Y21kL3F1ZXVlL21haW4uZ28=) | `0.49% <0.00%> (-0.01%)` | :arrow_down: |
| [pkg/reconciler/domainmapping/reconciler.go](https://codecov.io/gh/knative/serving/pull/12095/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL3JlY29uY2lsZXIvZG9tYWlubWFwcGluZy9yZWNvbmNpbGVyLmdv) | `92.10% <0.00%> (ø)` | |
| [pkg/apis/serving/fieldmask.go](https://codecov.io/gh/knative/serving/pull/12095/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2FwaXMvc2VydmluZy9maWVsZG1hc2suZ28=) | `95.01% <0.00%> (+0.01%)` | :arrow_up: |
| [pkg/apis/config/features.go](https://codecov.io/gh/knative/serving/pull/12095/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2FwaXMvY29uZmlnL2ZlYXR1cmVzLmdv) | `95.23% <0.00%> (+0.23%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Last update [ebeebd9...a31f35a](https://codecov.io/gh/knative/serving/pull/12095?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).


Patch:
diff --git a/cmd/queue/main.go b/cmd/queue/main.go
index 624fa93aa..385dbb897 100644
--- a/cmd/queue/main.go
+++ b/cmd/queue/main.go
@@ -77,7 +77,7 @@ type config struct {
 	QueueServingPort         string `split_words:"true" required:"true"`
 	UserPort                 string `split_words:"true" required:"true"`
 	RevisionTimeoutSeconds   int    `split_words:"true" required:"true"`
-	ServingReadinessProbe    string `split_words:"true" required:"true"`
+	ServingReadinessProbe    string `split_words:"true"` // optional
 	EnableProfiling          bool   `split_words:"true"` // optional
 	EnableHTTP2AutoDetection bool   `split_words:"true"` // optional
 
@@ -172,9 +172,12 @@ func main() {
 	}()
 
 	// Setup probe to run for checking user-application healthiness.
-	probe := buildProbe(logger, env)
-	healthState := health.NewState()
+	probe := func() bool { return true }
+	if env.ServingReadinessProbe != "" {
+		probe = buildProbe(logger, env.ServingReadinessProbe, env.EnableHTTP2AutoDetection).ProbeContainer
+	}
 
+	healthState := health.NewState()
 	mainServer := buildServer(ctx, env, healthState, probe, stats, logger)
 	servers := map[string]*http.Server{
 		"main":    mainServer,
@@ -261,18 +264,18 @@ func main() {
 	}
 }
 
-func buildProbe(logger *zap.SugaredLogger, env config) *readiness.Probe {
-	coreProbe, err := readiness.DecodeProbe(env.ServingReadinessProbe)
+func buildProbe(logger *zap.SugaredLogger, encodedProbe string, autodetectHTTP2 bool) *readiness.Probe {
+	coreProbe, err := readiness.DecodeProbe(encodedProbe)
 	if err != nil {
 		logger.Fatalw("Queue container failed to parse readiness probe", zap.Error(err))
 	}
-	if env.EnableHTTP2AutoDetection {
+	if autodetectHTTP2 {
 		return readiness.NewProbeWithHTTP2AutoDetection(coreProbe)
 	}
 	return readiness.NewProbe(coreProbe)
 }
 
-func buildServer(ctx context.Context, env config, healthState *health.State, rp *readiness.Probe, stats *network.RequestStats,
+func buildServer(ctx context.Context, env config, healthState *health.State, probeContainer func() bool, stats *network.RequestStats,
 	logger *zap.SugaredLogger) *http.Server {
 
 	maxIdleConns := 1000 // TODO: somewhat arbitrary value for CC=0, needs experimental validation.
@@ -323,7 +326,7 @@ func buildServer(ctx context.Context, env config, healthState *health.State, rp
 		composedHandler = tracing.HTTPSpanMiddleware(composedHandler)
 	}
 
-	composedHandler = health.ProbeHandler(healthState, rp.ProbeContainer, tracingEnabled, composedHandler)
+	composedHandler = health.ProbeHandler(healthState, probeContainer, tracingEnabled, composedHandler)
 	composedHandler = network.NewProbeHandler(composedHandler)
 	// We might want sometimes capture the probes/healthchecks in the request
 	// logs. Hence we need to have RequestLogHandler to be the first one.
diff --git a/config/core/configmaps/features.yaml b/config/core/configmaps/features.yaml
index c0eeeba2c..0382363a9 100644
--- a/config/core/configmaps/features.yaml
+++ b/config/core/configmaps/features.yaml
@@ -22,7 +22,7 @@ metadata:
     app.kubernetes.io/version: devel
     app.kubernetes.io/part-of: knative-serving
   annotations:
-    knative.dev/example-checksum: "0b69357a"
+    knative.dev/example-checksum: "2897f625"
 data:
   _example: |-
     ################################
@@ -143,3 +143,8 @@ data:
     # 1. Enabled: enabling EmptyDir volume support
     # 2. Disabled: disabling EmptyDir volume support
     kubernetes.podspec-volumes-emptydir: "disabled"
+
+    # Controls whether init containers support is enabled or not.
+    # 1. Enabled: enabling init containers support
+    # 2. Disabled: disabling init containers support
+    kubernetes.podspec-init-containers: "disabled"
diff --git a/go.mod b/go.mod
index 4fae6209e..0392d87e8 100644
--- a/go.mod
+++ b/go.mod
@@ -45,9 +45,9 @@ require (
 	k8s.io/code-generator v0.21.4
 	k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
 	k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 // indirect
-	knative.dev/caching v0.0.0-20210923061712-f2ac32bda031
+	knative.dev/caching v0.0.0-20211006061346-5d5320f8297c
 	knative.dev/hack v0.0.0-20210806075220-815cd312d65c
-	knative.dev/networking v0.0.0-20210929003422-f9355c551dbe
-	knative.dev/pkg v0.0.0-20210929111822-2267a4cbebb8
+	knative.dev/networking v0.0.0-20211006061346-090366a10f4a
+	knative.dev/pkg v0.0.0-20211005203644-a00ba487121e
 	sigs.k8s.io/yaml v1.3.0
 )
diff --git a/go.sum b/go.sum
index aa82314ce..ab28518d2 100644
--- a/go.sum
+++ b/go.sum
@@ -788,7 +788,6 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
 github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
 github.com/prometheus/common v0.31.1 h1:d18hG4PkHnNAKNMOmFuXFaiY8Us0nird/2m60uS1AMs=
 github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
 github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -944,7 +943,6 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
 go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
-go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -952,7 +950,6 @@ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
 go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1071,7 +1068,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b h1:eB48h3HiRycXNy8E0Gf5e0hv7YT6Kt14L/D73G1fuwo=
 golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1245,7 +1241,6 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1390,7 +1385,6 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210416161957-9910b6c460de/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
 google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
 google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
@@ -1575,15 +1569,14 @@ k8s.io/legacy-cloud-providers v0.21.0/go.mod h1:bNxo7gDg+PGkBmT/MFZswLTWdSWK9kAl
 k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ=
 k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-knative.dev/caching v0.0.0-20210923061712-f2ac32bda031 h1:NpcDooVoCqSapAtqftVfyIUdmJn2iirVwYZ+8PJs/yo=
-knative.dev/caching v0.0.0-20210923061712-f2ac32bda031/go.mod h1:FENM93IwhZILPKQLrERGYvWoJXixk/bswKroV1XEXFo=
+knative.dev/caching v0.0.0-20211006061346-5d5320f8297c h1:L2U33tbF1EzQlqE1wH/t+iAFqWHksRHg1mUZCwcbUTk=
+knative.dev/caching v0.0.0-20211006061346-5d5320f8297c/go.mod h1:W39Eh1CGgFeZE4E7iHIJ493MUAFG4fpBoZARqVG6nX4=
 knative.dev/hack v0.0.0-20210806075220-815cd312d65c h1:nOXoDWAAItwr4o0dp3nHr6skgpVD4IvME/UX84YNl5k=
 knative.dev/hack v0.0.0-20210806075220-815cd312d65c/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20210929003422-f9355c551dbe h1:ZSZeSNYZRkFOz+n9CYaLSlG2jNMCvZt8aRED4+F6lS0=
-knative.dev/networking v0.0.0-20210929003422-f9355c551dbe/go.mod h1:21B8DZiDsh9sLFhc3rgiCNs1hO1rvS9B0gpoR+nrBTI=
-knative.dev/pkg v0.0.0-20210919202233-5ae482141474/go.mod h1:jMSqkNMsrzuy+XR4Yr/BMy7SDVbUOl3KKB6+5MR+ZU8=
-knative.dev/pkg v0.0.0-20210929111822-2267a4cbebb8 h1:Ut2Z22rH5WfybI5hjEfi9fDU7rK6kIduWpSAgoEXh7M=
-knative.dev/pkg v0.0.0-20210929111822-2267a4cbebb8/go.mod h1:r27D20afKNeK+9aNOg+0qMv8JgQcyeP+CAYQIR1jEQY=
+knative.dev/networking v0.0.0-20211006061346-090366a10f4a h1:aKgZubUSnFkJMr1N6JGIdpSoC5PQ0l62BZwIOfUkA8U=
+knative.dev/networking v0.0.0-20211006061346-090366a10f4a/go.mod h1:fUuB+IaSvFjdX4sGmuiEv9NQQ12bORPMLoB6g+hEiSE=
+knative.dev/pkg v0.0.0-20211005203644-a00ba487121e h1:gLyCvMSW2wAN4g3J60nJ9L1Ywzn1DbVMfoNMHR+164w=
+knative.dev/pkg v0.0.0-20211005203644-a00ba487121e/go.mod h1:r27D20afKNeK+9aNOg+0qMv8JgQcyeP+CAYQIR1jEQY=
 pgregory.net/rapid v0.3.3 h1:jCjBsY4ln4Atz78QoBWxUEvAHaFyNDQg9+WU62aCn1U=
 pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/pkg/apis/config/features.go b/pkg/apis/config/features.go
index 17e75fc07..db4f212d6 100644
--- a/pkg/apis/config/features.go
+++ b/pkg/apis/config/features.go
@@ -54,6 +54,7 @@ func defaultFeaturesConfig() *Features {
 		ContainerSpecAddCapabilities: Disabled,
 		PodSpecTolerations:           Disabled,
 		PodSpecVolumesEmptyDir:       Disabled,
+		PodSpecInitContainers:        Disabled,
 		TagHeaderBasedRouting:        Disabled,
 		AutoDetectHTTP2:              Disabled,
 	}
@@ -77,6 +78,7 @@ func NewFeaturesConfigFromMap(data map[string]string) (*Features, error) {
 		asFlag("kubernetes.containerspec-addcapabilities", &nc.ContainerSpecAddCapabilities),
 		asFlag("kubernetes.podspec-tolerations", &nc.PodSpecTolerations),
 		asFlag("kubernetes.podspec-volumes-emptydir", &nc.PodSpecVolumesEmptyDir),
+		asFlag("kubernetes.podspec-init-containers", &nc.PodSpecInitContainers),
 		asFlag("tag-header-based-routing", &nc.TagHeaderBasedRouting),
 		asFlag("autodetect-http2", &nc.AutoDetectHTTP2)); err != nil {
 		return nil, err
@@ -104,6 +106,7 @@ type Features struct {
 	ContainerSpecAddCapabilities Flag
 	PodSpecTolerations           Flag
 	PodSpecVolumesEmptyDir       Flag
+	PodSpecInitContainers        Flag
 	TagHeaderBasedRouting        Flag
 	AutoDetectHTTP2              Flag
 }
diff --git a/pkg/apis/serving/fieldmask.go b/pkg/apis/serving/fieldmask.go
index aa6a86853..772cd764f 100644
--- a/pkg/apis/serving/fieldmask.go
+++ b/pkg/apis/serving/fieldmask.go
@@ -213,10 +213,12 @@ func PodSpecMask(ctx context.Context, in *corev1.PodSpec) *corev1.PodSpec {
 	if cfg.Features.PodSpecSchedulerName != config.Disabled {
 		out.SchedulerName = in.SchedulerName
 	}
+	if cfg.Features.PodSpecInitContainers != config.Disabled {
+		out.InitContainers = in.InitContainers
+	}
 
 	// Disallowed fields
 	// This list is unnecessary, but added here for clarity
-	out.InitContainers = nil
 	out.RestartPolicy = ""
 	out.TerminationGracePeriodSeconds = nil
 	out.ActiveDeadlineSeconds = nil
diff --git a/pkg/apis/serving/k8s_validation.go b/pkg/apis/serving/k8s_validation.go
index 51c506a57..c863f4790 100644
--- a/pkg/apis/serving/k8s_validation.go
+++ b/pkg/apis/serving/k8s_validation.go
@@ -247,7 +247,7 @@ func validateEnvValueFrom(ctx context.Context, source *corev1.EnvVarSource) *api
 }
 
 func getReservedEnvVarsPerContainerType(ctx context.Context) sets.String {
-	if IsInSidecarContainer(ctx) {
+	if IsInSidecarContainer(ctx) || IsInitContainer(ctx) {
 		return reservedSidecarEnvVars
 	}
 	return reservedEnvVars
@@ -316,6 +316,8 @@ func ValidatePodSpec(ctx context.Context, ps corev1.PodSpec) *apis.FieldError {
 
 	errs = errs.Also(ValidatePodSecurityContext(ctx, ps.SecurityContext).ViaField("securityContext"))
 
+	errs = errs.Also(validateInitContainers(ctx, ps.InitContainers, ps.Volumes))
+
 	volumes, err := ValidateVolumes(ctx, ps.Volumes, AllMountedVolumes(ps.Containers))
 	if err != nil {
 		errs = errs.Also(err.ViaField("volumes"))
@@ -338,6 +340,25 @@ func ValidatePodSpec(ctx context.Context, ps corev1.PodSpec) *apis.FieldError {
 	return errs
 }
 
+func validateInitContainers(ctx context.Context, containers []corev1.Container, volumes []corev1.Volume) (errs *apis.FieldError) {
+	if len(containers) == 0 {
+		return nil
+	}
+	features := config.FromContextOrDefaults(ctx).Features
+	if features.PodSpecInitContainers != config.Enabled {
+		return errs.Also(&apis.FieldError{Message: fmt.Sprintf("pod spec support for init-containers is off, "+
+			"but found %d init containers", len(containers))})
+	}
+	volumeMap, err := ValidateVolumes(ctx, volumes, AllMountedVolumes(containers))
+	if err != nil {
+		errs = errs.Also(err.ViaField("volumes"))
+	}
+	for i := range containers {
+		errs = errs.Also(validateInitContainer(ctx, containers[i], volumeMap).ViaFieldIndex("containers", i))
+	}
+	return errs
+}
+
 func validateContainers(ctx context.Context, containers []corev1.Container, volumes map[string]corev1.Volume) (errs *apis.FieldError) {
 	features := config.FromContextOrDefaults(ctx).Features
 	if features.MultiContainer != config.Enabled {
@@ -398,6 +419,36 @@ func validateSidecarContainer(ctx context.Context, container corev1.Container, v
 	return errs.Also(validate(ctx, container, volumes))
 }
 
+func validateInitContainer(ctx context.Context, container corev1.Container, volumes map[string]corev1.Volume) (errs *apis.FieldError) {
+	// This is checked at the K8s side for init containers so better validate early if possible
+	// ref: https://bit.ly/3tLZJV1
+	if container.LivenessProbe != nil {
+		errs = errs.Also(&apis.FieldError{
+			Message: "field not allowed in an init container",
+			Paths:   []string{"livenessProbe"},
+		})
+	}
+	if container.ReadinessProbe != nil {
+		errs = errs.Also(&apis.FieldError{
+			Message: "field not allowed in an init container",
+			Paths:   []string{"readinessProbe"},
+		})
+	}
+	if container.StartupProbe != nil {
+		errs = errs.Also(&apis.FieldError{
+			Message: "field not allowed in an init container",
+			Paths:   []string{"startupProbe"},
+		})
+	}
+	if container.Lifecycle != nil {
+		errs = errs.Also(&apis.FieldError{
+			Message: "field not allowed in an init container",
+			Paths:   []string{"lifecycle"},
+		})
+	}
+	return errs.Also(validate(WithinInitContainer(ctx), container, volumes))
+}
+
 // ValidateContainer validate fields for serving containers
 func ValidateContainer(ctx context.Context, container corev1.Container, volumes map[string]corev1.Volume) (errs *apis.FieldError) {
 	// Single container cannot have multiple ports
@@ -450,7 +501,11 @@ func validate(ctx context.Context, container corev1.Container, volumes map[strin
 		errs = errs.Also(fe)
 	}
 	// Ports
-	errs = errs.Also(validateContainerPorts(container.Ports).ViaField("ports"))
+	if IsInitContainer(ctx) {
+		errs = errs.Also(validateInitContainerPorts(container.Ports).ViaField("ports"))
+	} else {
+		errs = errs.Also(validateContainerPorts(container.Ports).ViaField("ports"))
+	}
 	// Resources
 	errs = errs.Also(validateResources(&container.Resources).ViaField("resources"))
 	// SecurityContext
@@ -557,24 +612,13 @@ func validateContainerPorts(ports []corev1.ContainerPort) *apis.FieldError {
 	// if user didn't set any port, it will set default port user-port=8080.
 	userPort := ports[0]
 
-	errs = errs.Also(apis.CheckDisallowedFields(userPort, *ContainerPortMask(&userPort)))
+	errs = errs.Also(validateContainerPortBasic(userPort))
 
 	// Only allow empty (defaulting to "TCP") or explicit TCP for protocol
 	if userPort.Protocol != "" && userPort.Protocol != corev1.ProtocolTCP {
 		errs = errs.Also(apis.ErrInvalidValue(userPort.Protocol, "protocol"))
 	}
 
-	// Don't allow userPort to conflict with knative system reserved ports
-	if reservedPorts.Has(userPort.ContainerPort) {
-		errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("%d is a reserved port", userPort.ContainerPort), "containerPort",
-			fmt.Sprintf("%d is a reserved port, please use a different value", userPort.ContainerPort)))
-	}
-
-	if userPort.ContainerPort < 0 || userPort.ContainerPort > 65535 {
-		errs = errs.Also(apis.ErrOutOfBoundsValue(userPort.ContainerPort,
-			0, 65535, "containerPort"))
-	}
-
 	if !validPortNames.Has(userPort.Name) {
 		errs = errs.Also(&apis.FieldError{
 			Message: fmt.Sprintf("Port name %v is not allowed", ports[0].Name),
@@ -586,6 +630,32 @@ func validateContainerPorts(ports []corev1.ContainerPort) *apis.FieldError {
 	return errs
 }
 
+func validateInitContainerPorts(ports []corev1.ContainerPort) *apis.FieldError {
+	var errs *apis.FieldError
+	if len(ports) == 0 {
+		return nil
+	}
+	for _, p := range ports {
+		errs = errs.Also(validateContainerPortBasic(p))
+	}
+	return errs
+}
+
+func validateContainerPortBasic(port corev1.ContainerPort) *apis.FieldError {
+	var errs *apis.FieldError
+	errs = errs.Also(apis.CheckDisallowedFields(port, *ContainerPortMask(&port)))
+
+	if reservedPorts.Has(port.ContainerPort) {
+		errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("%d is a reserved port", port.ContainerPort), "containerPort",
+			fmt.Sprintf("%d is a reserved port, please use a different value", port.ContainerPort)))
+	}
+
+	if port.ContainerPort < 0 || port.ContainerPort > 65535 {
+		errs = errs.Also(apis.ErrOutOfBoundsValue(port.ContainerPort, 0, 65535, "containerPort"))
+	}
+	return errs
+}
+
 func validateReadinessProbe(p *corev1.Probe) *apis.FieldError {
 	if p == nil {
 		return nil
@@ -757,3 +827,18 @@ func WithinSidecarContainer(ctx context.Context) context.Context {
 func IsInSidecarContainer(ctx context.Context) bool {
 	return ctx.Value(sidecarContainer{}) != nil
 }
+
+// This is attached to contexts as they are passed down through an init container
+// being validated.
+type initContainer struct{}
+
+// WithinInitContainer notes on the context that further validation or defaulting
+// is within the context of an init container in the revision.
+func WithinInitContainer(ctx context.Context) context.Context {
+	return context.WithValue(ctx, initContainer{}, struct{}{})
+}
+
+// IsInitContainer checks if we are in the context of an init container in the revision.
+func IsInitContainer(ctx context.Context) bool {
+	return ctx.Value(initContainer{}) != nil
+}
diff --git a/vendor/knative.dev/pkg/apis/contexts.go b/vendor/knative.dev/pkg/apis/contexts.go
index a8c7683a4..b9835fc00 100644
--- a/vendor/knative.dev/pkg/apis/contexts.go
+++ b/vendor/knative.dev/pkg/apis/contexts.go
@@ -18,6 +18,7 @@ package apis
 
 import (
 	"context"
+	"net/http"
 
 	authenticationv1 "k8s.io/api/authentication/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -233,3 +234,22 @@ func WithDryRun(ctx context.Context) context.Context {
 func IsDryRun(ctx context.Context) bool {
 	return ctx.Value(isDryRun{}) != nil
 }
+
+// This is attached to contexts passed to webhook interfaces with
+// additional context from the HTTP request.
+type httpReq struct{}
+
+// WithHTTPRequest associated the HTTP request object the webhook
+// received with the context.
+func WithHTTPRequest(ctx context.Context, r *http.Request) context.Context {
+	return context.WithValue(ctx, httpReq{}, r)
+}
+
+// GetHTTPRequest fetches the raw HTTP request received by the webhook.
+func GetHTTPRequest(ctx context.Context) *http.Request {
+	v := ctx.Value(httpReq{})
+	if v == nil {
+		return nil
+	}
+	return v.(*http.Request)
+}
diff --git a/vendor/knative.dev/pkg/tracker/enqueue.go b/vendor/knative.dev/pkg/tracker/enqueue.go
index 70fbe0e46..88d0254b3 100644
--- a/vendor/knative.dev/pkg/tracker/enqueue.go
+++ b/vendor/knative.dev/pkg/tracker/enqueue.go
@@ -95,7 +95,10 @@ func (i *impl) TrackReference(ref Reference, obj interface{}) error {
 	invalidFields := map[string][]string{
 		"APIVersion": validation.IsQualifiedName(ref.APIVersion),
 		"Kind":       validation.IsCIdentifier(ref.Kind),
-		"Namespace":  validation.IsDNS1123Label(ref.Namespace),
+	}
+	// Allow namespace to be empty for cluster-scoped references.
+	if ref.Namespace != "" {
+		invalidFields["Namespace"] = validation.IsDNS1123Label(ref.Namespace)
 	}
 	var selector labels.Selector
 	fieldErrors := []string{}
diff --git a/vendor/knative.dev/pkg/webhook/admission.go b/vendor/knative.dev/pkg/webhook/admission.go
index 4d00c746b..ff14585f7 100644
--- a/vendor/knative.dev/pkg/webhook/admission.go
+++ b/vendor/knative.dev/pkg/webhook/admission.go
@@ -26,6 +26,7 @@ import (
 	"go.uber.org/zap"
 	admissionv1 "k8s.io/api/admission/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	"knative.dev/pkg/apis"
 	"knative.dev/pkg/logging"
 	"knative.dev/pkg/logging/logkey"
 )
@@ -104,6 +105,7 @@ func admissionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c Admi
 			logkey.UserInfo, fmt.Sprint(review.Request.UserInfo))
 
 		ctx := logging.WithLogger(r.Context(), logger)
+		ctx = apis.WithHTTPRequest(ctx, r)
 
 		response := admissionv1.AdmissionReview{
 			// Use the same type meta as the request - this is required by the K8s API
diff --git a/vendor/knative.dev/pkg/webhook/conversion.go b/vendor/knative.dev/pkg/webhook/conversion.go
index 3ee306671..201ff41f4 100644
--- a/vendor/knative.dev/pkg/webhook/conversion.go
+++ b/vendor/knative.dev/pkg/webhook/conversion.go
@@ -24,6 +24,7 @@ import (
 
 	"go.uber.org/zap"
 	apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+	"knative.dev/pkg/apis"
 	"knative.dev/pkg/logging"
 )
 
@@ -53,6 +54,8 @@ func conversionHandler(rootLogger *zap.SugaredLogger, _ StatsReporter, c Convers
 		)
 
 		ctx := logging.WithLogger(r.Context(), logger)
+		ctx = apis.WithHTTPRequest(ctx, r)
+
 		response := apixv1.ConversionReview{
 			// Use the same type meta as the request - this is required by the K8s API
 			// note: v1beta1 & v1 ConversionReview shapes are identical so even though
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 676b40b8f..9d4b6c3bb 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1019,7 +1019,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20210923061712-f2ac32bda031
+# knative.dev/caching v0.0.0-20211006061346-5d5320f8297c
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -1044,7 +1044,7 @@ knative.dev/caching/pkg/client/listers/caching/v1alpha1
 ## explicit
 knative.dev/hack
 knative.dev/hack/shell
-# knative.dev/networking v0.0.0-20210929003422-f9355c551dbe
+# knative.dev/networking v0.0.0-20211006061346-090366a10f4a
 ## explicit
 knative.dev/networking/config
 knative.dev/networking/pkg
@@ -1074,7 +1074,7 @@ knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serve
 knative.dev/networking/pkg/client/listers/networking/v1alpha1
 knative.dev/networking/pkg/ingress
 knative.dev/networking/pkg/prober
-# knative.dev/pkg v0.0.0-20210929111822-2267a4cbebb8
+# knative.dev/pkg v0.0.0-20211005203644-a00ba487121e
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate


Test patch:
diff --git a/pkg/apis/config/features_test.go b/pkg/apis/config/features_test.go
index cc35f5b68..e38419f5f 100644
--- a/pkg/apis/config/features_test.go
+++ b/pkg/apis/config/features_test.go
@@ -354,6 +354,24 @@ func TestFeaturesConfiguration(t *testing.T) {
 		data: map[string]string{
 			"kubernetes.podspec-volumes-emptydir": "Enabled",
 		},
+	}, {
+		name:    "kubernetes.podspec-init-containers Disabled",
+		wantErr: false,
+		wantFeatures: defaultWith(&Features{
+			PodSpecInitContainers: Disabled,
+		}),
+		data: map[string]string{
+			"kubernetes.podspec-init-containers": "Disabled",
+		},
+	}, {
+		name:    "kubernetes.podspec-init-container Enabled",
+		wantErr: false,
+		wantFeatures: defaultWith(&Features{
+			PodSpecInitContainers: Enabled,
+		}),
+		data: map[string]string{
+			"kubernetes.podspec-init-containers": "Enabled",
+		},
 	}, {
 		name:    "kubernetes.podspec-priorityclassname Allowed",
 		wantErr: false,
diff --git a/pkg/apis/serving/k8s_validation_test.go b/pkg/apis/serving/k8s_validation_test.go
index 836f2cbbe..e170f2c51 100644
--- a/pkg/apis/serving/k8s_validation_test.go
+++ b/pkg/apis/serving/k8s_validation_test.go
@@ -35,6 +35,14 @@ import (
 
 type configOption func(*config.Config) *config.Config
 
+type containerValidationTestCase struct {
+	name    string
+	c       corev1.Container
+	want    *apis.FieldError
+	volumes map[string]corev1.Volume
+	cfgOpts []configOption
+}
+
 func withMultiContainerDisabled() configOption {
 	return func(cfg *config.Config) *config.Config {
 		cfg.Features.MultiContainer = config.Disabled
@@ -119,6 +127,13 @@ func withPodSpecSchedulerNameEnabled() configOption {
 	}
 }
 
+func withPodSpecInitContainersEnabled() configOption {
+	return func(cfg *config.Config) *config.Config {
+		cfg.Features.PodSpecInitContainers = config.Enabled
+		return cfg
+	}
+}
+
 func TestPodSpecValidation(t *testing.T) {
 	tests := []struct {
 		name    string
@@ -274,11 +289,9 @@ func TestPodSpecValidation(t *testing.T) {
 			Containers: []corev1.Container{{
 				Image: "busybox",
 			}},
-			InitContainers: []corev1.Container{{
-				Image: "helloworld",
-			}},
+			TerminationGracePeriodSeconds: ptr.Int64(5),
 		},
-		want: apis.ErrDisallowedFields("initContainers"),
+		want: apis.ErrDisallowedFields("terminationGracePeriodSeconds"),
 	}, {
 		name: "bad service account name",
 		ps: corev1.PodSpec{
@@ -891,770 +904,866 @@ func TestPodSpecFieldRefValidation(t *testing.T) {
 }
 
 func TestContainerValidation(t *testing.T) {
-	bidir := corev1.MountPropagationBidirectional
-
-	tests := []struct {
-		name    string
-		c       corev1.Container
-		want    *apis.FieldError
-		volumes map[string]corev1.Volume
-		cfgOpts []configOption
-	}{{
-		name: "empty container",
-		c:    corev1.Container{},
-		want: apis.ErrMissingField(apis.CurrentField),
-	}, {
-		name: "valid container",
-		c: corev1.Container{
-			Image: "foo",
-		},
-		want: nil,
-	}, {
-		name: "invalid container image",
-		c: corev1.Container{
-			Image: "foo:bar:baz",
-		},
-		want: &apis.FieldError{
-			Message: "Failed to parse image reference",
-			Paths:   []string{"image"},
-			Details: `image: "foo:bar:baz", error: could not parse reference: foo:bar:baz`,
-		},
-	}, {
-		name: "has a lifecycle",
-		c: corev1.Container{
-			Name:      "foo",
-			Image:     "foo",
-			Lifecycle: &corev1.Lifecycle{},
+	tests := []containerValidationTestCase{
+		{
+			name: "has a lifecycle",
+			c: corev1.Container{
+				Name:      "foo",
+				Image:     "foo",
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want:    apis.ErrDisallowedFields("lifecycle"),
+			cfgOpts: []configOption{withPodSpecInitContainersEnabled()},
+		}, {
+			name: "has lifecycle",
+			c: corev1.Container{
+				Image:     "foo",
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want: apis.ErrDisallowedFields("lifecycle"),
 		},
-		want: apis.ErrDisallowedFields("lifecycle"),
-	}, {
-		name: "has resources",
-		c: corev1.Container{
-			Image: "foo",
-			Resources: corev1.ResourceRequirements{
-				Limits: corev1.ResourceList{
-					corev1.ResourceMemory: resource.MustParse("250M"),
+		{
+			name: "has valid unnamed user port",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8181,
+				}},
+			},
+			want: nil,
+		}, {
+			name: "has valid user port http1",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Name: "http1",
+				}},
+			},
+			want: nil,
+		}, {
+			name: "has valid user port h2c",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Name: "h2c",
+				}},
+			},
+			want: nil,
+		}, {
+			name: "has more than one ports with valid names",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Name: "h2c",
+				}, {
+					Name: "http1",
+				}},
+			},
+			want: &apis.FieldError{
+				Message: "More than one container port is set",
+				Paths:   []string{"ports"},
+				Details: "Only a single port is allowed",
+			},
+		}, {
+			name: "has an empty port set",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{}},
+			},
+			want: nil,
+		}, {
+			name: "has more than one unnamed port",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8080,
+				}, {
+					ContainerPort: 8181,
+				}},
+			},
+			want: &apis.FieldError{
+				Message: "More than one container port is set",
+				Paths:   []string{"ports"},
+				Details: "Only a single port is allowed",
+			},
+		}, {
+			name: "has tcp protocol",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Protocol: corev1.ProtocolTCP,
+				}},
+			},
+			want: nil,
+		}, {
+			name: "has invalid protocol",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Protocol: "tdp",
+				}},
+			},
+			want: apis.ErrInvalidValue("tdp", "ports.protocol"),
+		}, {
+			name: "has host port",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					HostPort: 80,
+				}},
+			},
+			want: apis.ErrDisallowedFields("ports.hostPort"),
+		}, {
+			name: "has invalid port name",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					Name: "foobar",
+				}},
+			},
+			want: &apis.FieldError{
+				Message: fmt.Sprintf("Port name %v is not allowed", "foobar"),
+				Paths:   []string{"ports"},
+				Details: "Name must be empty, or one of: 'h2c', 'http1'",
+			},
+		}, {
+			name: "valid with probes (no port)",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    1,
+					TimeoutSeconds:   1,
+					SuccessThreshold: 1,
+					FailureThreshold: 3,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
+						},
+					},
 				},
-				Requests: corev1.ResourceList{
-					corev1.ResourceCPU: resource.MustParse("25m"),
+				LivenessProbe: &corev1.Probe{
+					Handler: corev1.Handler{
+						TCPSocket: &corev1.TCPSocketAction{},
+					},
 				},
 			},
-		},
-		want: nil,
-	}, {
-		name: "has no container ports set",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{},
-		},
-		want: nil,
-	}, {
-		name: "has valid unnamed user port",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8181,
-			}},
-		},
-		want: nil,
-	}, {
-		name: "has valid user port http1",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Name: "http1",
-			}},
-		},
-		want: nil,
-	}, {
-		name: "has valid user port h2c",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Name: "h2c",
-			}},
-		},
-		want: nil,
-	}, {
-		name: "has more than one ports with valid names",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Name: "h2c",
-			}, {
-				Name: "http1",
-			}},
-		},
-		want: &apis.FieldError{
-			Message: "More than one container port is set",
-			Paths:   []string{"ports"},
-			Details: "Only a single port is allowed",
-		},
-	}, {
-		name: "has container port value too large",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 65536,
-			}},
-		},
-		want: apis.ErrOutOfBoundsValue(65536, 0, 65535, "ports.containerPort"),
-	}, {
-		name: "has an empty port set",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{}},
-		},
-		want: nil,
-	}, {
-		name: "has more than one unnamed port",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8080,
-			}, {
-				ContainerPort: 8181,
-			}},
-		},
-		want: &apis.FieldError{
-			Message: "More than one container port is set",
-			Paths:   []string{"ports"},
-			Details: "Only a single port is allowed",
-		},
-	}, {
-		name: "has tcp protocol",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Protocol: corev1.ProtocolTCP,
-			}},
-		},
-		want: nil,
-	}, {
-		name: "has invalid protocol",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Protocol: "tdp",
-			}},
-		},
-		want: apis.ErrInvalidValue("tdp", "ports.protocol"),
-	}, {
-		name: "has host port",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				HostPort: 80,
-			}},
-		},
-		want: apis.ErrDisallowedFields("ports.hostPort"),
-	}, {
-		name: "has host ip",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				HostIP: "127.0.0.1",
-			}},
-		},
-		want: apis.ErrDisallowedFields("ports.hostIP"),
-	}, {
-		name: "port conflicts with queue proxy admin",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8022,
-			}},
-		},
-		want: apis.ErrInvalidValue("8022 is a reserved port", "ports.containerPort",
-			"8022 is a reserved port, please use a different value"),
-	}, {
-		name: "port conflicts with profiling port",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8008,
-			}},
-		},
-		want: apis.ErrInvalidValue("8008 is a reserved port", "ports.containerPort",
-			"8008 is a reserved port, please use a different value"),
-	}, {
-		name: "port conflicts with queue proxy",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8013,
-			}},
-		},
-		want: apis.ErrInvalidValue("8013 is a reserved port", "ports.containerPort",
-			"8013 is a reserved port, please use a different value"),
-	}, {
-		name: "port conflicts with queue proxy",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8012,
-			}},
-		},
-		want: apis.ErrInvalidValue("8012 is a reserved port", "ports.containerPort",
-			"8012 is a reserved port, please use a different value"),
-	}, {
-		name: "port conflicts with queue proxy metrics",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 9090,
-			}},
-		},
-		want: apis.ErrInvalidValue("9090 is a reserved port", "ports.containerPort",
-			"9090 is a reserved port, please use a different value"),
-	}, {
-		name: "port conflicts with user queue proxy metrics for user",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 9091,
-			}},
-		},
-		want: apis.ErrInvalidValue("9091 is a reserved port", "ports.containerPort",
-			"9091 is a reserved port, please use a different value"),
-	}, {
-		name: "has invalid port name",
-		c: corev1.Container{
-			Image: "foo",
-			Ports: []corev1.ContainerPort{{
-				Name: "foobar",
-			}},
-		},
-		want: &apis.FieldError{
-			Message: fmt.Sprintf("Port name %v is not allowed", "foobar"),
-			Paths:   []string{"ports"},
-			Details: "Name must be empty, or one of: 'h2c', 'http1'",
-		},
-	}, {
-		name: "has unknown volumeMounts",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				Name:             "the-name",
-				SubPath:          "oops",
-				MountPropagation: &bidir,
-			}},
-		},
-		want: (&apis.FieldError{
-			Message: "volumeMount has no matching volume",
-			Paths:   []string{"name"},
-		}).ViaFieldIndex("volumeMounts", 0).Also(
-			apis.ErrMissingField("readOnly").ViaFieldIndex("volumeMounts", 0)).Also(
-			apis.ErrMissingField("mountPath").ViaFieldIndex("volumeMounts", 0)).Also(
-			apis.ErrDisallowedFields("mountPropagation").ViaFieldIndex("volumeMounts", 0)),
-	}, {
-		name: "has known volumeMounts",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				MountPath: "/mount/path",
-				Name:      "the-name",
-				ReadOnly:  true,
-			}},
-		},
-		volumes: map[string]corev1.Volume{
-			"the-name": {
-				Name: "the-name",
-				VolumeSource: corev1.VolumeSource{
-					ConfigMap: &corev1.ConfigMapVolumeSource{
-						LocalObjectReference: corev1.LocalObjectReference{
-							Name: "test-cm",
+			want: nil,
+		}, {
+			name: "valid with exec probes ",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					InitialDelaySeconds: 0,
+					PeriodSeconds:       1,
+					TimeoutSeconds:      1,
+					SuccessThreshold:    1,
+					FailureThreshold:    3,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
 						},
 					},
 				},
+				LivenessProbe: &corev1.Probe{
+					Handler: corev1.Handler{
+						Exec: &corev1.ExecAction{},
+					},
+				},
 			},
-		},
-	}, {
-		name: "has known volumeMounts, but at reserved path",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				MountPath: "//var//log//",
-				Name:      "the-name",
-				ReadOnly:  true,
-			}},
-		},
-		volumes: map[string]corev1.Volume{
-			"the-name": {
-				Name: "the-name",
-				VolumeSource: corev1.VolumeSource{
-					ConfigMap: &corev1.ConfigMapVolumeSource{
-						LocalObjectReference: corev1.LocalObjectReference{
-							Name: "test-cm",
+			want: nil,
+		}, {
+			name: "invalid with no handler",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    1,
+					TimeoutSeconds:   1,
+					SuccessThreshold: 1,
+					FailureThreshold: 3,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
 						},
 					},
 				},
+				LivenessProbe: &corev1.Probe{
+					Handler: corev1.Handler{},
+				},
 			},
-		},
-		want: (&apis.FieldError{
-			Message: `mountPath "/var/log" is a reserved path`,
-			Paths:   []string{"mountPath"},
-		}).ViaFieldIndex("volumeMounts", 0),
-	}, {
-		name: "has known volumeMounts, bad mountPath",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				MountPath: "not/absolute",
-				Name:      "the-name",
-				ReadOnly:  true,
-			}},
-		},
-		volumes: map[string]corev1.Volume{
-			"the-name": {
-				Name: "the-name",
-				VolumeSource: corev1.VolumeSource{
-					ConfigMap: &corev1.ConfigMapVolumeSource{
-						LocalObjectReference: corev1.LocalObjectReference{
-							Name: "test-cm",
+			want: apis.ErrMissingOneOf("livenessProbe.httpGet", "livenessProbe.tcpSocket", "livenessProbe.exec"),
+		}, {
+			name: "invalid with multiple handlers",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    1,
+					TimeoutSeconds:   1,
+					SuccessThreshold: 1,
+					FailureThreshold: 3,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
 						},
+						Exec:      &corev1.ExecAction{},
+						TCPSocket: &corev1.TCPSocketAction{},
 					},
 				},
 			},
-		},
-		want: apis.ErrInvalidValue("not/absolute", "volumeMounts[0].mountPath"),
-	}, {
-		name: "Empty dir has rw access",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				MountPath: "/mount/path",
-				Name:      "the-name",
-			}},
-		},
-		volumes: map[string]corev1.Volume{
-			"the-name": {
-				Name: "the-name",
-				VolumeSource: corev1.VolumeSource{
-					EmptyDir: &corev1.EmptyDirVolumeSource{
-						Medium: "Memory",
+			want: apis.ErrMultipleOneOf("readinessProbe.exec", "readinessProbe.tcpSocket", "readinessProbe.httpGet"),
+		}, {
+			name: "invalid readiness http probe (has port)",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    1,
+					TimeoutSeconds:   1,
+					SuccessThreshold: 1,
+					FailureThreshold: 3,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
+							Port: intstr.FromInt(8080),
+						},
 					},
 				},
 			},
-		},
-	}, {
-		name: "has lifecycle",
-		c: corev1.Container{
-			Image:     "foo",
-			Lifecycle: &corev1.Lifecycle{},
-		},
-		want: apis.ErrDisallowedFields("lifecycle"),
-	}, {
-		name: "has known volumeMount twice",
-		c: corev1.Container{
-			Image: "foo",
-			VolumeMounts: []corev1.VolumeMount{{
-				MountPath: "/mount/path",
-				Name:      "the-name",
-				ReadOnly:  true,
-			}, {
-				MountPath: "/another/mount/path",
-				Name:      "the-name",
-				ReadOnly:  true,
-			}},
-		},
-		volumes: map[string]corev1.Volume{
-			"the-name": {
-				Name: "the-name",
-				VolumeSource: corev1.VolumeSource{
-					ConfigMap: &corev1.ConfigMapVolumeSource{
-						LocalObjectReference: corev1.LocalObjectReference{
-							Name: "test-cm",
+			want: apis.ErrDisallowedFields("readinessProbe.httpGet.port"),
+		}, {
+			name: "invalid readiness probe (has failureThreshold while using special probe)",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    0,
+					FailureThreshold: 2,
+					SuccessThreshold: 1,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
 						},
 					},
 				},
 			},
-		},
-	}, {
-		name: "valid with probes (no port)",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    1,
-				TimeoutSeconds:   1,
-				SuccessThreshold: 1,
-				FailureThreshold: 3,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+			want: &apis.FieldError{
+				Message: "failureThreshold is disallowed when periodSeconds is zero",
+				Paths:   []string{"readinessProbe.failureThreshold"},
+			},
+		}, {
+			name: "invalid readiness probe (has timeoutSeconds while using special probe)",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:    0,
+					TimeoutSeconds:   2,
+					SuccessThreshold: 1,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{
+							Path: "/",
+						},
 					},
 				},
 			},
-			LivenessProbe: &corev1.Probe{
-				Handler: corev1.Handler{
-					TCPSocket: &corev1.TCPSocketAction{},
-				},
+			want: &apis.FieldError{
+				Message: "timeoutSeconds is disallowed when periodSeconds is zero",
+				Paths:   []string{"readinessProbe.timeoutSeconds"},
 			},
-		},
-		want: nil,
-	}, {
-		name: "valid with exec probes ",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				InitialDelaySeconds: 0,
-				PeriodSeconds:       1,
-				TimeoutSeconds:      1,
-				SuccessThreshold:    1,
-				FailureThreshold:    3,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+		}, {
+			name: "out of bounds probe values",
+			c: corev1.Container{
+				Image: "foo",
+				ReadinessProbe: &corev1.Probe{
+					PeriodSeconds:       -1,
+					TimeoutSeconds:      0,
+					SuccessThreshold:    0,
+					FailureThreshold:    0,
+					InitialDelaySeconds: -1,
+					Handler: corev1.Handler{
+						HTTPGet: &corev1.HTTPGetAction{},
 					},
 				},
 			},
-			LivenessProbe: &corev1.Probe{
-				Handler: corev1.Handler{
-					Exec: &corev1.ExecAction{},
+			want: apis.ErrOutOfBoundsValue(-1, 0, math.MaxInt32, "readinessProbe.periodSeconds").Also(
+				apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.timeoutSeconds")).Also(
+				apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.successThreshold")).Also(
+				apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.failureThreshold")).Also(
+				apis.ErrOutOfBoundsValue(-1, 0, math.MaxInt32, "readinessProbe.initialDelaySeconds")),
+		}, {
+			name: "reserved env var name for serving container",
+			c: corev1.Container{
+				Image: "foo",
+				Env: []corev1.EnvVar{{
+					Name:  "PORT",
+					Value: "Foo",
+				}},
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8888,
+				}},
+			},
+			want: &apis.FieldError{
+				Message: `"PORT" is a reserved environment variable`,
+				Paths:   []string{"env[0].name"},
+			},
+		}, {
+			name: "invalid liveness tcp probe (has port)",
+			c: corev1.Container{
+				Image: "foo",
+				LivenessProbe: &corev1.Probe{
+					Handler: corev1.Handler{
+						TCPSocket: &corev1.TCPSocketAction{
+							Port: intstr.FromString("http"),
+						},
+					},
 				},
 			},
+			want: apis.ErrDisallowedFields("livenessProbe.tcpSocket.port"),
+		}, {
+			name: "disallowed container fields",
+			c: corev1.Container{
+				Image:     "foo",
+				Name:      "fail",
+				Stdin:     true,
+				StdinOnce: true,
+				TTY:       true,
+				Lifecycle: &corev1.Lifecycle{},
+				VolumeDevices: []corev1.VolumeDevice{{
+					Name:       "disallowed",
+					DevicePath: "/",
+				}},
+			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(
+				apis.ErrDisallowedFields("stdin")).Also(
+				apis.ErrDisallowedFields("stdinOnce")).Also(
+				apis.ErrDisallowedFields("tty")).Also(
+				apis.ErrDisallowedFields("volumeDevices")),
+		}, {
+			name: "has numerous problems",
+			c: corev1.Container{
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(
+				apis.ErrMissingField("image")),
 		},
-		want: nil,
-	}, {
-		name: "invalid with no handler",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    1,
-				TimeoutSeconds:   1,
-				SuccessThreshold: 1,
-				FailureThreshold: 3,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+	}
+	tests = append(tests, getCommonContainerValidationTestCases()...)
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			ctx := context.Background()
+			if test.cfgOpts != nil {
+				cfg := config.FromContextOrDefaults(ctx)
+				for _, opt := range test.cfgOpts {
+					cfg = opt(cfg)
+				}
+				ctx = config.ToContext(ctx, cfg)
+			}
+
+			got := ValidateContainer(ctx, test.c, test.volumes)
+			if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" {
+				t.Errorf("ValidateContainer (-want, +got): \n%s", diff)
+			}
+		})
+	}
+}
+
+func TestInitContainerValidation(t *testing.T) {
+	tests := []containerValidationTestCase{
+		{
+			name: "has a lifecycle",
+			c: corev1.Container{
+				Name:      "foo",
+				Image:     "foo",
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(&apis.FieldError{
+				Message: "field not allowed in an init container",
+				Paths:   []string{"lifecycle"},
+			}),
+			cfgOpts: []configOption{withPodSpecInitContainersEnabled()},
+		}, {
+			name: "has lifecycle",
+			c: corev1.Container{
+				Image:     "foo",
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(&apis.FieldError{
+				Message: "field not allowed in an init container",
+				Paths:   []string{"lifecycle"},
+			}),
+		}, {
+			name: "invalid liveness tcp probe (has port)",
+			c: corev1.Container{
+				Image: "foo",
+				LivenessProbe: &corev1.Probe{
+					Handler: corev1.Handler{
+						TCPSocket: &corev1.TCPSocketAction{
+							Port: intstr.FromString("http"),
+						},
 					},
 				},
 			},
-			LivenessProbe: &corev1.Probe{
-				Handler: corev1.Handler{},
+			want: &apis.FieldError{
+				Message: "field not allowed in an init container",
+				Paths:   []string{"livenessProbe"}},
+		}, {
+			name: "disallowed container fields",
+			c: corev1.Container{
+				Image:     "foo",
+				Name:      "fail",
+				Stdin:     true,
+				StdinOnce: true,
+				TTY:       true,
+				Lifecycle: &corev1.Lifecycle{},
+				VolumeDevices: []corev1.VolumeDevice{{
+					Name:       "disallowed",
+					DevicePath: "/",
+				}},
 			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(
+				&apis.FieldError{
+					Message: "field not allowed in an init container",
+					Paths:   []string{"lifecycle"},
+				}).Also(
+				apis.ErrDisallowedFields("stdin")).Also(
+				apis.ErrDisallowedFields("stdinOnce")).Also(
+				apis.ErrDisallowedFields("tty")).Also(
+				apis.ErrDisallowedFields("volumeDevices")),
+		}, {
+			name: "has numerous problems",
+			c: corev1.Container{
+				Lifecycle: &corev1.Lifecycle{},
+			},
+			want: apis.ErrDisallowedFields("lifecycle").Also(
+				&apis.FieldError{
+					Message: "field not allowed in an init container",
+					Paths:   []string{"lifecycle"},
+				}).Also(apis.ErrMissingField("image")),
 		},
-		want: apis.ErrMissingOneOf("livenessProbe.httpGet", "livenessProbe.tcpSocket", "livenessProbe.exec"),
-	}, {
-		name: "invalid with multiple handlers",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    1,
-				TimeoutSeconds:   1,
-				SuccessThreshold: 1,
-				FailureThreshold: 3,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+	}
+	tests = append(tests, getCommonContainerValidationTestCases()...)
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			ctx := context.Background()
+			if test.cfgOpts != nil {
+				cfg := config.FromContextOrDefaults(ctx)
+				for _, opt := range test.cfgOpts {
+					cfg = opt(cfg)
+				}
+				ctx = config.ToContext(ctx, cfg)
+			}
+			got := validateInitContainer(ctx, test.c, test.volumes)
+			if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" {
+				t.Errorf("ValidateInitContainer (-want, +got): \n%s", diff)
+			}
+		})
+	}
+}
+
+func getCommonContainerValidationTestCases() []containerValidationTestCase {
+	bidir := corev1.MountPropagationBidirectional
+	return []containerValidationTestCase{
+		{
+			name:    "empty container",
+			c:       corev1.Container{},
+			want:    apis.ErrMissingField(apis.CurrentField),
+			cfgOpts: []configOption{withPodSpecInitContainersEnabled()},
+		}, {
+			name: "valid container",
+			c: corev1.Container{
+				Image: "foo",
+			},
+			want: nil,
+		}, {
+			name: "invalid container image",
+			c: corev1.Container{
+				Image: "foo:bar:baz",
+			},
+			want: &apis.FieldError{
+				Message: "Failed to parse image reference",
+				Paths:   []string{"image"},
+				Details: `image: "foo:bar:baz", error: could not parse reference: foo:bar:baz`,
+			},
+		}, {
+			name: "has resources",
+			c: corev1.Container{
+				Image: "foo",
+				Resources: corev1.ResourceRequirements{
+					Limits: corev1.ResourceList{
+						corev1.ResourceMemory: resource.MustParse("250M"),
+					},
+					Requests: corev1.ResourceList{
+						corev1.ResourceCPU: resource.MustParse("25m"),
 					},
-					Exec:      &corev1.ExecAction{},
-					TCPSocket: &corev1.TCPSocketAction{},
 				},
 			},
-		},
-		want: apis.ErrMultipleOneOf("readinessProbe.exec", "readinessProbe.tcpSocket", "readinessProbe.httpGet"),
-	}, {
-		name: "invalid readiness http probe (has port)",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    1,
-				TimeoutSeconds:   1,
-				SuccessThreshold: 1,
-				FailureThreshold: 3,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
-						Port: intstr.FromInt(8080),
+			want: nil,
+		}, {
+			name: "has no container ports set",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{},
+			},
+			want: nil,
+		}, {
+			name: "has container port value too large",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 65536,
+				}},
+			},
+			want: apis.ErrOutOfBoundsValue(65536, 0, 65535, "ports.containerPort"),
+		}, {
+			name: "has host ip",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					HostIP: "127.0.0.1",
+				}},
+			},
+			want: apis.ErrDisallowedFields("ports.hostIP"),
+		}, {
+			name: "port conflicts with profiling port",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8008,
+				}},
+			},
+			want: apis.ErrInvalidValue("8008 is a reserved port", "ports.containerPort",
+				"8008 is a reserved port, please use a different value"),
+		}, {
+			name: "port conflicts with queue proxy",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8013,
+				}},
+			},
+			want: apis.ErrInvalidValue("8013 is a reserved port", "ports.containerPort",
+				"8013 is a reserved port, please use a different value"),
+		}, {
+			name: "port conflicts with queue proxy",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8012,
+				}},
+			},
+			want: apis.ErrInvalidValue("8012 is a reserved port", "ports.containerPort",
+				"8012 is a reserved port, please use a different value"),
+		}, {
+			name: "port conflicts with queue proxy metrics",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 9090,
+				}},
+			},
+			want: apis.ErrInvalidValue("9090 is a reserved port", "ports.containerPort",
+				"9090 is a reserved port, please use a different value"),
+		}, {
+			name: "port conflicts with user queue proxy metrics for user",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 9091,
+				}},
+			},
+			want: apis.ErrInvalidValue("9091 is a reserved port", "ports.containerPort",
+				"9091 is a reserved port, please use a different value"),
+		}, {
+			name: "port conflicts with queue proxy admin",
+			c: corev1.Container{
+				Image: "foo",
+				Ports: []corev1.ContainerPort{{
+					ContainerPort: 8022,
+				}},
+			},
+			want: apis.ErrInvalidValue("8022 is a reserved port", "ports.containerPort",
+				"8022 is a reserved port, please use a different value"),
+		}, {
+			name: "has unknown volumeMounts",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					Name:             "the-name",
+					SubPath:          "oops",
+					MountPropagation: &bidir,
+				}},
+			},
+			want: (&apis.FieldError{
+				Message: "volumeMount has no matching volume",
+				Paths:   []string{"name"},
+			}).ViaFieldIndex("volumeMounts", 0).Also(
+				apis.ErrMissingField("readOnly").ViaFieldIndex("volumeMounts", 0)).Also(
+				apis.ErrMissingField("mountPath").ViaFieldIndex("volumeMounts", 0)).Also(
+				apis.ErrDisallowedFields("mountPropagation").ViaFieldIndex("volumeMounts", 0)),
+		}, {
+			name: "has known volumeMounts",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					MountPath: "/mount/path",
+					Name:      "the-name",
+					ReadOnly:  true,
+				}},
+			},
+			volumes: map[string]corev1.Volume{
+				"the-name": {
+					Name: "the-name",
+					VolumeSource: corev1.VolumeSource{
+						ConfigMap: &corev1.ConfigMapVolumeSource{
+							LocalObjectReference: corev1.LocalObjectReference{
+								Name: "test-cm",
+							},
+						},
 					},
 				},
 			},
-		},
-		want: apis.ErrDisallowedFields("readinessProbe.httpGet.port"),
-	}, {
-		name: "invalid readiness probe (has failureThreshold while using special probe)",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    0,
-				FailureThreshold: 2,
-				SuccessThreshold: 1,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+		}, {
+			name: "has known volumeMounts, but at reserved path",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					MountPath: "//var//log//",
+					Name:      "the-name",
+					ReadOnly:  true,
+				}},
+			},
+			volumes: map[string]corev1.Volume{
+				"the-name": {
+					Name: "the-name",
+					VolumeSource: corev1.VolumeSource{
+						ConfigMap: &corev1.ConfigMapVolumeSource{
+							LocalObjectReference: corev1.LocalObjectReference{
+								Name: "test-cm",
+							},
+						},
 					},
 				},
 			},
-		},
-		want: &apis.FieldError{
-			Message: "failureThreshold is disallowed when periodSeconds is zero",
-			Paths:   []string{"readinessProbe.failureThreshold"},
-		},
-	}, {
-		name: "invalid readiness probe (has timeoutSeconds while using special probe)",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:    0,
-				TimeoutSeconds:   2,
-				SuccessThreshold: 1,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{
-						Path: "/",
+			want: (&apis.FieldError{
+				Message: `mountPath "/var/log" is a reserved path`,
+				Paths:   []string{"mountPath"},
+			}).ViaFieldIndex("volumeMounts", 0),
+		}, {
+			name: "has known volumeMounts, bad mountPath",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					MountPath: "not/absolute",
+					Name:      "the-name",
+					ReadOnly:  true,
+				}},
+			},
+			volumes: map[string]corev1.Volume{
+				"the-name": {
+					Name: "the-name",
+					VolumeSource: corev1.VolumeSource{
+						ConfigMap: &corev1.ConfigMapVolumeSource{
+							LocalObjectReference: corev1.LocalObjectReference{
+								Name: "test-cm",
+							},
+						},
 					},
 				},
 			},
-		},
-		want: &apis.FieldError{
-			Message: "timeoutSeconds is disallowed when periodSeconds is zero",
-			Paths:   []string{"readinessProbe.timeoutSeconds"},
-		},
-	}, {
-		name: "out of bounds probe values",
-		c: corev1.Container{
-			Image: "foo",
-			ReadinessProbe: &corev1.Probe{
-				PeriodSeconds:       -1,
-				TimeoutSeconds:      0,
-				SuccessThreshold:    0,
-				FailureThreshold:    0,
-				InitialDelaySeconds: -1,
-				Handler: corev1.Handler{
-					HTTPGet: &corev1.HTTPGetAction{},
+			want: apis.ErrInvalidValue("not/absolute", "volumeMounts[0].mountPath"),
+		}, {
+			name: "Empty dir has rw access",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					MountPath: "/mount/path",
+					Name:      "the-name",
+				}},
+			},
+			volumes: map[string]corev1.Volume{
+				"the-name": {
+					Name: "the-name",
+					VolumeSource: corev1.VolumeSource{
+						EmptyDir: &corev1.EmptyDirVolumeSource{
+							Medium: "Memory",
+						},
+					},
 				},
 			},
-		},
-		want: apis.ErrOutOfBoundsValue(-1, 0, math.MaxInt32, "readinessProbe.periodSeconds").Also(
-			apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.timeoutSeconds")).Also(
-			apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.successThreshold")).Also(
-			apis.ErrOutOfBoundsValue(0, 1, math.MaxInt32, "readinessProbe.failureThreshold")).Also(
-			apis.ErrOutOfBoundsValue(-1, 0, math.MaxInt32, "readinessProbe.initialDelaySeconds")),
-	}, {
-		name: "disallowed security context field",
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				Privileged: ptr.Bool(true),
+		}, {
+			name: "has known volumeMount twice",
+			c: corev1.Container{
+				Image: "foo",
+				VolumeMounts: []corev1.VolumeMount{{
+					MountPath: "/mount/path",
+					Name:      "the-name",
+					ReadOnly:  true,
+				}, {
+					MountPath: "/another/mount/path",
+					Name:      "the-name",
+					ReadOnly:  true,
+				}},
 			},
-		},
-		want: apis.ErrDisallowedFields("securityContext.privileged"),
-	}, {
-		name: "not allowed to add a security context capability",
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				Capabilities: &corev1.Capabilities{
-					Add: []corev1.Capability{"all"},
+			volumes: map[string]corev1.Volume{
+				"the-name": {
+					Name: "the-name",
+					VolumeSource: corev1.VolumeSource{
+						ConfigMap: &corev1.ConfigMapVolumeSource{
+							LocalObjectReference: corev1.LocalObjectReference{
+								Name: "test-cm",
+							},
+						},
+					},
 				},
 			},
-		},
-		want: apis.ErrDisallowedFields("securityContext.capabilities.add"),
-	}, {
-		name: "allowed to add a security context capability when gate is enabled",
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				Capabilities: &corev1.Capabilities{
-					Add: []corev1.Capability{"all"},
+		}, {
+			name: "not allowed to add a security context capability",
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					Capabilities: &corev1.Capabilities{
+						Add: []corev1.Capability{"all"},
+					},
 				},
 			},
-		},
-		cfgOpts: []configOption{withContainerSpecAddCapabilitiesEnabled()},
-		want:    nil,
-	}, {
-		name: "too large uid",
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				RunAsUser: ptr.Int64(math.MaxInt32 + 1),
+			want: apis.ErrDisallowedFields("securityContext.capabilities.add"),
+		}, {
+			name: "allowed to add a security context capability when gate is enabled",
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					Capabilities: &corev1.Capabilities{
+						Add: []corev1.Capability{"all"},
+					},
+				},
 			},
-		},
-		want: apis.ErrOutOfBoundsValue(int64(math.MaxInt32+1), 0, math.MaxInt32, "securityContext.runAsUser"),
-	}, {
-		name: "negative uid",
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				RunAsUser: ptr.Int64(-10),
+			cfgOpts: []configOption{withContainerSpecAddCapabilitiesEnabled()},
+			want:    nil,
+		}, {
+			name: "disallowed security context field",
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					Privileged: ptr.Bool(true),
+				},
 			},
-		},
-		want: apis.ErrOutOfBoundsValue(-10, 0, math.MaxInt32, "securityContext.runAsUser"),
-	}, {
-		name:    "too large gid - feature enabled",
-		cfgOpts: []configOption{withPodSpecSecurityContextEnabled()},
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				RunAsGroup: ptr.Int64(math.MaxInt32 + 1),
+			want: apis.ErrDisallowedFields("securityContext.privileged"),
+		}, {
+			name: "too large uid",
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					RunAsUser: ptr.Int64(math.MaxInt32 + 1),
+				},
 			},
-		},
-		want: apis.ErrOutOfBoundsValue(int64(math.MaxInt32+1), 0, math.MaxInt32, "securityContext.runAsGroup"),
-	}, {
-		name:    "negative gid - feature enabled",
-		cfgOpts: []configOption{withPodSpecSecurityContextEnabled()},
-		c: corev1.Container{
-			Image: "foo",
-			SecurityContext: &corev1.SecurityContext{
-				RunAsGroup: ptr.Int64(-10),
+			want: apis.ErrOutOfBoundsValue(int64(math.MaxInt32+1), 0, math.MaxInt32, "securityContext.runAsUser"),
+		}, {
+			name: "negative uid",
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					RunAsUser: ptr.Int64(-10),
+				},
 			},
-		},
-		want: apis.ErrOutOfBoundsValue(-10, 0, math.MaxInt32, "securityContext.runAsGroup"),
-	}, {
-		name: "envFrom - None of",
-		c: corev1.Container{
-			Image:   "foo",
-			EnvFrom: []corev1.EnvFromSource{{}},
-		},
-		want: apis.ErrMissingOneOf("envFrom.configMapRef", "envFrom.secretRef"),
-	}, {
-		name: "envFrom - Multiple",
-		c: corev1.Container{
-			Image: "foo",
-			EnvFrom: []corev1.EnvFromSource{{
-				ConfigMapRef: &corev1.ConfigMapEnvSource{
-					LocalObjectReference: corev1.LocalObjectReference{
-						Name: "ConfigMapName",
-					},
+			want: apis.ErrOutOfBoundsValue(-10, 0, math.MaxInt32, "securityContext.runAsUser"),
+		}, {
+			name:    "too large gid - feature enabled",
+			cfgOpts: []configOption{withPodSpecSecurityContextEnabled()},
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					RunAsGroup: ptr.Int64(math.MaxInt32 + 1),
 				},
-				SecretRef: &corev1.SecretEnvSource{
-					LocalObjectReference: corev1.LocalObjectReference{
-						Name: "SecretName",
-					},
+			},
+			want: apis.ErrOutOfBoundsValue(int64(math.MaxInt32+1), 0, math.MaxInt32, "securityContext.runAsGroup"),
+		}, {
+			name:    "negative gid - feature enabled",
+			cfgOpts: []configOption{withPodSpecSecurityContextEnabled()},
+			c: corev1.Container{
+				Image: "foo",
+				SecurityContext: &corev1.SecurityContext{
+					RunAsGroup: ptr.Int64(-10),
 				},
-			}},
-		},
-		want: apis.ErrMultipleOneOf("envFrom.configMapRef", "envFrom.secretRef"),
-	}, {
-		name: "envFrom - Secret",
-		c: corev1.Container{
-			Image: "foo",
-			EnvFrom: []corev1.EnvFromSource{{
-				SecretRef: &corev1.SecretEnvSource{
-					LocalObjectReference: corev1.LocalObjectReference{
-						Name: "SecretName",
+			},
+			want: apis.ErrOutOfBoundsValue(-10, 0, math.MaxInt32, "securityContext.runAsGroup"),
+		}, {
+			name: "envFrom - None of",
+			c: corev1.Container{
+				Image:   "foo",
+				EnvFrom: []corev1.EnvFromSource{{}},
+			},
+			want: apis.ErrMissingOneOf("envFrom.configMapRef", "envFrom.secretRef"),
+		}, {
+			name: "envFrom - Multiple",
+			c: corev1.Container{
+				Image: "foo",
+				EnvFrom: []corev1.EnvFromSource{{
+					ConfigMapRef: &corev1.ConfigMapEnvSource{
+						LocalObjectReference: corev1.LocalObjectReference{
+							Name: "ConfigMapName",
+						},
 					},
-				},
-			}},
-		},
-		want: nil,
-	}, {
-		name: "envFrom - ConfigMap",
-		c: corev1.Container{
-			Image: "foo",
-			EnvFrom: []corev1.EnvFromSource{{
-				ConfigMapRef: &corev1.ConfigMapEnvSource{
-					LocalObjectReference: corev1.LocalObjectReference{
-						Name: "ConfigMapName",
+					SecretRef: &corev1.SecretEnvSource{
+						LocalObjectReference: corev1.LocalObjectReference{
+							Name: "SecretName",
+						},
 					},
-				},
-			}},
-		},
-		want: nil,
-	}, {
-		name: "termination message policy",
-		c: corev1.Container{
-			Image:                    "foo",
-			TerminationMessagePolicy: corev1.TerminationMessagePolicy("Not a Policy"),
-		},
-		want: apis.ErrInvalidValue(corev1.TerminationMessagePolicy("Not a Policy"), "terminationMessagePolicy"),
-	}, {
-		name: "empty env var name",
-		c: corev1.Container{
-			Image: "foo",
-			Env: []corev1.EnvVar{{
-				Value: "Foo",
-			}},
-		},
-		want: apis.ErrMissingField("env[0].name"),
-	}, {
-		name: "reserved env var name for serving container",
-		c: corev1.Container{
-			Image: "foo",
-			Env: []corev1.EnvVar{{
-				Name:  "PORT",
-				Value: "Foo",
-			}},
-			Ports: []corev1.ContainerPort{{
-				ContainerPort: 8888,
-			}},
-		},
-		want: &apis.FieldError{
-			Message: `"PORT" is a reserved environment variable`,
-			Paths:   []string{"env[0].name"},
-		},
-	}, {
-		name: "disallowed envvarsource",
-		c: corev1.Container{
-			Image: "foo",
-			Env: []corev1.EnvVar{{
-				Name: "Foo",
-				ValueFrom: &corev1.EnvVarSource{
-					FieldRef: &corev1.ObjectFieldSelector{
-						FieldPath: "/v1",
+				}},
+			},
+			want: apis.ErrMultipleOneOf("envFrom.configMapRef", "envFrom.secretRef"),
+		}, {
+			name: "envFrom - Secret",
+			c: corev1.Container{
+				Image: "foo",
+				EnvFrom: []corev1.EnvFromSource{{
+					SecretRef: &corev1.SecretEnvSource{
+						LocalObjectReference: corev1.LocalObjectReference{
+							Name: "SecretName",
+						},
 					},
-				},
-			}},
-		},
-		want: apis.ErrDisallowedFields("env[0].valueFrom.fieldRef"),
-	}, {
-		name: "invalid liveness tcp probe (has port)",
-		c: corev1.Container{
-			Image: "foo",
-			LivenessProbe: &corev1.Probe{
-				Handler: corev1.Handler{
-					TCPSocket: &corev1.TCPSocketAction{
-						Port: intstr.FromString("http"),
+				}},
+			},
+			want: nil,
+		}, {
+			name: "envFrom - ConfigMap",
+			c: corev1.Container{
+				Image: "foo",
+				EnvFrom: []corev1.EnvFromSource{{
+					ConfigMapRef: &corev1.ConfigMapEnvSource{
+						LocalObjectReference: corev1.LocalObjectReference{
+							Name: "ConfigMapName",
+						},
 					},
-				},
+				}},
 			},
-		},
-		want: apis.ErrDisallowedFields("livenessProbe.tcpSocket.port"),
-	}, {
-		name: "disallowed container fields",
-		c: corev1.Container{
-			Image:     "foo",
-			Name:      "fail",
-			Stdin:     true,
-			StdinOnce: true,
-			TTY:       true,
-			Lifecycle: &corev1.Lifecycle{},
-			VolumeDevices: []corev1.VolumeDevice{{
-				Name:       "disallowed",
-				DevicePath: "/",
-			}},
-		},
-		want: apis.ErrDisallowedFields("lifecycle").Also(
-			apis.ErrDisallowedFields("stdin")).Also(
-			apis.ErrDisallowedFields("stdinOnce")).Also(
-			apis.ErrDisallowedFields("tty")).Also(
-			apis.ErrDisallowedFields("volumeDevices")),
-	}, {
-		name: "has numerous problems",
-		c: corev1.Container{
-			Lifecycle: &corev1.Lifecycle{},
-		},
-		want: apis.ErrDisallowedFields("lifecycle").Also(
-			apis.ErrMissingField("image")),
-	}}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			ctx := context.Background()
-			if test.cfgOpts != nil {
-				cfg := config.FromContextOrDefaults(ctx)
-				for _, opt := range test.cfgOpts {
-					cfg = opt(cfg)
-				}
-				ctx = config.ToContext(ctx, cfg)
-			}
-
-			got := ValidateContainer(ctx, test.c, test.volumes)
-			if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" {
-				t.Errorf("ValidateContainer (-want, +got): \n%s", diff)
-			}
-		})
-	}
+			want: nil,
+		}, {
+			name: "termination message policy",
+			c: corev1.Container{
+				Image:                    "foo",
+				TerminationMessagePolicy: "Not a Policy",
+			},
+			want: apis.ErrInvalidValue(corev1.TerminationMessagePolicy("Not a Policy"), "terminationMessagePolicy"),
+		}, {
+			name: "empty env var name",
+			c: corev1.Container{
+				Image: "foo",
+				Env: []corev1.EnvVar{{
+					Value: "Foo",
+				}},
+			},
+			want: apis.ErrMissingField("env[0].name"),
+		}, {
+			name: "disallowed envvarsource",
+			c: corev1.Container{
+				Image: "foo",
+				Env: []corev1.EnvVar{{
+					Name: "Foo",
+					ValueFrom: &corev1.EnvVarSource{
+						FieldRef: &corev1.ObjectFieldSelector{
+							FieldPath: "/v1",
+						},
+					},
+				}},
+			},
+			want: apis.ErrDisallowedFields("env[0].valueFrom.fieldRef"),
+		}}
 }
 
 func TestVolumeValidation(t *testing.T) {
diff --git a/pkg/reconciler/route/resources/service_test.go b/pkg/reconciler/route/resources/service_test.go
index 6564f615f..8c439babd 100644
--- a/pkg/reconciler/route/resources/service_test.go
+++ b/pkg/reconciler/route/resources/service_test.go
@@ -429,6 +429,7 @@ func testConfig() *config.Config {
 			PodSpecNodeSelector:      apiConfig.Disabled,
 			PodSpecTolerations:       apiConfig.Disabled,
 			PodSpecVolumesEmptyDir:   apiConfig.Disabled,
+			PodSpecInitContainers:    apiConfig.Disabled,
 			PodSpecPriorityClassName: apiConfig.Disabled,
 			PodSpecSchedulerName:     apiConfig.Disabled,
 			TagHeaderBasedRouting:    apiConfig.Disabled,
diff --git a/test/e2e-auto-tls-tests.sh b/test/e2e-auto-tls-tests.sh
index 4e1ad3ba9..f85a84ba6 100755
--- a/test/e2e-auto-tls-tests.sh
+++ b/test/e2e-auto-tls-tests.sh
@@ -170,7 +170,8 @@ function delete_dns_record() {
 # Skip installing istio as an add-on
 # Temporarily increasing the cluster size for serving tests to rule out
 # resource/eviction as causes of flakiness.
-initialize --skip-istio-addon --min-nodes=4 --max-nodes=4 --enable-ha "$@"
+# Pin to 1.20 since scale test is super flakey on 1.21
+initialize "$@" --skip-istio-addon --min-nodes=4 --max-nodes=4 --enable-ha --cluster-version=1.20
 
 # Run the tests
 header "Running tests"
diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh
index 4f839dd6a..f157551ef 100755
--- a/test/e2e-tests.sh
+++ b/test/e2e-tests.sh
@@ -32,7 +32,8 @@ source $(dirname $0)/e2e-common.sh
 # Skip installing istio as an add-on.
 # Temporarily increasing the cluster size for serving tests to rule out
 # resource/eviction as causes of flakiness.
-initialize --skip-istio-addon --min-nodes=4 --max-nodes=4 --enable-ha "$@"
+# Pin to 1.20 since scale test is super flakey on 1.21
+initialize --skip-istio-addon --min-nodes=4 --max-nodes=4 --enable-ha --cluster-version=1.20 "$@"
 
 # Run the tests
 header "Running tests"
diff --git a/test/e2e-upgrade-tests.sh b/test/e2e-upgrade-tests.sh
index 01b0d37d7..06f366d9a 100755
--- a/test/e2e-upgrade-tests.sh
+++ b/test/e2e-upgrade-tests.sh
@@ -36,7 +36,9 @@ source "$(dirname "${BASH_SOURCE[0]}")/e2e-common.sh"
 # Skip installing istio as an add-on.
 # Temporarily increasing the cluster size for serving tests to rule out
 # resource/eviction as causes of flakiness.
-initialize --skip-istio-addon  --min-nodes=4 --max-nodes=4 --install-latest-release "$@"
+# Pin to 1.20 since scale test is super flakey on 1.21
+initialize "$@" --skip-istio-addon  --min-nodes=4 --max-nodes=4 --cluster-version=1.20 \
+  --install-latest-release
 
 # TODO(#2656): Reduce the timeout after we get this test to consistently passing.
 TIMEOUT=30m
diff --git a/third_party/contour-latest/contour.yaml b/third_party/contour-latest/contour.yaml
index 708ff9b48..08e984836 100644
--- a/third_party/contour-latest/contour.yaml
+++ b/third_party/contour-latest/contour.yaml
@@ -1904,7 +1904,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           command:
             - contour
@@ -2155,7 +2155,7 @@ spec:
             - --config-path=/config/contour.yaml
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -2244,7 +2244,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -2326,7 +2326,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
@@ -2605,7 +2605,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           command:
             - contour
@@ -2717,7 +2717,7 @@ spec:
             - --config-path=/config/contour.yaml
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -2806,7 +2806,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -2888,7 +2888,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7e87a6123dfb13950976998ae7394739404b80c36dd91646049f7d41663f2993
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:543f38ca4e67f93e71cfbd6f9e8f56fe84346f6d75983501feae782819f7cd2c
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
diff --git a/third_party/contour-latest/net-contour.yaml b/third_party/contour-latest/net-contour.yaml
index cb1d5437a..a7ef873b6 100644
--- a/third_party/contour-latest/net-contour.yaml
+++ b/third_party/contour-latest/net-contour.yaml
@@ -33,7 +33,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: contour
-    serving.knative.dev/release: "v20210923-d482acee"
+    serving.knative.dev/release: "v20211001-2db64e2d"
 data:
   _example: |
     ################################
@@ -103,7 +103,7 @@ spec:
         - name: controller
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:0061f8a08ecd8eb01349a068b75c3afeddbc118f6cd7e2c66a5f513f829476de
+          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:1433a1f4b52d6652ed5d8b88891e7fdebc84382bdfbf8ef9db869dae7b0c9368
           resources:
             requests:
               cpu: 40m