Repository: GoogleContainerTools/skaffold
Pull request #7703 (2022-07-29 19:57:34)

fix: retagging an image index
<!-- Thank you for your contribution! -->

<!-- Include if applicable: -->
Fixes: #7681, #7634 <!-- tracking issues that this PR will close -->

codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) Report
> Merging [#7703](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) (5c2955c) into [main](https://codecov.io/gh/GoogleContainerTools/skaffold/commit/290280e8c6c19231e9ed5b5c027f2c01d22f75be?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) (290280e) will **decrease** coverage by `3.96%`.
> The diff coverage is `51.48%`.

```diff
@@            Coverage Diff             @@
##             main    #7703      +/-   ##
==========================================
- Coverage   70.48%   66.52%   -3.97%     
==========================================
  Files         515      589      +74     
  Lines       23150    28331    +5181     
==========================================
+ Hits        16317    18846    +2529     
- Misses       5776     8099    +2323     
- Partials     1057     1386     +329     
```


| [Impacted Files](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) | Coverage Δ | |
|---|---|---|
| [cmd/skaffold/app/cmd/credits/export.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvY3JlZGl0cy9leHBvcnQuZ28=) | `0.00% <0.00%> (ø)` | |
| [cmd/skaffold/app/cmd/deploy.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvZGVwbG95Lmdv) | `40.90% <0.00%> (-12.94%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/test.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvdGVzdC5nbw==) | `44.44% <0.00%> (ø)` | |
| [cmd/skaffold/skaffold.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL3NrYWZmb2xkLmdv) | `0.00% <0.00%> (ø)` | |
| [cmd/skaffold/app/cmd/inspect\_tests.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvaW5zcGVjdF90ZXN0cy5nbw==) | `62.50% <14.28%> (-1.14%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/render.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvcmVuZGVyLmdv) | `35.48% <18.18%> (-5.90%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/fix.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvZml4Lmdv) | `44.87% <25.00%> (-31.60%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/lsp.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvbHNwLmdv) | `28.12% <28.12%> (ø)` | |
| [cmd/skaffold/app/cmd/run.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvcnVuLmdv) | `64.28% <33.33%> (-9.63%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/verify.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvdmVyaWZ5Lmdv) | `41.17% <41.17%> (ø)` | |
| ... and [335 more](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/7703/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) | |

:mega: Codecov can now indicate which changes are the most critical in Pull Requests. [Learn more](https://about.codecov.io/product/feature/runtime-insights/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools)


Patch:
diff --git a/cmd/skaffold/app/cmd/dev.go b/cmd/skaffold/app/cmd/dev.go
index 8c00af02a..638bff8f1 100644
--- a/cmd/skaffold/app/cmd/dev.go
+++ b/cmd/skaffold/app/cmd/dev.go
@@ -72,7 +72,7 @@ func runDev(ctx context.Context, out io.Writer) error {
 				}
 				err := r.Dev(ctx, out, artifacts)
 
-				if r.HasDeployed() {
+				if r.DeployManifests().String() != "" {
 					cleanup = func() {
 						manifestsByConfig, err := r.Render(ctx, io.Discard, []graph.Artifact{}, false)
 						if err != nil {
diff --git a/cmd/skaffold/app/cmd/flags.go b/cmd/skaffold/app/cmd/flags.go
index 4a73b9960..ac6019232 100644
--- a/cmd/skaffold/app/cmd/flags.go
+++ b/cmd/skaffold/app/cmd/flags.go
@@ -652,6 +652,24 @@ var flagRegistry = []Flag{
 		FlagAddMethod: "BoolVar",
 		DefinedOn:     []string{"dev", "render", "run", "debug", "deploy"},
 	},
+	{
+		Name:          "cloud-run-project",
+		Shorthand:     "",
+		Usage:         "The GCP Project ID or Project Number to deploy for Cloud Run",
+		Value:         &opts.CloudRunProject,
+		DefValue:      "",
+		FlagAddMethod: "StringVar",
+		DefinedOn:     []string{"dev", "run", "debug", "deploy", "apply", "delete"},
+	},
+	{
+		Name:          "cloud-run-location",
+		Shorthand:     "",
+		Usage:         "The GCP Region to deploy Cloud Run services to",
+		Value:         &opts.CloudRunLocation,
+		DefValue:      "",
+		FlagAddMethod: "StringVar",
+		DefinedOn:     []string{"dev", "run", "debug", "deploy", "apply", "delete"},
+	},
 }
 
 func methodNameByType(v reflect.Value) string {
diff --git a/cmd/skaffold/app/cmd/schema/list.go b/cmd/skaffold/app/cmd/schema/list.go
index 183d2bc3c..dffba68eb 100644
--- a/cmd/skaffold/app/cmd/schema/list.go
+++ b/cmd/skaffold/app/cmd/schema/list.go
@@ -27,7 +27,6 @@ import (
 
 var OutputType string
 
-// TODO(yuwenma): We currently hide the v3alpha* schemas from users. We should display it once the render v2 is available.
 // List prints to `out` all supported schema versions.
 func List(_ context.Context, out io.Writer) error {
 	return list(out, OutputType)
@@ -69,5 +68,9 @@ func versions() []string {
 		versions = append(versions, version.APIVersion)
 	}
 
+	for _, version := range schema.SchemaVersionsV2 {
+		versions = append(versions, version.APIVersion)
+	}
+
 	return versions
 }
diff --git a/docs-v2/content/en/docs/pipeline-stages/deployers/_index.md b/docs-v2/content/en/docs/pipeline-stages/deployers/_index.md
index 0e1dfbd4c..4ac946ac6 100644
--- a/docs-v2/content/en/docs/pipeline-stages/deployers/_index.md
+++ b/docs-v2/content/en/docs/pipeline-stages/deployers/_index.md
@@ -7,18 +7,13 @@ aliases: [/docs/how-tos/deployers]
 no_list: true
 ---
 
-When Skaffold deploys your application to Kubernetes, it (usually) goes through these steps:
+When Skaffold deploys your application to Kubernetes, it goes through these steps:
 
 In the default case (no manifest provided using the kubectl or kpt deployer ), skaffold deploy will do the following:
 * the Skaffold renderer _renders_ the final Kubernetes manifests: Skaffold replaces untagged image names in the Kubernetes manifests with the final tagged image names.
-It also might go through the extra intermediate step of expanding templates (for helm) or calculating overlays (for kustomize).
+It also might go through the extra intermediate step of expanding templates (for helm) or calculating overlays (for kustomize).  Additionally some deployers (docker) do not render manifests as such don't use this phase.
 * the Skaffold deployer _deploys_ the final Kubernetes manifests to the cluster (or to local docker for the docker deployer)
 * the Skaffold deployer performs [status checks]({{< relref "/docs/pipeline-stages/status-check" >}}) and waits for the deployed resources to stabilize.
-
-In the case that a manifest file is supplied via the --TODO flag or the deployer does not accept manifests (eg: helm and docker) skaffold deploy will only do the following steps:
-* the Skaffold deployer _deploys_ the supplied Kubernetes manifests to the cluster (or deploys the specified container to docker for the docker deployer)
-* the Skaffold deployer performs [status checks]({{< relref "/docs/pipeline-stages/status-check" >}}) and waits for the deployed resources to stabilize
-
 ### Supported deployers
 
 Skaffold supports the following tools for deploying applications:
diff --git a/docs/content/en/docs/references/cli/_index.md b/docs/content/en/docs/references/cli/_index.md
index 44c60df29..0c843957d 100644
--- a/docs/content/en/docs/references/cli/_index.md
+++ b/docs/content/en/docs/references/cli/_index.md
@@ -122,6 +122,8 @@ Examples:
 
 Options:
       --assume-yes=false: If true, skaffold will skip yes/no confirmation from the user and default to yes
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -f, --filename='skaffold.yaml': Path or URL to the Skaffold config file
       --force=false: Recreate Kubernetes resources if necessary for deployment, warning: might cause downtime!
@@ -147,6 +149,8 @@ Use "skaffold options" for a list of global command-line options (applies to all
 Env vars:
 
 * `SKAFFOLD_ASSUME_YES` (same as `--assume-yes`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_FILENAME` (same as `--filename`)
 * `SKAFFOLD_FORCE` (same as `--force`)
@@ -405,6 +409,8 @@ Options:
       --cache-artifacts=true: Set to false to disable default caching of artifacts
       --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache)
       --cleanup=true: Delete deployments after dev or debug mode is interrupted
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
@@ -464,6 +470,8 @@ Env vars:
 * `SKAFFOLD_CACHE_ARTIFACTS` (same as `--cache-artifacts`)
 * `SKAFFOLD_CACHE_FILE` (same as `--cache-file`)
 * `SKAFFOLD_CLEANUP` (same as `--cleanup`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_DEFAULT_REPO` (same as `--default-repo`)
 * `SKAFFOLD_DETECT_MINIKUBE` (same as `--detect-minikube`)
@@ -518,6 +526,8 @@ Examples:
 
 Options:
       --assume-yes=false: If true, skaffold will skip yes/no confirmation from the user and default to yes
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
@@ -543,6 +553,8 @@ Use "skaffold options" for a list of global command-line options (applies to all
 Env vars:
 
 * `SKAFFOLD_ASSUME_YES` (same as `--assume-yes`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_DEFAULT_REPO` (same as `--default-repo`)
 * `SKAFFOLD_DETECT_MINIKUBE` (same as `--detect-minikube`)
@@ -579,6 +591,8 @@ Options:
       --assume-yes=false: If true, skaffold will skip yes/no confirmation from the user and default to yes
   -a, --build-artifacts=: File containing build result from a previous 'skaffold build --file-output'
       --build-concurrency=-1: Number of concurrently running builds. Set to 0 to run all builds in parallel. Doesn't violate build order among dependencies.
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
@@ -626,6 +640,8 @@ Env vars:
 * `SKAFFOLD_ASSUME_YES` (same as `--assume-yes`)
 * `SKAFFOLD_BUILD_ARTIFACTS` (same as `--build-artifacts`)
 * `SKAFFOLD_BUILD_CONCURRENCY` (same as `--build-concurrency`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_DEFAULT_REPO` (same as `--default-repo`)
 * `SKAFFOLD_DETECT_MINIKUBE` (same as `--detect-minikube`)
@@ -678,6 +694,8 @@ Options:
       --cache-artifacts=true: Set to false to disable default caching of artifacts
       --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache)
       --cleanup=true: Delete deployments after dev or debug mode is interrupted
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
@@ -737,6 +755,8 @@ Env vars:
 * `SKAFFOLD_CACHE_ARTIFACTS` (same as `--cache-artifacts`)
 * `SKAFFOLD_CACHE_FILE` (same as `--cache-file`)
 * `SKAFFOLD_CLEANUP` (same as `--cleanup`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_DEFAULT_REPO` (same as `--default-repo`)
 * `SKAFFOLD_DETECT_MINIKUBE` (same as `--detect-minikube`)
@@ -1023,6 +1043,8 @@ Options:
       --cache-artifacts=true: Set to false to disable default caching of artifacts
       --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache)
       --cleanup=true: Delete deployments after dev or debug mode is interrupted
+      --cloud-run-location='': The GCP Region to deploy Cloud Run services to
+      --cloud-run-project='': The GCP Project ID or Project Number to deploy for Cloud Run
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
@@ -1077,6 +1099,8 @@ Env vars:
 * `SKAFFOLD_CACHE_ARTIFACTS` (same as `--cache-artifacts`)
 * `SKAFFOLD_CACHE_FILE` (same as `--cache-file`)
 * `SKAFFOLD_CLEANUP` (same as `--cleanup`)
+* `SKAFFOLD_CLOUD_RUN_LOCATION` (same as `--cloud-run-location`)
+* `SKAFFOLD_CLOUD_RUN_PROJECT` (same as `--cloud-run-project`)
 * `SKAFFOLD_CONFIG` (same as `--config`)
 * `SKAFFOLD_DEFAULT_REPO` (same as `--default-repo`)
 * `SKAFFOLD_DETECT_MINIKUBE` (same as `--detect-minikube`)
diff --git a/docs/content/en/samples/deployers/kubectl.yaml b/docs/content/en/samples/deployers/kubectl.yaml
index 1fd919953..221b91b08 100644
--- a/docs/content/en/samples/deployers/kubectl.yaml
+++ b/docs/content/en/samples/deployers/kubectl.yaml
@@ -1,4 +1,3 @@
-deploy:
-  kubectl:
-    manifests:
-    - k8s-*
+manifests:
+  rawYaml:    
+  - k8s-*
diff --git a/docs/content/en/samples/deployers/status-check.yaml b/docs/content/en/samples/deployers/status-check.yaml
index 010016baa..c1d010872 100644
--- a/docs/content/en/samples/deployers/status-check.yaml
+++ b/docs/content/en/samples/deployers/status-check.yaml
@@ -1,5 +1,2 @@
 deploy:
   statusCheckDeadlineSeconds: 300
-  kubectl:
-    manifests:
-    - k8s-*
\ No newline at end of file
diff --git a/docs/content/en/samples/pipeline-stages/init-example.yaml b/docs/content/en/samples/pipeline-stages/init-example.yaml
index ed9d4099d..5d83b0549 100644
--- a/docs/content/en/samples/pipeline-stages/init-example.yaml
+++ b/docs/content/en/samples/pipeline-stages/init-example.yaml
@@ -6,8 +6,7 @@ build:
     context: leeroy-app
   - image: gcr.io/k8s-skaffold/leeroy-web
     context: path/to/context
-deploy:
-  kubectl:
-    manifests:
+manifests:
+  rawYaml:
     - leeroy-app/kubernetes/deployment.yaml
-    - leeroy-web/kubernetes/deployment.yaml
\ No newline at end of file
+    - leeroy-web/kubernetes/deployment.yaml
diff --git a/docs/content/en/samples/profiles/activations.yaml b/docs/content/en/samples/profiles/activations.yaml
index b1f8d1fd0..b9d67abad 100644
--- a/docs/content/en/samples/profiles/activations.yaml
+++ b/docs/content/en/samples/profiles/activations.yaml
@@ -1,10 +1,9 @@
 build:
   artifacts:
   - image: gcr.io/k8s-skaffold/skaffold-example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-pod
+manifests:
+  rawYaml:
+  - k8s-pod
 profiles:
 - name: profile1
   activation:
diff --git a/docs/content/en/samples/profiles/patches.yaml b/docs/content/en/samples/profiles/patches.yaml
index 07061d161..7410d48a2 100644
--- a/docs/content/en/samples/profiles/patches.yaml
+++ b/docs/content/en/samples/profiles/patches.yaml
@@ -5,10 +5,9 @@ build:
         dockerfile: Dockerfile
     - image: gcr.io/k8s-skaffold/skaffold2
     - image: gcr.io/k8s-skaffold/skaffold3
-deploy:
-  kubectl:
-    manifests:
-      - k8s-pod
+manifests:
+  rawYaml:
+  - k8s-pod
 profiles:
   - name: dev
     patches:
diff --git a/docs/content/en/samples/profiles/profiles.yaml b/docs/content/en/samples/profiles/profiles.yaml
index 9017e0ee8..5c8e49a8d 100644
--- a/docs/content/en/samples/profiles/profiles.yaml
+++ b/docs/content/en/samples/profiles/profiles.yaml
@@ -1,10 +1,9 @@
 build:
   artifacts:
   - image: gcr.io/k8s-skaffold/skaffold-example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-pod
+manifests:
+  rawYaml:
+  - k8s-pod
 profiles:
 - name: gcb
   build:
diff --git a/examples/templated-fields/charts/values.yaml b/examples/templated-fields/charts/values.yaml
index ba42ad6e1..3e6d9d77f 100644
--- a/examples/templated-fields/charts/values.yaml
+++ b/examples/templated-fields/charts/values.yaml
@@ -2,3 +2,4 @@
 # This is a YAML-formatted file.
 # Declare variables to be passed into your templates.
 replicaCount: 2
+image: skaffold-templated
\ No newline at end of file
diff --git a/examples/templated-fields/skaffold.yaml b/examples/templated-fields/skaffold.yaml
index 8dfa78de6..e1e1c58d6 100644
--- a/examples/templated-fields/skaffold.yaml
+++ b/examples/templated-fields/skaffold.yaml
@@ -16,8 +16,6 @@ deploy:
     releases:
     - name: skaffold-templated
       chartPath: charts
-      artifactOverrides:
-        image: skaffold-templated
       setValueTemplates:
         imageRepo: "{{.IMAGE_REPO}}"
         imageTag: "{{.IMAGE_TAG}}"
diff --git a/integration/examples/cross-platform-builds/skaffold.yaml b/integration/examples/cross-platform-builds/skaffold.yaml
index b9f503eb6..2b8de1eec 100644
--- a/integration/examples/cross-platform-builds/skaffold.yaml
+++ b/integration/examples/cross-platform-builds/skaffold.yaml
@@ -1,10 +1,17 @@
 apiVersion: skaffold/v3alpha1
 kind: Config
 build:
-  platforms: ["linux/amd64"]
   artifacts:
   - image: skaffold-example
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+    context: .
+    docker:
+      dockerfile: Dockerfile
+  tagPolicy:
+    gitCommit: {}
+  platforms:
+  - linux/amd64
+  local:
+    concurrency: 1
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/examples/cross-platform-builds/skaffold.yaml.v2 b/integration/examples/cross-platform-builds/skaffold.yaml.v2
new file mode 100644
index 000000000..a2a0f34f7
--- /dev/null
+++ b/integration/examples/cross-platform-builds/skaffold.yaml.v2
@@ -0,0 +1,10 @@
+apiVersion: skaffold/v2beta29
+kind: Config
+build:
+  platforms: ["linux/amd64"]
+  artifacts:
+  - image: skaffold-example
+deploy:
+  kubectl:
+    manifests:
+      - k8s-*
diff --git a/integration/examples/gcb-kaniko/skaffold.yaml b/integration/examples/gcb-kaniko/skaffold.yaml
index c2acc22ae..e531beac0 100644
--- a/integration/examples/gcb-kaniko/skaffold.yaml
+++ b/integration/examples/gcb-kaniko/skaffold.yaml
@@ -7,7 +7,6 @@ build:
   - image: skaffold-example
     kaniko:
       cache: {}
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/examples/generate-pipeline/skaffold.yaml b/integration/examples/generate-pipeline/skaffold.yaml
index 1670ec3e3..9c27396e3 100644
--- a/integration/examples/generate-pipeline/skaffold.yaml
+++ b/integration/examples/generate-pipeline/skaffold.yaml
@@ -3,7 +3,6 @@ kind: Config
 build:
   artifacts:
   - image: pipeline-example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/examples/getting-started-kustomize/skaffold.yaml b/integration/examples/getting-started-kustomize/skaffold.yaml
index dd02586b7..03c55d803 100644
--- a/integration/examples/getting-started-kustomize/skaffold.yaml
+++ b/integration/examples/getting-started-kustomize/skaffold.yaml
@@ -8,18 +8,18 @@ build:
     context: app
     docker:
       dockerfile: Dockerfile
-deploy:
+manifests:
   kustomize:
     paths:
     - overlays/dev
 profiles:
 - name: prod
-  deploy:
+  manifests:
     kustomize:
       paths:
       - overlays/prod
 - name: staging
-  deploy:
+  manifests:
     kustomize:
       paths:
       - overlays/staging
diff --git a/integration/examples/google-cloud-build/skaffold.yaml b/integration/examples/google-cloud-build/skaffold.yaml
index 818136d7c..461badc49 100644
--- a/integration/examples/google-cloud-build/skaffold.yaml
+++ b/integration/examples/google-cloud-build/skaffold.yaml
@@ -5,7 +5,6 @@ build:
     projectId: k8s-skaffold
   artifacts:
   - image: skaffold-example
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/examples/kaniko/skaffold.yaml b/integration/examples/kaniko/skaffold.yaml
index 5f0dcc102..777bb5b83 100644
--- a/integration/examples/kaniko/skaffold.yaml
+++ b/integration/examples/kaniko/skaffold.yaml
@@ -9,7 +9,6 @@ build:
     pullSecretName: e2esecret-with-path
     pullSecretPath:     kaniko-secret.json
     namespace: default
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/examples/lifecycle-hooks/skaffold.yaml b/integration/examples/lifecycle-hooks/skaffold.yaml
index a604e04bc..07bdf6638 100644
--- a/integration/examples/lifecycle-hooks/skaffold.yaml
+++ b/integration/examples/lifecycle-hooks/skaffold.yaml
@@ -31,10 +31,11 @@ build:
         after:
           - container:
               command: ["sh", "-c", "set -x; kill -HUP 1"]
+manifests:
+  rawYaml:
+  - deployment.yaml
 deploy:
   kubectl:
-    manifests:
-      - deployment.yaml
     hooks:
       before:
         - host:
diff --git a/integration/examples/microservices/README.md b/integration/examples/microservices/README.md
index 5f192fba1..37ee0ada5 100644
--- a/integration/examples/microservices/README.md
+++ b/integration/examples/microservices/README.md
@@ -87,10 +87,9 @@ COPY --from=builder /app .
 In the deploy stanza, we use the glob matching pattern to deploy all YAML and JSON files in the respective Kubernetes manifest directories.
 
 ```yaml
-deploy:
-  kubectl:
-    manifests:
-    - ./leeroy-web/kubernetes/*
-    - ./leeroy-app/kubernetes/*
+manifests:
+  rawYaml:
+  - ./leeroy-web/kubernetes/*
+  - ./leeroy-app/kubernetes/*
 ```
 
diff --git a/integration/examples/multiple-renderers/backend/Chart.yaml b/integration/examples/multiple-renderers/backend/Chart.yaml
new file mode 100644
index 000000000..d75d2453e
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+description: back end for guestbook
+name: backend
+version: 0.1.0
diff --git a/integration/examples/multiple-renderers/backend/src/Dockerfile b/integration/examples/multiple-renderers/backend/src/Dockerfile
new file mode 100644
index 000000000..a81769c57
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/Dockerfile
@@ -0,0 +1,29 @@
+# Use base golang image from Docker Hub
+FROM golang:1.17 as build
+
+WORKDIR /app
+
+# Copy the go.mod and go.sum, download the dependencies
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copy rest of the application source code
+COPY . ./
+
+# Compile the application to /app/backend.
+# Skaffold passes in debug-oriented compiler flags
+ARG SKAFFOLD_GO_GCFLAGS
+RUN echo "Go gcflags: ${SKAFFOLD_GO_GCFLAGS}"
+RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -mod=readonly -v -o /app/backend .
+
+# Now create separate deployment image
+FROM gcr.io/distroless/base
+
+# Definition of this variable is used by 'skaffold debug' to identify a golang binary.
+# Default behavior - a failure prints a stack trace for the current goroutine.
+# See https://golang.org/pkg/runtime/
+ENV GOTRACEBACK=single
+
+WORKDIR /app
+COPY --from=build /app/backend /app/backend
+ENTRYPOINT ["/app/backend"]
diff --git a/integration/examples/multiple-renderers/backend/src/database.go b/integration/examples/multiple-renderers/backend/src/database.go
new file mode 100644
index 000000000..663e963e7
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/database.go
@@ -0,0 +1,10 @@
+package main
+
+import (
+	"context"
+)
+
+type database interface {
+	entries(context.Context) ([]guestbookEntry, error)
+	addEntry(context.Context, guestbookEntry) error
+}
diff --git a/integration/examples/multiple-renderers/backend/src/go.mod b/integration/examples/multiple-renderers/backend/src/go.mod
new file mode 100644
index 000000000..d29581e26
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/go.mod
@@ -0,0 +1,9 @@
+module backend
+
+go 1.12
+
+require (
+	github.com/DataDog/zstd v1.4.4 // indirect
+	github.com/xdg/stringprep v1.0.0 // indirect
+	go.mongodb.org/mongo-driver v1.8.4
+)
diff --git a/integration/examples/multiple-renderers/backend/src/go.sum b/integration/examples/multiple-renderers/backend/src/go.sum
new file mode 100644
index 000000000..d818d7179
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/go.sum
@@ -0,0 +1,203 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/DataDog/zstd v1.4.4 h1:+IawcoXhCBylN7ccwdwf8LOH2jKq7NavGpEPanrlTzE=
+github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/aws/aws-sdk-go v1.29.15 h1:0ms/213murpsujhsnxnNKNeVouW60aJqSd992Ks3mxs=
+github.com/aws/aws-sdk-go v1.29.15/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
+github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
+github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
+github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
+github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
+github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g=
+github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
+github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
+github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
+github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c=
+go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
+go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.1.3 h1:++7u8r9adKhGR+I79NfEtYrk2ktjenErXM99PSufIoI=
+go.mongodb.org/mongo-driver v1.1.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.2.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.2.1 h1:ANAlYXXM5XmOdW/Nc38jOr+wS5nlk7YihT24U1imiWM=
+go.mongodb.org/mongo-driver v1.2.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.3.0 h1:ew6uUIeJOo+qdUUv7LxFCUhtWmVv7ZV/Xuy4FAUsw2E=
+go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
+go.mongodb.org/mongo-driver v1.3.1 h1:op56IfTQiaY2679w922KVWa3qcHdml2K/Io8ayAOUEQ=
+go.mongodb.org/mongo-driver v1.3.1/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
+go.mongodb.org/mongo-driver v1.3.2 h1:IYppNjEV/C+/3VPbhHVxQ4t04eVW0cLp0/pNdW++6Ug=
+go.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
+go.mongodb.org/mongo-driver v1.3.3 h1:9kX7WY6sU/5qBuhm5mdnNWdqaDAQKB2qSZOd5wMEPGQ=
+go.mongodb.org/mongo-driver v1.3.3/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
+go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCdE=
+go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
+go.mongodb.org/mongo-driver v1.4.0 h1:C8rFn1VF4GVEM/rG+dSoMmlm2pyQ9cs2/oRtUATejRU=
+go.mongodb.org/mongo-driver v1.4.0/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs=
+go.mongodb.org/mongo-driver v1.4.1 h1:38NSAyDPagwnFpUA/D5SFgbugUYR3NzYRNa4Qk9UxKs=
+go.mongodb.org/mongo-driver v1.4.1/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs=
+go.mongodb.org/mongo-driver v1.4.2 h1:WlnEglfTg/PfPq4WXs2Vkl/5ICC6hoG8+r+LraPmGk4=
+go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
+go.mongodb.org/mongo-driver v1.4.3 h1:moga+uhicpVshTyaqY9L23E6QqwcHRUv1sqyOsoyOO8=
+go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
+go.mongodb.org/mongo-driver v1.4.4 h1:bsPHfODES+/yx2PCWzUYMH8xj6PVniPI8DQrsJuSXSs=
+go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
+go.mongodb.org/mongo-driver v1.4.6 h1:rh7GdYmDrb8AQSkF8yteAus8qYOgOASWDOv1BWqBXkU=
+go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
+go.mongodb.org/mongo-driver v1.5.0 h1:REddm85e1Nl0JPXGGhgZkgJdG/yOe6xvpXUcYK5WLt0=
+go.mongodb.org/mongo-driver v1.5.0/go.mod h1:boiGPFqyBs5R0R5qf2ErokGRekMfwn+MqKaUyHs7wy0=
+go.mongodb.org/mongo-driver v1.5.2 h1:AsxOLoJTgP6YNM0fXWw4OjdluYmWzQYp+lFJL7xu9fU=
+go.mongodb.org/mongo-driver v1.5.2/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
+go.mongodb.org/mongo-driver v1.5.3 h1:wWbFB6zaGHpzguF3f7tW94sVE8sFl3lHx8OZx/4OuFI=
+go.mongodb.org/mongo-driver v1.5.3/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
+go.mongodb.org/mongo-driver v1.7.2 h1:pFttQyIiJUHEn50YfZgC9ECjITMT44oiN36uArf/OFg=
+go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
+go.mongodb.org/mongo-driver v1.7.3 h1:G4l/eYY9VrQAK/AUgkV0koQKzQnyddnWxrd/Etf0jIs=
+go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
+go.mongodb.org/mongo-driver v1.8.2 h1:8ssUXufb90ujcIvR6MyE1SchaNj0SFxsakiZgxIyrMk=
+go.mongodb.org/mongo-driver v1.8.2/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
+go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
+go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
+go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
+go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f h1:aZp0e2vLN4MToVqnjNEYEtrEA8RH8U8FN1CU7JgqsPU=
+golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/integration/examples/multiple-renderers/backend/src/main.go b/integration/examples/multiple-renderers/backend/src/main.go
new file mode 100644
index 000000000..34c81c8af
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/main.go
@@ -0,0 +1,117 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"time"
+
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+	"go.mongodb.org/mongo-driver/mongo/readpref"
+)
+
+// guestbookEntry represents the message object returned in the API.
+type guestbookEntry struct {
+	Author  string    `json:"author" bson:"author"`
+	Message string    `json:"message" bson:"message"`
+	Date    time.Time `json:"date" bson:"date"`
+}
+
+type guestbookServer struct {
+	db database
+}
+
+// main starts a server listening on $PORT responding to requests "GET
+// /messages" and "POST /messages" with a JSON API.
+func main() {
+	ctx := context.Background()
+
+	// PORT environment variable is set in guestbook-backend.deployment.yaml.
+	port := os.Getenv("PORT")
+	if port == "" {
+		log.Fatal("PORT environment variable not specified")
+	}
+	// GUESTBOOK_DB_ADDR environment variable is set in guestbook-backend.deployment.yaml.
+	dbAddr := os.Getenv("GUESTBOOK_DB_ADDR")
+	if dbAddr == "" {
+		log.Fatal("GUESTBOOK_DB_ADDR environment variable not specified")
+	}
+
+	mongoURI := "mongodb://" + dbAddr
+	connCtx, cancel := context.WithTimeout(ctx, time.Second*30)
+	defer cancel()
+	dbConn, err := mongo.Connect(connCtx, options.Client().ApplyURI(mongoURI))
+	if err != nil {
+		log.Fatalf("failed to initialize connection to mongodb: %+v", err)
+	}
+	if err := dbConn.Ping(connCtx, readpref.Primary()); err != nil {
+		log.Fatalf("ping to mongodb failed: %+v", err)
+	}
+
+	gs := &guestbookServer{
+		db: &mongodb{
+			conn: dbConn,
+		},
+	}
+
+	log.Printf("backend server listening on port %s", port)
+	http.Handle("/messages", gs)
+	if err := http.ListenAndServe(":"+port, nil); err != nil {
+		log.Fatal(err)
+	}
+}
+
+func (s *guestbookServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	log.Printf("received request: method=%s path=%s", r.Method, r.URL.Path)
+	if r.Method == http.MethodGet {
+		s.getMessagesHandler(w, r)
+	} else if r.Method == http.MethodPost {
+		s.postMessageHandler(w, r)
+	} else {
+		http.Error(w, fmt.Sprintf("unsupported method %s", r.Method), http.StatusMethodNotAllowed)
+	}
+}
+
+func (s *guestbookServer) getMessagesHandler(w http.ResponseWriter, r *http.Request) {
+	entries, err := s.db.entries(r.Context())
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to read entries: %+v", err), http.StatusInternalServerError)
+		// TODO return JSON error
+		return
+	}
+	if err := json.NewEncoder(w).Encode(entries); err != nil {
+		log.Printf("WARNING: failed to encode json into response: %+v", err)
+	} else {
+		log.Printf("%d entries returned", len(entries))
+	}
+}
+
+func (s *guestbookServer) postMessageHandler(w http.ResponseWriter, r *http.Request) {
+	defer r.Body.Close()
+
+	var v guestbookEntry
+	if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
+		http.Error(w, fmt.Sprintf("failed to decode request body into json: %+v", err), http.StatusBadRequest)
+		return
+	}
+	if v.Author == "" {
+		http.Error(w, "empty 'author' value", http.StatusBadRequest)
+		return
+	}
+	if v.Message == "" {
+		http.Error(w, "empty 'message' value", http.StatusBadRequest)
+		return
+	}
+
+	v.Date = time.Now()
+
+	if err := s.db.addEntry(r.Context(), v); err != nil {
+		http.Error(w, fmt.Sprintf("failed to save entry: %+v", err), http.StatusInternalServerError)
+		return
+	}
+	log.Printf("entry saved: author=%q message=%q", v.Author, v.Message)
+}
diff --git a/integration/examples/multiple-renderers/backend/src/mongodb.go b/integration/examples/multiple-renderers/backend/src/mongodb.go
new file mode 100644
index 000000000..5b010f86f
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/src/mongodb.go
@@ -0,0 +1,53 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+)
+
+type mongodb struct {
+	conn *mongo.Client
+}
+
+func (m *mongodb) entries(ctx context.Context) ([]guestbookEntry, error) {
+	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
+	defer cancel()
+
+	col := m.conn.Database("guestbook").Collection("entries")
+	cur, err := col.Find(ctx, bson.D{}, &options.FindOptions{
+		Sort: map[string]interface{}{"_id": -1},
+	})
+	if err != nil {
+		return nil, fmt.Errorf("mongodb.Find failed: %+v", err)
+	}
+	defer cur.Close(ctx)
+
+	var out []guestbookEntry
+	for cur.Next(ctx) {
+		var v guestbookEntry
+		if err := cur.Decode(&v); err != nil {
+			return nil, fmt.Errorf("decoding mongodb record failed: %+v", err)
+		}
+		out = append(out, v)
+	}
+	if err := cur.Err(); err != nil {
+		return nil, fmt.Errorf("failed to iterate on mongodb cursor: %+v", err)
+	}
+	return out, nil
+}
+
+func (m *mongodb) addEntry(ctx context.Context, e guestbookEntry) error {
+	ctx, cancel := context.WithTimeout(ctx, time.Second*3)
+	defer cancel()
+
+	col := m.conn.Database("guestbook").Collection("entries")
+	if _, err := col.InsertOne(ctx, e); err != nil {
+		return fmt.Errorf("mongodb.InsertOne failed: %+v", err)
+	}
+	return nil
+}
diff --git a/integration/examples/multiple-renderers/backend/templates/deployment.yaml b/integration/examples/multiple-renderers/backend/templates/deployment.yaml
new file mode 100644
index 000000000..553c19a2a
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/templates/deployment.yaml
@@ -0,0 +1,29 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    app: {{ .Chart.Name }}
+spec:
+  selector:
+    matchLabels:
+      app: {{ .Chart.Name }}
+  replicas: {{ .Values.replicaCount }}
+  template:
+    metadata:
+      labels:
+        app: {{ .Chart.Name }}
+    spec:
+      containers:
+      - name: {{ .Chart.Name }}
+        image: {{ .Values.image }}
+        ports:
+        - name: http-server
+          containerPort: 8081
+        - name: debug
+          containerPort: 3000
+        env:
+        - name: PORT
+          value: "8081"
+        - name: GUESTBOOK_DB_ADDR
+          value: go-guestbook-mongodb:27017
diff --git a/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml
new file mode 100644
index 000000000..1a0145220
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml
@@ -0,0 +1,29 @@
+################################################################################
+# WARNING: This MongoDB deployment is not suitable for production as the data is
+# not persistently stored and will go away every time the Pod restarts. Consider
+# using a Helm chart that provisions a StatefulSet instead of Deployment.
+################################################################################
+kind: Deployment
+apiVersion: apps/v1
+metadata:
+  name: go-guestbook-mongodb
+  labels:
+    app: guestbook
+    tier: db
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: guestbook
+      tier: db
+  template:
+    metadata:
+      labels:
+        app: guestbook
+        tier: db
+    spec:
+      containers:
+        - name: mongo
+          image: mongo:4
+          ports:
+            - containerPort: 27017
diff --git a/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml
new file mode 100644
index 000000000..64970bfe0
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: go-guestbook-mongodb
+  labels:
+    app: guestbook
+    tier: db
+spec:
+  ports:
+    - port: 27017
+      targetPort: 27017
+  selector:
+    app: guestbook
+    tier: db
diff --git a/integration/examples/multiple-renderers/backend/templates/service.yaml b/integration/examples/multiple-renderers/backend/templates/service.yaml
new file mode 100644
index 000000000..5f7aad5d6
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/templates/service.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    app: {{ .Chart.Name }}
+spec:
+  type: ClusterIP
+  selector:
+    app: {{ .Chart.Name }}
+  ports:
+  - port: 8081
+    targetPort: http-server
diff --git a/integration/examples/multiple-renderers/backend/val.yaml b/integration/examples/multiple-renderers/backend/val.yaml
new file mode 100644
index 000000000..a28bfc3f4
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/val.yaml
@@ -0,0 +1,2 @@
+# This is another YAML-formatted file.
+image: go-guestbook-backend
\ No newline at end of file
diff --git a/integration/examples/multiple-renderers/backend/values.yaml b/integration/examples/multiple-renderers/backend/values.yaml
new file mode 100644
index 000000000..d6c6edc41
--- /dev/null
+++ b/integration/examples/multiple-renderers/backend/values.yaml
@@ -0,0 +1,3 @@
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+replicaCount: 1
\ No newline at end of file
diff --git a/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml b/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml
new file mode 100644
index 000000000..e256fb30e
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml
@@ -0,0 +1,29 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: frontend
+  labels:
+    app: frontend
+spec:
+  selector:
+    matchLabels:
+      app: frontend
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: frontend
+    spec:
+      containers:
+      - name: frontend
+        image: go-guestbook-frontend
+        ports:
+        - name: http-server
+          containerPort: 8080
+        - name: debug
+          containerPort: 3000
+        env:
+        - name: PORT
+          value: "8080"
+        - name: GUESTBOOK_API_ADDR
+          value: localhost:27017
diff --git a/integration/examples/multiple-renderers/frontend/k8s/service.yaml b/integration/examples/multiple-renderers/frontend/k8s/service.yaml
new file mode 100644
index 000000000..fdbe07742
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/k8s/service.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: frontend
+  labels:
+    app: frontend
+spec:
+  type: ClusterIP
+  selector:
+    app: frontend
+  ports:
+  - port: 8080
+    targetPort: http-server
diff --git a/integration/examples/multiple-renderers/frontend/src/Dockerfile b/integration/examples/multiple-renderers/frontend/src/Dockerfile
new file mode 100644
index 000000000..09ef1305d
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/src/Dockerfile
@@ -0,0 +1,31 @@
+# Use base golang image from Docker Hub
+FROM golang:1.17 as build
+
+WORKDIR /app
+
+# Copy the go.mod and go.sum, download the dependencies
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copy rest of the application source code
+COPY . ./
+
+# Compile the application to /app/frontend.
+# Skaffold passes in debug-oriented compiler flags
+ARG SKAFFOLD_GO_GCFLAGS
+RUN echo "Go gcflags: ${SKAFFOLD_GO_GCFLAGS}"
+RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -mod=readonly -v -o /app/frontend .
+
+# Now create separate deployment image
+FROM gcr.io/distroless/base
+
+# Definition of this variable is used by 'skaffold debug' to identify a golang binary.
+# Default behavior - a failure prints a stack trace for the current goroutine.
+# See https://golang.org/pkg/runtime/
+ENV GOTRACEBACK=single
+
+WORKDIR /app
+COPY static /app/static
+COPY templates /app/templates
+COPY --from=build /app/frontend /app/frontend
+ENTRYPOINT ["/app/frontend"]
diff --git a/integration/examples/multiple-renderers/frontend/src/go.mod b/integration/examples/multiple-renderers/frontend/src/go.mod
new file mode 100644
index 000000000..ffdcef69b
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/src/go.mod
@@ -0,0 +1,3 @@
+module frontend
+
+go 1.12
diff --git a/integration/examples/multiple-renderers/frontend/src/go.sum b/integration/examples/multiple-renderers/frontend/src/go.sum
new file mode 100644
index 000000000..e69de29bb
diff --git a/integration/examples/multiple-renderers/frontend/src/main.go b/integration/examples/multiple-renderers/frontend/src/main.go
new file mode 100644
index 000000000..c1dfb6f93
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/src/main.go
@@ -0,0 +1,165 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"html/template"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"time"
+)
+
+var (
+	// tpl stores the parsed frontend html template
+	tpl *template.Template
+)
+
+// guestbookEntry represents the message object returned from the backend API.
+type guestbookEntry struct {
+	Author  string    `json:"author"`
+	Message string    `json:"message"`
+	Date    time.Time `json:"date"`
+}
+
+// main starts a frontend server and connects to the backend.
+func main() {
+	// GUESTBOOK_API_ADDR environment variable is provided in guestbook-frontend.deployment.yaml.
+	backendAddr := os.Getenv("GUESTBOOK_API_ADDR")
+	if backendAddr == "" {
+		log.Fatal("GUESTBOOK_API_ADDR environment variable not specified")
+	}
+
+	// PORT environment variable is provided in guestbook-frontend.deployment.yaml.
+	port := os.Getenv("PORT")
+	if port == "" {
+		log.Fatal("PORT environment variable not specified")
+	}
+
+	// Parse html templates and save them to global variable.
+	t, err := template.New("").Funcs(map[string]interface{}{
+		"since": sinceDate,
+	}).ParseGlob("templates/*.tpl")
+	if err != nil {
+		log.Fatalf("could not parse templates: %+v", err)
+	}
+	tpl = t
+
+	// Register http handlers and start listening on port.
+	fe := &frontendServer{backendAddr: backendAddr}
+	fs := http.FileServer(http.Dir("static"))
+	http.Handle("/static/", http.StripPrefix("/static/", fs))
+	http.HandleFunc("/", fe.homeHandler)
+	http.HandleFunc("/post", fe.postHandler)
+	log.Printf("frontend server listening on port %s", port)
+	if err := http.ListenAndServe(":"+port, nil); err != nil {
+		log.Fatalf("server listen error: %+v", err)
+	}
+}
+
+type frontendServer struct {
+	backendAddr string
+}
+
+// homeHandler handles GET requests to /.
+func (f *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) {
+	log.Printf("received request: %s %s", r.Method, r.URL.Path)
+	if r.Method != http.MethodGet {
+		http.Error(w, fmt.Sprintf("only GET requests are supported (got %s)", r.Method), http.StatusMethodNotAllowed)
+		return
+	}
+	if r.URL.Path != "/" {
+		http.Error(w, "page not found", http.StatusNotFound)
+		return
+	}
+
+	log.Printf("querying backend for entries")
+	resp, err := http.Get(fmt.Sprintf("http://%s/messages", f.backendAddr))
+	if err != nil {
+		http.Error(w, fmt.Sprintf("querying backend failed: %+v", err), http.StatusInternalServerError)
+		return
+	}
+	defer resp.Body.Close()
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to read response body: %+v", err), http.StatusInternalServerError)
+		return
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		http.Error(w, fmt.Sprintf("got status code %d from the backend: %s", resp.StatusCode, string(body)), http.StatusInternalServerError)
+		return
+	}
+
+	log.Printf("parsing backend response into json")
+	var v []guestbookEntry
+	if err := json.Unmarshal(body, &v); err != nil {
+		log.Printf("WARNING: failed to decode json from the api: %+v input=%q", err, string(body))
+		http.Error(w,
+			fmt.Sprintf("could not decode json response from the api: %+v", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	log.Printf("retrieved %d messages from the backend api", len(v))
+	if err := tpl.ExecuteTemplate(w, "home", map[string]interface{}{
+		"messages": v,
+	}); err != nil {
+		log.Printf("WARNING: failed to render html template: %+v", err)
+	}
+}
+
+// postHandler handles POST requests to /messages.
+func (f *frontendServer) postHandler(w http.ResponseWriter, r *http.Request) {
+	log.Printf("received request: %s %s", r.Method, r.URL.Path)
+	if r.Method != http.MethodPost {
+		http.Error(w, "only POST requests are supported", http.StatusMethodNotAllowed)
+		return
+	}
+
+	author := r.FormValue("name")
+	message := r.FormValue("message")
+	if author == "" {
+		http.Error(w, `"name" not specified in the form`, http.StatusBadRequest)
+		return
+	}
+	if message == "" {
+		http.Error(w, `"message" not specified in the form`, http.StatusBadRequest)
+		return
+	}
+
+	if err := f.saveMessage(r.FormValue("name"), r.FormValue("message")); err != nil {
+		http.Error(w, fmt.Sprintf("failed to save message: %+v", err), http.StatusInternalServerError)
+		return
+	}
+
+	http.Redirect(w, r, "/", http.StatusFound) // redirect to homepage
+}
+
+// saveMessage makes a request to the backend to persist the message.
+func (f *frontendServer) saveMessage(author, message string) error {
+	entry := guestbookEntry{
+		Author:  author,
+		Message: message,
+	}
+	body, err := json.Marshal(entry)
+	if err != nil {
+		return fmt.Errorf("failed to serialize message into json: %+v", err)
+	}
+
+	resp, err := http.Post(fmt.Sprintf("http://%s/messages", f.backendAddr), "application/json", bytes.NewReader(body))
+	if err != nil {
+		return fmt.Errorf("backend returned failure: %+v", err)
+	}
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("unexpected status code from backend: %d %v", resp.StatusCode, resp.Status)
+	}
+	defer resp.Body.Close()
+	return nil
+}
+
+// sinceDate is used in the html template to display human-friendly dates.
+func sinceDate(t time.Time) string { return time.Since(t).Truncate(time.Second).String() }
diff --git a/integration/examples/multiple-renderers/frontend/src/static/style.css b/integration/examples/multiple-renderers/frontend/src/static/style.css
new file mode 100644
index 000000000..b0ee5b631
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/src/static/style.css
@@ -0,0 +1,111 @@
+body {
+    font-family: 'Roboto', sans-serif;
+    background: #f8f9fa;
+}
+
+.container {
+    margin-top: 50px;
+    background: white;
+    border-radius: 10px;
+    z-index: 10;
+    position: relative;
+    padding: 50px 16px;
+}
+
+.next-logo {
+    position: absolute;
+    right: 0;
+    top: 0;
+    opacity: 0.5;
+    z-index: -1;
+    width: 30%
+}
+
+a:hover {
+    text-decoration: none;
+}
+
+.header .container {
+    background: none;
+}
+
+.form-inline {
+    margin-bottom: 40px;
+}
+
+h1 {
+    margin-bottom: 2rem;
+    max-width: 1140px;
+    margin: auto;
+    padding-bottom: 16px;
+    position: relative;
+}
+
+.card-body {
+    margin: 10px;
+}
+  
+.posts:after {
+    background: linear-gradient(to right, #4285f4 25%,#db4437 25%, #db4437 50%, #f4b400 50%, #f4b400 75%, #0f9d58 75%);
+    position: absolute;
+    content: '';
+    height: 4px;
+    right: 0;
+    left: 0;
+    top: 0;
+}
+
+.card {
+    border: none;
+    box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+    display: inline-block;
+}
+
+.github {
+    max-width: 80px;
+    opacity: 0.5;
+}
+
+.github:hover {
+    opacity: 1;
+}
+
+h5 {
+    font-size: 24px;
+    float: left;
+}
+
+h6 {
+    font-size: 14px;
+    color: black;
+    float: right;
+}
+
+p {
+    font-size: 14px;
+    color: #646464;
+    margin-top: 1rem !important;
+}
+
+h1 a {
+    color: #202124;
+    font-size: 60px;
+}
+
+.header {
+    margin: 0;
+    position: relative;
+}
+
+@media (min-width: 1200px) {
+    .container {
+        max-width: 900px;
+        padding: 50px;
+    }
+}
+
+@media (max-width: 480px) {
+    h1 a {
+        font-size: 40px;
+    }
+}
diff --git a/integration/examples/multiple-renderers/frontend/src/templates/home.tpl b/integration/examples/multiple-renderers/frontend/src/templates/home.tpl
new file mode 100644
index 000000000..7ea94314f
--- /dev/null
+++ b/integration/examples/multiple-renderers/frontend/src/templates/home.tpl
@@ -0,0 +1,64 @@
+{{ define "home" }}
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Guestbook</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
+    <link rel="stylesheet" href="/static/style.css" type="text/css">
+    <link rel="icon" href="/static/favicon.png" type="image/x-icon"/>
+    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
+</head>
+
+<body>
+    <div class="header">
+        <div class="container">
+            <h1>
+                <a href="/">
+                    My Guestbook
+                </a>
+            </h1>
+            <a href="#" class="text-muted">View on GitHub</a>
+        </div>
+    </div>
+
+    <div class="container posts mt-0">
+        <form class="form-inline" method="POST" action="/post">
+            <label class="sr-only" for="name">Name</label>
+            <div class="input-group mb-2 mr-sm-2">
+                <div class="input-group-prepend">
+                    <div class="input-group-text">Your Name</div>
+                </div>
+                <input type="text" class="form-control" id="name" name="name" required>
+            </div>
+            <label class="sr-only" for="message">Message</label>
+            <div class="input-group mb-2 mr-sm-2">
+                <div class="input-group-prepend">
+                    <div class="input-group-text">Message</div>
+                </div>
+                <input type="text" class="form-control" id="message" name="message" required>
+            </div>
+            <button type="submit" class="btn btn-primary mb-2">Post to Guestbook</button>
+        </form>
+
+        {{ range .messages }}
+        <div class="card my-3 col-12">
+            <div class="card-body">
+                <h5 class="card-title">{{.Author}}</h5>
+                <h6 class="card-subtitle mb-2 text-muted">{{ since .Date}} ago</h6>
+                <br>
+                <p class="card-text">
+                    {{ .Message }}
+                </p>
+            </div>
+        </div>
+        {{ else }}
+            <div class="alert alert-info" role="alert">
+                No messages are logged to the guestbook yet.
+            </div>
+        {{ end }}
+    </div>
+</body>
+</html>
+{{ end }}
diff --git a/integration/examples/multiple-renderers/skaffold.yaml b/integration/examples/multiple-renderers/skaffold.yaml
new file mode 100644
index 000000000..1717a229f
--- /dev/null
+++ b/integration/examples/multiple-renderers/skaffold.yaml
@@ -0,0 +1,40 @@
+apiVersion: skaffold/v3alpha1
+kind: Config
+metadata:
+  name: go-guestbook
+build:
+  artifacts:
+  - image: go-guestbook-backend
+    context: backend/src
+    docker:
+      dockerfile: Dockerfile
+  - image: go-guestbook-frontend
+    context: frontend/src
+    docker:
+      dockerfile: Dockerfile
+manifests:
+  rawYaml:
+  - frontend/k8s/*.yaml
+  helm:
+    releases:
+    - name: backend
+      chartPath: backend
+      valuesFiles:
+      - backend/val.yaml
+      - backend/values.yaml
+      version: 0.1.0
+
+profiles:
+  - name: mix-deploy
+    patches:
+     - op: remove
+       path: /manifests/helm
+    deploy:
+      helm:
+        releases:
+        - name: backend
+          chartPath: backend
+          valuesFiles:
+          - backend/val.yaml
+          - backend/values.yaml
+          version: 0.1.0
diff --git a/integration/examples/profile-patches/skaffold.yaml b/integration/examples/profile-patches/skaffold.yaml
index 96d8bf0a0..21caa4ac4 100644
--- a/integration/examples/profile-patches/skaffold.yaml
+++ b/integration/examples/profile-patches/skaffold.yaml
@@ -5,10 +5,9 @@ build:
   artifacts:
   - image: skaffold-base
     context: base-service
-deploy:
-  kubectl:
-    manifests:
-      - 'base-service/*.yaml'
+manifests:
+  rawYaml:
+  - 'base-service/*.yaml'
 
 profiles:
   - name: hello
@@ -19,7 +18,7 @@ profiles:
           image: skaffold-hello
           context: hello-service
       - op: add
-        path: /deploy/kubectl/manifests/1
+        path: /manifests/rawYaml/1
         value: 'hello-service/*.yaml'
 
   - name: world
@@ -30,5 +29,5 @@ profiles:
           image: skaffold-world
           context: world-service
       - op: add
-        path: /deploy/kubectl/manifests/1
+        path: /manifests/rawYaml/1
         value: 'world-service/*.yaml'
diff --git a/integration/examples/simple-artifact-dependency/skaffold.yaml b/integration/examples/simple-artifact-dependency/skaffold.yaml
index 87a8f585d..fca30aa78 100644
--- a/integration/examples/simple-artifact-dependency/skaffold.yaml
+++ b/integration/examples/simple-artifact-dependency/skaffold.yaml
@@ -9,8 +9,7 @@ build:
       alias: BASE
   - image: base
     context: base
-deploy:
-  kubectl:
-    manifests:
-    - app/k8s-pod.yaml
+manifests:
+  rawYaml:
+  - app/k8s-pod.yaml
 
diff --git a/pkg/skaffold/build/buildpacks/fetcher.go b/pkg/skaffold/build/buildpacks/fetcher.go
index 14389ec0b..93ed7322e 100644
--- a/pkg/skaffold/build/buildpacks/fetcher.go
+++ b/pkg/skaffold/build/buildpacks/fetcher.go
@@ -25,6 +25,7 @@ import (
 	"github.com/buildpacks/imgutil/local"
 	pack "github.com/buildpacks/pack/pkg/client"
 	packimg "github.com/buildpacks/pack/pkg/image"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
 )
@@ -45,7 +46,7 @@ func newFetcher(out io.Writer, docker docker.LocalDaemon) *fetcher {
 
 func (f *fetcher) Fetch(ctx context.Context, name string, options packimg.FetchOptions) (imgutil.Image, error) {
 	if options.PullPolicy == packimg.PullAlways || (options.PullPolicy == packimg.PullIfNotPresent && !f.docker.ImageExists(ctx, name)) {
-		if err := f.docker.Pull(ctx, f.out, name); err != nil {
+		if err := f.docker.Pull(ctx, f.out, name, v1.Platform{Architecture: "amd64", OS: "linux"}); err != nil {
 			return nil, err
 		}
 	}
diff --git a/pkg/skaffold/build/cache/lookup.go b/pkg/skaffold/build/cache/lookup.go
index 1ebf062c2..369c3a6eb 100644
--- a/pkg/skaffold/build/cache/lookup.go
+++ b/pkg/skaffold/build/cache/lookup.go
@@ -22,12 +22,15 @@ import (
 	"io"
 	"sync"
 
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/instrumentation"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/tag"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
 )
 
 func (c *cache) lookupArtifacts(ctx context.Context, tags tag.ImageTags, platforms platform.Resolver, artifacts []*latest.Artifact) []cacheDetails {
@@ -67,8 +70,16 @@ func (c *cache) lookup(ctx context.Context, a *latest.Artifact, tag string, plat
 	c.cacheMutex.RLock()
 	entry, cacheHit := c.artifactCache[hash]
 	c.cacheMutex.RUnlock()
-	if !cacheHit {
-		if entry, err = c.tryImport(ctx, a, tag, hash); err != nil {
+
+	pls := platforms.GetPlatforms(a.ImageName)
+	// TODO (gaghosh): allow `tryImport` when the Docker daemon starts supporting multiarch images
+	// See https://github.com/docker/buildx/issues/1220#issuecomment-1189996403
+	if !cacheHit && !pls.IsMultiPlatform() {
+		var pl v1.Platform
+		if len(pls.Platforms) == 1 {
+			pl = util.ConvertToV1Platform(pls.Platforms[0])
+		}
+		if entry, err = c.tryImport(ctx, a, tag, hash, pl); err != nil {
 			log.Entry(ctx).Debugf("Could not import artifact from Docker, building instead (%s)", err)
 			return needsBuilding{hash: hash}
 		}
@@ -131,7 +142,7 @@ func (c *cache) lookupRemote(ctx context.Context, hash, tag string, entry ImageD
 	return needsBuilding{hash: hash}
 }
 
-func (c *cache) tryImport(ctx context.Context, a *latest.Artifact, tag string, hash string) (ImageDetails, error) {
+func (c *cache) tryImport(ctx context.Context, a *latest.Artifact, tag string, hash string, pl v1.Platform) (ImageDetails, error) {
 	entry := ImageDetails{}
 
 	if importMissing, err := c.importMissingImage(a.ImageName); err != nil {
@@ -142,7 +153,7 @@ func (c *cache) tryImport(ctx context.Context, a *latest.Artifact, tag string, h
 
 	if !c.client.ImageExists(ctx, tag) {
 		log.Entry(ctx).Debugf("Importing artifact %s from docker registry", tag)
-		err := c.client.Pull(ctx, io.Discard, tag)
+		err := c.client.Pull(ctx, io.Discard, tag, pl)
 		if err != nil {
 			return entry, err
 		}
diff --git a/pkg/skaffold/build/docker/docker.go b/pkg/skaffold/build/docker/docker.go
index 843f1bbba..e471c8498 100644
--- a/pkg/skaffold/build/docker/docker.go
+++ b/pkg/skaffold/build/docker/docker.go
@@ -23,6 +23,8 @@ import (
 	"os"
 	"os/exec"
 
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/instrumentation"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
@@ -39,6 +41,10 @@ func (b *Builder) SupportedPlatforms() platform.Matcher {
 }
 
 func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, matcher platform.Matcher) (string, error) {
+	var pl v1.Platform
+	if len(matcher.Platforms) == 1 {
+		pl = util.ConvertToV1Platform(matcher.Platforms[0])
+	}
 	a = adjustCacheFrom(a, tag)
 	instrumentation.AddAttributesToCurrentSpanFromContext(ctx, map[string]string{
 		"BuildType":   "docker",
@@ -55,7 +61,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact,
 		return "", dockerfileNotFound(err, a.ImageName)
 	}
 
-	if err := b.pullCacheFromImages(ctx, out, a.ArtifactType.DockerArtifact); err != nil {
+	if err := b.pullCacheFromImages(ctx, out, a.ArtifactType.DockerArtifact, pl); err != nil {
 		return "", cacheFromPullErr(err, a.ImageName)
 	}
 	opts := docker.BuildOptions{Tag: tag, Mode: b.cfg.Mode(), ExtraBuildArgs: docker.ResolveDependencyImages(a.Dependencies, b.artifacts, true)}
@@ -66,7 +72,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact,
 	// we might consider a different approach in the future.
 	// use CLI for cross-platform builds
 	if b.useCLI || (b.useBuildKit != nil && *b.useBuildKit) || len(a.DockerArtifact.CliFlags) > 0 || matcher.IsNotEmpty() {
-		imageID, err = b.dockerCLIBuild(ctx, output.GetUnderlyingWriter(out), a.ImageName, a.Workspace, dockerfile, a.ArtifactType.DockerArtifact, opts, matcher)
+		imageID, err = b.dockerCLIBuild(ctx, output.GetUnderlyingWriter(out), a.ImageName, a.Workspace, dockerfile, a.ArtifactType.DockerArtifact, opts, pl)
 	} else {
 		imageID, err = b.localDocker.Build(ctx, out, a.Workspace, a.ImageName, a.ArtifactType.DockerArtifact, opts)
 	}
@@ -84,12 +90,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact,
 	return imageID, nil
 }
 
-func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string, workspace string, dockerfilePath string, a *latest.DockerArtifact, opts docker.BuildOptions, matcher platform.Matcher) (string, error) {
-	if matcher.IsMultiPlatform() {
-		// TODO: implement multi platform build
-		log.Entry(ctx).Warnf("multiple target platforms %q found for artifact %q. Skaffold doesn't yet support multi-platform builds for the docker builder. Consider specifying a single target platform explicitly. See https://skaffold.dev/docs/pipeline-stages/builders/#cross-platform-build-support", matcher.String(), name)
-	}
-
+func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string, workspace string, dockerfilePath string, a *latest.DockerArtifact, opts docker.BuildOptions, pl v1.Platform) (string, error) {
 	args := []string{"build", workspace, "--file", dockerfilePath, "-t", opts.Tag}
 	ba, err := docker.EvalBuildArgs(b.cfg.Mode(), workspace, a.DockerfilePath, a.BuildArgs, opts.ExtraBuildArgs)
 	if err != nil {
@@ -105,8 +106,8 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string
 		args = append(args, "--force-rm")
 	}
 
-	if len(matcher.Platforms) == 1 {
-		args = append(args, "--platform", platform.Format(matcher.Platforms[0]))
+	if pl.String() != "" {
+		args = append(args, "--platform", pl.String())
 	}
 
 	cmd := exec.CommandContext(ctx, "docker", args...)
@@ -117,8 +118,8 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string
 		} else {
 			cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0")
 		}
-	} else if len(matcher.Platforms) == 1 { // cross-platform builds require buildkit
-		log.Entry(ctx).Debugf("setting DOCKER_BUILDKIT=1 for docker build for artifact %q since it targets platform %q", name, matcher.Platforms[0])
+	} else if pl.String() != "" { // cross-platform builds require buildkit
+		log.Entry(ctx).Debugf("setting DOCKER_BUILDKIT=1 for docker build for artifact %q since it targets platform %q", name, pl.String())
 		cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=1")
 	}
 	cmd.Stdout = out
@@ -131,7 +132,7 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string
 	return b.localDocker.ImageID(ctx, opts.Tag)
 }
 
-func (b *Builder) pullCacheFromImages(ctx context.Context, out io.Writer, a *latest.DockerArtifact) error {
+func (b *Builder) pullCacheFromImages(ctx context.Context, out io.Writer, a *latest.DockerArtifact, pl v1.Platform) error {
 	if len(a.CacheFrom) == 0 {
 		return nil
 	}
@@ -146,8 +147,8 @@ func (b *Builder) pullCacheFromImages(ctx context.Context, out io.Writer, a *lat
 			continue
 		}
 
-		if err := b.localDocker.Pull(ctx, out, image); err != nil {
-			warnings.Printf("cacheFrom image couldn't be pulled: %s\n", image)
+		if err := b.localDocker.Pull(ctx, out, image, pl); err != nil {
+			warnings.Printf("cacheFrom image %q couldn't be pulled for platform %q\n", image, pl)
 		}
 	}
 
diff --git a/pkg/skaffold/config/options.go b/pkg/skaffold/config/options.go
index 2b92a83ef..6e8988b04 100644
--- a/pkg/skaffold/config/options.go
+++ b/pkg/skaffold/config/options.go
@@ -61,6 +61,8 @@ type SkaffoldOptions struct {
 	EnablePlatformNodeAffinity bool
 	MakePathsAbsolute          *bool
 	MultiLevelRepo             *bool
+	CloudRunProject            string
+	CloudRunLocation           string
 	ConfigurationFile          string
 	HydrationDir               string
 	InventoryNamespace         string
diff --git a/pkg/skaffold/deploy/docker/deploy.go b/pkg/skaffold/deploy/docker/deploy.go
index f6dad5b82..1435df268 100644
--- a/pkg/skaffold/deploy/docker/deploy.go
+++ b/pkg/skaffold/deploy/docker/deploy.go
@@ -25,6 +25,7 @@ import (
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/mount"
 	"github.com/docker/go-connections/nat"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/pkg/errors"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/access"
@@ -229,7 +230,7 @@ func (d *Deployer) setupDebugging(ctx context.Context, out io.Writer, artifact g
 			continue
 		}
 		// pull the debug support image into the local daemon
-		if err := d.client.Pull(ctx, out, c.Image); err != nil {
+		if err := d.client.Pull(ctx, out, c.Image, v1.Platform{}); err != nil {
 			return nil, errors.Wrap(err, "pulling init container image")
 		}
 		// create the init container
diff --git a/pkg/skaffold/deploy/kubectl/errors.go b/pkg/skaffold/deploy/kubectl/errors.go
index 5b3f35bbe..1e809561f 100644
--- a/pkg/skaffold/deploy/kubectl/errors.go
+++ b/pkg/skaffold/deploy/kubectl/errors.go
@@ -59,14 +59,6 @@ func readManifestErr(err error) error {
 		})
 }
 
-func readRemoteManifestErr(err error) error {
-	return sErrors.NewError(err,
-		&proto.ActionableErr{
-			Message: err.Error(),
-			ErrCode: proto.StatusCode_DEPLOY_READ_REMOTE_MANIFEST_ERR,
-		})
-}
-
 func userErr(err error) error {
 	return deployerr.UserError(err, proto.StatusCode_DEPLOY_KUBECTL_USER_ERR)
 }
diff --git a/pkg/skaffold/deploy/kubectl/kubectl.go b/pkg/skaffold/deploy/kubectl/kubectl.go
index 9285a8508..14539ac55 100644
--- a/pkg/skaffold/deploy/kubectl/kubectl.go
+++ b/pkg/skaffold/deploy/kubectl/kubectl.go
@@ -17,11 +17,9 @@ limitations under the License.
 package kubectl
 
 import (
-	"bytes"
 	"context"
 	"fmt"
 	"io"
-	"strings"
 
 	"github.com/segmentio/textio"
 	"go.opentelemetry.io/otel/trace"
@@ -50,7 +48,6 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/status"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/stringslice"
 )
 
 // Deployer deploys workflows using kubectl CLI.
@@ -72,7 +69,6 @@ type Deployer struct {
 	hydratedManifests  []string
 	workingDir         string
 	globalConfig       string
-	gcsManifestDir     string
 	defaultRepo        *string
 	multiLevelRepo     *bool
 	kubectl            CLI
@@ -281,72 +277,6 @@ func (k *Deployer) PostDeployHooks(ctx context.Context, out io.Writer) error {
 	return nil
 }
 
-func (k *Deployer) manifestFiles(manifests []string) ([]string, error) {
-	var nonURLManifests, gcsManifests []string
-	for _, manifest := range manifests {
-		switch {
-		case util.IsURL(manifest):
-		case strings.HasPrefix(manifest, "gs://"):
-			gcsManifests = append(gcsManifests, manifest)
-		default:
-			nonURLManifests = append(nonURLManifests, manifest)
-		}
-	}
-
-	list, err := util.ExpandPathsGlob(k.workingDir, nonURLManifests)
-	if err != nil {
-		return nil, userErr(fmt.Errorf("expanding kubectl manifest paths: %w", err))
-	}
-
-	if len(gcsManifests) != 0 {
-		// return tmp dir of the downloaded manifests
-		tmpDir, err := manifest.DownloadFromGCS(gcsManifests)
-		if err != nil {
-			return nil, userErr(fmt.Errorf("downloading from GCS: %w", err))
-		}
-		k.gcsManifestDir = tmpDir
-		l, err := util.ExpandPathsGlob(tmpDir, []string{"*"})
-		if err != nil {
-			return nil, userErr(fmt.Errorf("expanding kubectl manifest paths: %w", err))
-		}
-		list = append(list, l...)
-	}
-
-	var filteredManifests []string
-	for _, f := range list {
-		if !kubernetes.HasKubernetesFileExtension(f) {
-			if !stringslice.Contains(manifests, f) {
-				olog.Entry(context.TODO()).Infof("refusing to deploy/delete non {json, yaml} file %s", f)
-				olog.Entry(context.TODO()).Info("If you still wish to deploy this file, please specify it directly, outside a glob pattern.")
-				continue
-			}
-		}
-		filteredManifests = append(filteredManifests, f)
-	}
-
-	return filteredManifests, nil
-}
-
-// readRemoteManifests will try to read manifests from the given kubernetes
-// context in the specified namespace and for the specified type
-func (k *Deployer) readRemoteManifest(ctx context.Context, name string) ([]byte, error) {
-	var args []string
-	ns := ""
-	if parts := strings.Split(name, ":"); len(parts) > 1 {
-		ns = parts[0]
-		name = parts[1]
-	}
-	args = append(args, name, "-o", "yaml")
-
-	var manifest bytes.Buffer
-	err := k.kubectl.RunInNamespace(ctx, nil, &manifest, "get", ns, args...)
-	if err != nil {
-		return nil, readRemoteManifestErr(fmt.Errorf("getting remote manifests: %w", err))
-	}
-
-	return manifest.Bytes(), nil
-}
-
 // Cleanup deletes what was deployed by calling Deploy.
 func (k *Deployer) Cleanup(ctx context.Context, out io.Writer, dryRun bool, manifestsByConfig manifest.ManifestListByConfig) error {
 	var manifests manifest.ManifestList
@@ -355,34 +285,11 @@ func (k *Deployer) Cleanup(ctx context.Context, out io.Writer, dryRun bool, mani
 		"DeployerType": "kubectl",
 	})
 	if dryRun {
-		for _, manifest := range manifests {
-			output.White.Fprintf(out, "---\n%s", manifest)
+		for _, manifestP := range manifests {
+			output.White.Fprintf(out, "---\n%s", manifestP)
 		}
 		return nil
 	}
-	// revert remote manifests
-	// TODO(dgageot): That seems super dangerous and I don't understand
-	// why we need to update resources just before we delete them.
-	// todo clean up this block as RemoteManifests is no longer used for deployer
-	if len(k.RemoteManifests) > 0 {
-		var rm manifest.ManifestList
-		for _, m := range k.RemoteManifests {
-			manifest, err := k.readRemoteManifest(ctx, m)
-			if err != nil {
-				return err
-			}
-			rm = append(rm, manifest)
-		}
-
-		upd, err := rm.ReplaceRemoteManifestImages(ctx, k.originalImages, manifest.NewResourceSelectorImages(k.transformableAllowlist, k.transformableDenylist))
-		if err != nil {
-			return err
-		}
-
-		if err := k.kubectl.Apply(ctx, out, upd); err != nil {
-			return err
-		}
-	}
 
 	if err := k.kubectl.Delete(ctx, textio.NewPrefixWriter(out, " - "), manifests); err != nil {
 		return err
@@ -393,5 +300,5 @@ func (k *Deployer) Cleanup(ctx context.Context, out io.Writer, dryRun bool, mani
 
 // Dependencies lists all the files that describe what needs to be deployed.
 func (k *Deployer) Dependencies() ([]string, error) {
-	return k.manifestFiles(k.KubectlDeploy.Manifests)
+	return []string{}, nil
 }
diff --git a/pkg/skaffold/docker/image.go b/pkg/skaffold/docker/image.go
index f0d7f3509..9e179326d 100644
--- a/pkg/skaffold/docker/image.go
+++ b/pkg/skaffold/docker/image.go
@@ -86,7 +86,7 @@ type LocalDaemon interface {
 	ContainerInspect(ctx context.Context, id string) (types.ContainerJSON, error)
 	ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error)
 	Push(ctx context.Context, out io.Writer, ref string) (string, error)
-	Pull(ctx context.Context, out io.Writer, ref string) error
+	Pull(ctx context.Context, out io.Writer, ref string, platform v1.Platform) error
 	Load(ctx context.Context, out io.Writer, input io.Reader, ref string) (string, error)
 	Run(ctx context.Context, out io.Writer, opts ContainerCreateOpts) (<-chan container.ContainerWaitOKBody, <-chan error, string, error)
 	Delete(ctx context.Context, out io.Writer, id string) error
@@ -287,7 +287,7 @@ func (l *localDaemon) ConfigFile(ctx context.Context, image string) (*v1.ConfigF
 			return nil, err
 		}
 	} else {
-		cfg, err = RetrieveRemoteConfig(image, l.cfg, nil)
+		cfg, err = RetrieveRemoteConfig(image, l.cfg, v1.Platform{})
 		if err != nil {
 			return nil, err
 		}
@@ -472,7 +472,7 @@ func (l *localDaemon) isAlreadyPushed(ctx context.Context, ref, registryAuth str
 }
 
 // Pull pulls an image reference from a registry.
-func (l *localDaemon) Pull(ctx context.Context, out io.Writer, ref string) error {
+func (l *localDaemon) Pull(ctx context.Context, out io.Writer, ref string, platform v1.Platform) error {
 	// We first try pulling the image with credentials.  If that fails then retry
 	// without credentials in case the image is public.
 
@@ -503,6 +503,7 @@ func (l *localDaemon) Pull(ctx context.Context, out io.Writer, ref string) error
 			//     return "" to retry as an anonymous pull.
 			return "", err
 		},
+		Platform: platform.String(),
 	})
 	if err != nil {
 		return fmt.Errorf("pulling image from repository: %w", err)
diff --git a/pkg/skaffold/docker/image_util.go b/pkg/skaffold/docker/image_util.go
index 29e3c14ed..f465e071b 100644
--- a/pkg/skaffold/docker/image_util.go
+++ b/pkg/skaffold/docker/image_util.go
@@ -40,7 +40,7 @@ func RetrieveConfigFile(ctx context.Context, tagged string, cfg Config) (*v1.Con
 	}
 	if err != nil {
 		// No local Docker is available
-		cf, err = RetrieveRemoteConfig(tagged, cfg, nil)
+		cf, err = RetrieveRemoteConfig(tagged, cfg, v1.Platform{})
 	}
 	if err != nil {
 		return nil, fmt.Errorf("retrieving image config: %w", err)
diff --git a/pkg/skaffold/docker/remote.go b/pkg/skaffold/docker/remote.go
index b0f56a610..4683989cd 100644
--- a/pkg/skaffold/docker/remote.go
+++ b/pkg/skaffold/docker/remote.go
@@ -40,16 +40,29 @@ var (
 
 func AddRemoteTag(src, target string, cfg Config, platforms []specs.Platform) error {
 	log.Entry(context.TODO()).Debugf("attempting to add tag %s to src %s", target, src)
-	img, err := getRemoteImage(src, cfg, platforms)
-	if err != nil {
-		return fmt.Errorf("getting image: %w", err)
-	}
 
 	targetRef, err := parseReference(target, cfg, name.WeakValidation)
 	if err != nil {
 		return err
 	}
 
+	if len(platforms) > 1 {
+		index, err := getRemoteIndex(src, cfg)
+		if err != nil {
+			return fmt.Errorf("getting image index: %w", err)
+		}
+		return remote.WriteIndex(targetRef, index, remote.WithAuthFromKeychain(primaryKeychain))
+	}
+
+	var pl v1.Platform
+	if len(platforms) == 1 {
+		pl = util.ConvertToV1Platform(platforms[0])
+	}
+	img, err := getRemoteImage(src, cfg, pl)
+	if err != nil {
+		return fmt.Errorf("getting image: %w", err)
+	}
+
 	return remote.Write(targetRef, img, remote.WithAuthFromKeychain(primaryKeychain))
 }
 
@@ -58,8 +71,14 @@ func getRemoteDigest(identifier string, cfg Config, platforms []specs.Platform)
 	if err == nil {
 		return digest(idx)
 	}
-
-	img, err := getRemoteImage(identifier, cfg, platforms)
+	if len(platforms) > 1 {
+		return "", fmt.Errorf("cannot fetch remote index for multiple platform image %q: %w", identifier, err)
+	}
+	var pl v1.Platform
+	if len(platforms) == 1 {
+		pl = util.ConvertToV1Platform(platforms[0])
+	}
+	img, err := getRemoteImage(identifier, cfg, pl)
 	if err != nil {
 		return "", fmt.Errorf("getting image: %w", err)
 	}
@@ -68,8 +87,8 @@ func getRemoteDigest(identifier string, cfg Config, platforms []specs.Platform)
 }
 
 // RetrieveRemoteConfig retrieves the remote config file for an image
-func RetrieveRemoteConfig(identifier string, cfg Config, platforms []specs.Platform) (*v1.ConfigFile, error) {
-	img, err := getRemoteImage(identifier, cfg, platforms)
+func RetrieveRemoteConfig(identifier string, cfg Config, platform v1.Platform) (*v1.ConfigFile, error) {
+	img, err := getRemoteImage(identifier, cfg, platform)
 	if err != nil {
 		return nil, err
 	}
@@ -96,13 +115,7 @@ func Push(tarPath, tag string, cfg Config, platforms []specs.Platform) (string,
 	return getRemoteDigest(tag, cfg, platforms)
 }
 
-func getRemoteImage(identifier string, cfg Config, platforms []specs.Platform) (v1.Image, error) {
-	// for multi-arch images, we can only get the image for one platform at a time.
-	// If the platform is not specified then it'll fetch the image for the host architecture.
-	// To avoid discrepencies, we fail image fetch for multi-platform images. These should instead be accessed with the `remoteIndex` method.
-	if len(platforms) > 1 {
-		return nil, fmt.Errorf("cannot fetch remote image %q for multiple platforms %q", identifier, platforms)
-	}
+func getRemoteImage(identifier string, cfg Config, platform v1.Platform) (v1.Image, error) {
 	ref, err := parseReference(identifier, cfg)
 	if err != nil {
 		return nil, err
@@ -110,8 +123,8 @@ func getRemoteImage(identifier string, cfg Config, platforms []specs.Platform) (
 	options := []remote.Option{
 		remote.WithAuthFromKeychain(primaryKeychain),
 	}
-	if len(platforms) == 1 {
-		options = append(options, remote.WithPlatform(util.ConvertToV1Platform(platforms[0])))
+	if platform.String() != "" {
+		options = append(options, remote.WithPlatform(platform))
 	}
 
 	return remoteImage(ref, options...)
diff --git a/pkg/skaffold/helm/args.go b/pkg/skaffold/helm/args.go
index 311b2465c..46ce47267 100644
--- a/pkg/skaffold/helm/args.go
+++ b/pkg/skaffold/helm/args.go
@@ -130,5 +130,9 @@ func envVarForImage(imageName string, digest string) map[string]string {
 	} else {
 		customMap["DIGEST_HEX"] = digest
 	}
+
+	// IMAGE_DOMAIN and IMAGE_REPO_NO_DOMAIN added for v2beta* 'helm+explicitRegistry' -> v3alpha* compatibility
+	customMap["IMAGE_DOMAIN"] = ref.Domain
+	customMap["IMAGE_REPO_NO_DOMAIN"] = strings.TrimPrefix(ref.BaseName, ref.Domain+"/")
 	return customMap
 }
diff --git a/pkg/skaffold/kubernetes/manifest/manifests.go b/pkg/skaffold/kubernetes/manifest/manifests.go
index 185d89a1c..92d56de81 100644
--- a/pkg/skaffold/kubernetes/manifest/manifests.go
+++ b/pkg/skaffold/kubernetes/manifest/manifests.go
@@ -46,8 +46,12 @@ func NewManifestListByConfig() ManifestListByConfig {
 }
 
 func (ml *ManifestListByConfig) Add(configName string, manifest ManifestList) {
-	ml.configNames = append(ml.configNames, configName)
-	ml.manifests[configName] = manifest
+	if _, ok := ml.manifests[configName]; !ok {
+		ml.configNames = append(ml.configNames, configName)
+		ml.manifests[configName] = manifest
+		return
+	}
+	ml.manifests[configName] = append(ml.manifests[configName], manifest...)
 }
 
 func (ml ManifestListByConfig) GetForConfig(configName string) ManifestList {
diff --git a/pkg/skaffold/lint/k8smanifests.go b/pkg/skaffold/lint/k8smanifests.go
index 9b6136487..08953c519 100644
--- a/pkg/skaffold/lint/k8smanifests.go
+++ b/pkg/skaffold/lint/k8smanifests.go
@@ -67,10 +67,7 @@ func GetK8sManifestsLintResults(ctx context.Context, opts Options) (*[]Result, e
 	}
 
 	for _, c := range cfgs {
-		if c.Deploy.KubectlDeploy == nil {
-			continue
-		}
-		for _, pattern := range c.Deploy.KubectlDeploy.Manifests {
+		for _, pattern := range c.Render.RawK8s {
 			// NOTE: pattern is a pattern that can have wildcards, eg: leeroy-app/kubernetes/*
 			if util.IsURL(pattern) {
 				log.Entry(ctx).Debugf("skaffold lint found url manifest and is skipping lint rules for: %s", pattern)
diff --git a/pkg/skaffold/lint/skaffoldyamls.go b/pkg/skaffold/lint/skaffoldyamls.go
index c3670dc8d..ac2d09a60 100644
--- a/pkg/skaffold/lint/skaffoldyamls.go
+++ b/pkg/skaffold/lint/skaffoldyamls.go
@@ -83,13 +83,13 @@ var skaffoldYamlLintRules = []Rule{
   localPort: {{ $v.LocalPort }}{{end}}`,
 		LintConditions: []func(InputParams) bool{
 			func(params InputParams) bool {
-				// checks if deploy stanza exists
+				// checks if manifests stanza exists
 				linter := &YamlFieldLinter{}
 				recs, err := linter.Lint(params, &[]Rule{
 					{
 						RuleType: YamlFieldLintRule,
 						Filter: YamlFieldFilter{
-							Filter: yaml.Lookup("deploy"),
+							Filter: yaml.Lookup("manifests"),
 						},
 					},
 				})
@@ -106,10 +106,7 @@ var skaffoldYamlLintRules = []Rule{
 		ExplanationPopulator: func(lintInputs InputParams) (explanationInfo, error) {
 			fieldMap := map[string]interface{}{}
 			forwardedPorts := util.PortSet{}
-			if lintInputs.SkaffoldConfig.Deploy.KubectlDeploy == nil {
-				return explanationInfo{}, fmt.Errorf("expected kubectl deploy information to be populated but it was nil")
-			}
-			for _, pattern := range lintInputs.SkaffoldConfig.Deploy.KubectlDeploy.Manifests {
+			for _, pattern := range lintInputs.SkaffoldConfig.Render.Generate.RawK8s {
 				// NOTE: pattern is a pattern that can have wildcards, eg: leeroy-app/kubernetes/*
 				if util.IsURL(pattern) {
 					log.Entry(context.TODO()).Infof("skaffold lint found url manifest when processing rule %d and is skipping lint rules for: %s", SkaffoldYamlUseStaticPort, pattern)
diff --git a/pkg/skaffold/render/generate/generate.go b/pkg/skaffold/render/generate/generate.go
index c4a58025a..2b6e179da 100644
--- a/pkg/skaffold/render/generate/generate.go
+++ b/pkg/skaffold/render/generate/generate.go
@@ -34,7 +34,6 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/kptfile"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/stringset"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/stringslice"
 )
 
@@ -53,6 +52,19 @@ type Generator struct {
 	config       latest.Generate
 }
 
+func localManifests(paths []string, workdir string) ([]string, error) {
+	var localPaths []string
+	for _, path := range paths {
+		switch {
+		case util.IsURL(path):
+		case strings.HasPrefix(path, "gs://"):
+		default:
+			localPaths = append(localPaths, path)
+		}
+	}
+	return util.ExpandPathsGlob(workdir, localPaths)
+}
+
 func resolveRemoteAndLocal(paths []string, workdir string) ([]string, error) {
 	var localPaths []string
 	var gcsManifests []string
@@ -259,34 +271,31 @@ func isKptDir(path string) (string, bool) {
 	return dir, true
 }
 
-// walkManifests finds out all the manifests from the `.manifests.generate`, so they can be registered in the file watcher.
+// walkLocalManifests finds out all the manifests from the `.manifests.generate`, so they can be registered in the file watcher.
 // Note: the logic about manifest dependencies shall separate from the "Generate" function, which requires "context" and
 // only be called when a rendering action is needed (normally happens after the file watcher registration).
-func (g Generator) walkManifests() ([]string, error) {
+func (g Generator) walkLocalManifests() ([]string, error) {
 	var dependencyPaths []string
 
 	// Generate kustomize Manifests
 	if g.config.Kustomize != nil {
-		kustomizePaths, err := resolveRemoteAndLocal(g.config.Kustomize.Paths, g.workingDir)
+		kustomizePaths, err := localManifests(g.config.Kustomize.Paths, g.workingDir)
 		if err != nil {
-			event.DeployInfoEvent(fmt.Errorf("could not expand the glob kustomize manifests: %w", err))
 			return nil, err
 		}
 		dependencyPaths = append(dependencyPaths, kustomizePaths...)
 	}
 
 	// Generate in-place hydrated kpt Manifests
-	kptPaths, err := resolveRemoteAndLocal(g.config.Kpt, g.workingDir)
+	kptPaths, err := localManifests(g.config.Kpt, g.workingDir)
 	if err != nil {
-		event.DeployInfoEvent(fmt.Errorf("could not expand the glob kpt manifests: %w", err))
 		return nil, err
 	}
 	dependencyPaths = append(dependencyPaths, kptPaths...)
 
 	// Generate Raw Manifests
-	sourceManifests, err := resolveRemoteAndLocal(g.config.RawK8s, g.workingDir)
+	sourceManifests, err := localManifests(g.config.RawK8s, g.workingDir)
 	if err != nil {
-		event.DeployInfoEvent(fmt.Errorf("could not expand the glob raw manifests: %w", err))
 		return nil, err
 	}
 	dependencyPaths = append(dependencyPaths, sourceManifests...)
@@ -294,9 +303,9 @@ func (g Generator) walkManifests() ([]string, error) {
 }
 
 func (g Generator) ManifestDeps() ([]string, error) {
-	deps := stringset.New()
+	deps := []string{}
 
-	dependencyPaths, err := g.walkManifests()
+	dependencyPaths, err := g.walkLocalManifests()
 	if err != nil {
 		return nil, err
 	}
@@ -308,7 +317,7 @@ func (g Generator) ManifestDeps() ([]string, error) {
 				}
 				fname := filepath.Base(p)
 				if strings.HasSuffix(fname, ".yaml") || strings.HasSuffix(fname, ".yml") || fname == kptfile.KptFileName {
-					deps.Insert(p)
+					deps = append(deps, p)
 				}
 				return nil
 			})
@@ -316,5 +325,5 @@ func (g Generator) ManifestDeps() ([]string, error) {
 			return nil, err
 		}
 	}
-	return deps.ToList(), nil
+	return deps, nil
 }
diff --git a/pkg/skaffold/render/renderer/noop/noop.go b/pkg/skaffold/render/renderer/noop/noop.go
index 661b3ebf3..377d1f86d 100644
--- a/pkg/skaffold/render/renderer/noop/noop.go
+++ b/pkg/skaffold/render/renderer/noop/noop.go
@@ -30,8 +30,8 @@ import (
 // TODO(marlongamez): add Helm renderer which uses helm template and can feed into deployers
 type Noop struct{}
 
-func New(_ latest.RenderConfig, _, _ string, _ map[string]string) (Noop, error) {
-	return Noop{}, nil
+func New(_ latest.RenderConfig, _, _ string, _ map[string]string) Noop {
+	return Noop{}
 }
 
 func (r Noop) Render(ctx context.Context, out io.Writer, artifacts []graph.Artifact, offline bool) (manifest.ManifestListByConfig, error) {
diff --git a/pkg/skaffold/render/renderer/render_mux.go b/pkg/skaffold/render/renderer/render_mux.go
index 8b1eb3ebd..c3d55f6e7 100644
--- a/pkg/skaffold/render/renderer/render_mux.go
+++ b/pkg/skaffold/render/renderer/render_mux.go
@@ -30,14 +30,17 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/stringset"
 )
 
+// GroupRenderer maintains the slice of all `Renderer`s defined in a single Skaffold config.
+type GroupRenderer []Renderer
+
 // RenderMux forwards all method calls to the renderers it contains.
 // When encountering an error, it aborts and returns the error. Otherwise,
 // it collects the results and returns all the manifests.
 type RenderMux struct {
-	renderers []Renderer
+	renderers GroupRenderer
 }
 
-func NewRenderMux(renderers []Renderer) Renderer {
+func NewRenderMux(renderers GroupRenderer) Renderer {
 	return RenderMux{renderers: renderers}
 }
 
diff --git a/pkg/skaffold/render/renderer/renderer.go b/pkg/skaffold/render/renderer/renderer.go
index ceaaffd20..720c2b602 100644
--- a/pkg/skaffold/render/renderer/renderer.go
+++ b/pkg/skaffold/render/renderer/renderer.go
@@ -39,18 +39,34 @@ type Renderer interface {
 }
 
 // New creates a new Renderer object from the latestV2 API schema.
-func New(cfg render.Config, renderCfg latest.RenderConfig, hydrationDir string, labels map[string]string, usingLegacyHelmDeploy bool, command string, configName string) (Renderer, error) {
+func New(ctx context.Context, cfg render.Config, renderCfg latest.RenderConfig, hydrationDir string, labels map[string]string, usingLegacyHelmDeploy bool, command string, configName string) (GroupRenderer, error) {
 	if usingLegacyHelmDeploy && command != "render" {
-		return noop.New(renderCfg, cfg.GetWorkingDir(), hydrationDir, labels)
+		return GroupRenderer{noop.New(renderCfg, cfg.GetWorkingDir(), hydrationDir, labels)}, nil
 	}
-	if renderCfg.Validate == nil && renderCfg.Transform == nil && renderCfg.Helm != nil {
-		log.Entry(context.TODO()).Debug("setting up helm renderer")
-		return helm.New(cfg, renderCfg, labels, configName)
+	if renderCfg.Validate != nil || renderCfg.Transform != nil || renderCfg.Kpt != nil {
+		r, err := kpt.New(cfg, renderCfg, hydrationDir, labels, configName)
+		if err != nil {
+			return nil, err
+		}
+		log.Entry(context.TODO()).Infof("setting up kpt renderer")
+		return []Renderer{r}, nil
 	}
-	if renderCfg.Validate == nil && renderCfg.Transform == nil && renderCfg.Kpt == nil {
-		log.Entry(context.TODO()).Debug("setting up kubectl renderer")
-		return kubectl.New(cfg, renderCfg, labels, configName)
+
+	var rs GroupRenderer
+
+	if renderCfg.RawK8s != nil || renderCfg.Kustomize != nil {
+		r, err := kubectl.New(cfg, renderCfg, labels, configName)
+		if err != nil {
+			return nil, err
+		}
+		rs = append(rs, r)
+	}
+	if renderCfg.Helm != nil {
+		r, err := helm.New(cfg, renderCfg, labels, configName)
+		if err != nil {
+			return nil, err
+		}
+		rs = append(rs, r)
 	}
-	log.Entry(context.TODO()).Infof("setting up kpt renderer")
-	return kpt.New(cfg, renderCfg, hydrationDir, labels, configName)
+	return rs, nil
 }
diff --git a/pkg/skaffold/runner/deployer.go b/pkg/skaffold/runner/deployer.go
index f1f41ab64..fef9fca4d 100644
--- a/pkg/skaffold/runner/deployer.go
+++ b/pkg/skaffold/runner/deployer.go
@@ -99,7 +99,7 @@ func GetDeployer(ctx context.Context, runCtx *runcontext.RunContext, labeller *l
 				return nil, errors.New("skaffold apply called with both Cloud Run and Kubernetes deployers. Mixing deployment targets is not allowed" +
 					" when using the Cloud Run deployer")
 			}
-			return getCloudRunDeployer(runCtx, labeller)
+			return getCloudRunDeployer(runCtx, labeller, pipelines.Deployers(), "")
 		}
 		if len(helmNamespaces) > 1 || (nonHelmDeployFound && len(helmNamespaces) == 1) {
 			return nil, errors.New("skaffold apply called with conflicting namespaces set via skaffold.yaml. This is likely due to the use of the 'deploy.helm.releases.*.namespace' field which is not supported in apply.  Remove the 'deploy.helm.releases.*.namespace' field(s) and run skaffold apply again")
@@ -185,7 +185,7 @@ func GetDeployer(ctx context.Context, runCtx *runcontext.RunContext, labeller *l
 			deployers = append(deployers, deployer)
 		}
 		if d.CloudRunDeploy != nil {
-			deployer, err := cloudrun.NewDeployer(dCtx, labeller, d.CloudRunDeploy, configName)
+			deployer, err := getCloudRunDeployer(dCtx.RunContext, labeller, runCtx.DeployConfigs(), configName)
 			if err != nil {
 				return nil, err
 			}
@@ -312,21 +312,38 @@ func validateKubectlFlags(flags *latest.KubectlFlags, additional latest.KubectlF
 }
 
 /* The Cloud Run deployer for apply. Used when Cloud Run is specified. */
-func getCloudRunDeployer(runCtx *runcontext.RunContext, labeller *label.DefaultLabeller) (*cloudrun.Deployer, error) {
+func getCloudRunDeployer(runCtx *runcontext.RunContext, labeller *label.DefaultLabeller, deployers []latest.DeployConfig, configName string) (*cloudrun.Deployer, error) {
 	var region string
+	regionFlag := false
 	var defaultProject string
-	for _, d := range runCtx.DeployConfigs() {
+	projectFlag := false
+	if runCtx.Opts.CloudRunLocation != "" {
+		region = runCtx.Opts.CloudRunLocation
+		regionFlag = true
+	}
+	if runCtx.Opts.CloudRunProject != "" {
+		defaultProject = runCtx.Opts.CloudRunProject
+		projectFlag = true
+	}
+	for _, d := range deployers {
 		if d.CloudRunDeploy != nil {
 			crDeploy := d.CloudRunDeploy
-			if region != "" && region != crDeploy.Region {
-				return nil, fmt.Errorf("expected all Cloud Run deploys to be in the same region, found deploys to %s and %s", region, crDeploy.Region)
+			if !regionFlag {
+				// No region flag was provided, so take it from the config.
+				if region != "" && region != crDeploy.Region {
+					return nil, fmt.Errorf("expected all Cloud Run deploys to be in the same region, found deploys to %s and %s", region, crDeploy.Region)
+				}
+
+				region = crDeploy.Region
 			}
-			region = crDeploy.Region
-			if defaultProject != "" && defaultProject != crDeploy.ProjectID {
-				return nil, fmt.Errorf("expected all Cloud Run deploys to use the same project, found deploys to projects %s and %s", defaultProject, crDeploy.ProjectID)
+			if !projectFlag {
+				// No project flag was specified so take it from the config.
+				if defaultProject != "" && defaultProject != crDeploy.ProjectID {
+					return nil, fmt.Errorf("expected all Cloud Run deploys to use the same project, found deploys to projects %s and %s", defaultProject, crDeploy.ProjectID)
+				}
+				defaultProject = crDeploy.ProjectID
 			}
-			defaultProject = crDeploy.ProjectID
 		}
 	}
-	return cloudrun.NewDeployer(runCtx, labeller, &latest.CloudRunDeploy{Region: region, ProjectID: defaultProject}, "")
+	return cloudrun.NewDeployer(runCtx, labeller, &latest.CloudRunDeploy{Region: region, ProjectID: defaultProject}, configName)
 }
diff --git a/pkg/skaffold/runner/renderer.go b/pkg/skaffold/runner/renderer.go
index 20b23a269..3ff54bccf 100644
--- a/pkg/skaffold/runner/renderer.go
+++ b/pkg/skaffold/runner/renderer.go
@@ -27,13 +27,13 @@ import (
 func GetRenderer(ctx context.Context, runCtx *runcontext.RunContext, hydrationDir string, labels map[string]string, usingLegacyHelmDeploy bool) (renderer.Renderer, error) {
 	ps := runCtx.Pipelines.AllByConfigNames()
 
-	var renderers []renderer.Renderer
+	var renderers renderer.GroupRenderer
 	for configName, p := range ps {
-		r, err := renderer.New(runCtx, p.Render, hydrationDir, labels, usingLegacyHelmDeploy, runCtx.Opts.Command, configName)
+		rs, err := renderer.New(ctx, runCtx, p.Render, hydrationDir, labels, usingLegacyHelmDeploy, runCtx.Opts.Command, configName)
 		if err != nil {
 			return nil, err
 		}
-		renderers = append(renderers, r)
+		renderers = append(renderers, rs...)
 	}
 	return renderer.NewRenderMux(renderers), nil
 }
diff --git a/pkg/skaffold/runner/runner.go b/pkg/skaffold/runner/runner.go
index 7c9296f64..a9a1d89fe 100644
--- a/pkg/skaffold/runner/runner.go
+++ b/pkg/skaffold/runner/runner.go
@@ -42,7 +42,7 @@ type Runner interface {
 	DeployAndLog(context.Context, io.Writer, []graph.Artifact, manifest.ManifestListByConfig) error
 	GeneratePipeline(context.Context, io.Writer, []util.VersionedConfig, []string, string) error
 	HasBuilt() bool
-	HasDeployed() bool
+	DeployManifests() manifest.ManifestListByConfig
 	Prune(context.Context, io.Writer) error
 
 	Render(ctx context.Context, out io.Writer, builds []graph.Artifact, offline bool) (manifest.ManifestListByConfig, error)
diff --git a/pkg/skaffold/runner/v2/apply.go b/pkg/skaffold/runner/v2/apply.go
index 9549a73d3..6d3746382 100644
--- a/pkg/skaffold/runner/v2/apply.go
+++ b/pkg/skaffold/runner/v2/apply.go
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
+
 package v2
 
 import (
@@ -68,7 +69,7 @@ func (r *SkaffoldRunner) applyResources(ctx context.Context, out io.Writer, arti
 		endTrace(instrumentation.TraceEndError(err))
 		return err
 	}
-	r.hasDeployed = true
+	r.deployManifests = list
 	event.DeployComplete()
 	return nil
 }
diff --git a/pkg/skaffold/runner/v2/cleanup.go b/pkg/skaffold/runner/v2/cleanup.go
index 7210c9a38..264855667 100644
--- a/pkg/skaffold/runner/v2/cleanup.go
+++ b/pkg/skaffold/runner/v2/cleanup.go
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
+
 package v2
 
 import (
diff --git a/pkg/skaffold/runner/v2/deploy.go b/pkg/skaffold/runner/v2/deploy.go
index d8698d67e..1e5edfe31 100644
--- a/pkg/skaffold/runner/v2/deploy.go
+++ b/pkg/skaffold/runner/v2/deploy.go
@@ -110,7 +110,7 @@ See https://skaffold.dev/docs/pipeline-stages/taggers/#how-tagging-works`)
 
 	r.deployer.RegisterLocalImages(localAndBuiltImages)
 	err = r.deployer.Deploy(ctx, deployOut, artifacts, list)
-	r.hasDeployed = true // set even if deploy may have failed, because we want to cleanup any partially created resources
+	r.deployManifests = list // set even if deploy may have failed, because we want to cleanup any partially created resources
 	postDeployFn()
 	if err != nil {
 		event.DeployFailed(err)
diff --git a/pkg/skaffold/runner/v2/dev.go b/pkg/skaffold/runner/v2/dev.go
index 9fa2e26ac..37985d2a0 100644
--- a/pkg/skaffold/runner/v2/dev.go
+++ b/pkg/skaffold/runner/v2/dev.go
@@ -186,6 +186,7 @@ func (r *SkaffoldRunner) doDev(ctx context.Context, out io.Writer) error {
 			endTrace(instrumentation.TraceEndError(err))
 			return nil
 		}
+		r.deployManifests = manifests
 
 		if err := r.Deploy(childCtx, out, r.Builds, manifests); err != nil {
 			log.Entry(ctx).Warn("Skipping deploy due to error:", err)
@@ -348,6 +349,7 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la
 
 	// First render
 	manifests, err := r.Render(ctx, out, r.Builds, true)
+	r.deployManifests = manifests
 	if err != nil {
 		event.DevLoopFailedInPhase(r.devIteration, constants.Render, err)
 		eventV2.TaskFailed(constants.DevLoop, err)
diff --git a/pkg/skaffold/runner/v2/render.go b/pkg/skaffold/runner/v2/render.go
index 0eed61d18..f3b222d8e 100644
--- a/pkg/skaffold/runner/v2/render.go
+++ b/pkg/skaffold/runner/v2/render.go
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
+
 package v2
 
 import (
diff --git a/pkg/skaffold/runner/v2/runner.go b/pkg/skaffold/runner/v2/runner.go
index 5cd7b7ce8..89a5a8833 100644
--- a/pkg/skaffold/runner/v2/runner.go
+++ b/pkg/skaffold/runner/v2/runner.go
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
+
 package v2
 
 import (
@@ -22,6 +23,7 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy/label"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/filemon"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/manifest"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/render/renderer"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
@@ -50,13 +52,13 @@ type SkaffoldRunner struct {
 	sourceDependencies graph.SourceDependenciesCache
 	platforms          platform.Resolver
 
-	devIteration int
-	isLocalImage func(imageName string) (bool, error)
-	hasDeployed  bool
-	intents      *runner.Intents
+	devIteration    int
+	isLocalImage    func(imageName string) (bool, error)
+	deployManifests manifest.ManifestListByConfig
+	intents         *runner.Intents
 }
 
-// HasDeployed returns true if this runner has deployed something.
-func (r *SkaffoldRunner) HasDeployed() bool {
-	return r.hasDeployed
+// DeployManifests returns a list of manifest if this runner has deployed something.
+func (r *SkaffoldRunner) DeployManifests() manifest.ManifestListByConfig {
+	return r.deployManifests
 }
diff --git a/pkg/skaffold/runner/v2/verify.go b/pkg/skaffold/runner/v2/verify.go
index 2a1ceefac..cb455cce9 100644
--- a/pkg/skaffold/runner/v2/verify.go
+++ b/pkg/skaffold/runner/v2/verify.go
@@ -103,7 +103,6 @@ See https://skaffold.dev/docs/pipeline-stages/taggers/#how-tagging-works`)
 
 	r.verifier.RegisterLocalImages(localAndBuiltImages)
 	err = r.verifier.Verify(ctx, deployOut, artifacts)
-	r.hasDeployed = true // set even if deploy may have failed, because we want to cleanup any partially created resources
 	postDeployFn()
 	if err != nil {
 		eventV2.TaskFailed(constants.Verify, err)
diff --git a/pkg/skaffold/schema/v2beta29/upgrade.go b/pkg/skaffold/schema/v2beta29/upgrade.go
index c7d7f4d22..3ee98127e 100644
--- a/pkg/skaffold/schema/v2beta29/upgrade.go
+++ b/pkg/skaffold/schema/v2beta29/upgrade.go
@@ -45,7 +45,6 @@ func upgradeOnePipeline(oldPipeline, newPipeline interface{}) error {
 	// Copy kubectl deploy config to render config
 	if oldPL.Deploy.KubectlDeploy != nil {
 		newPL.Render.RawK8s = oldPL.Deploy.KubectlDeploy.Manifests
-		newPL.Deploy.KubectlDeploy.Manifests = nil
 	}
 
 	// Copy kustomize deploy config to render config
@@ -87,6 +86,43 @@ func upgradeOnePipeline(oldPipeline, newPipeline interface{}) error {
 		newPL.Render.Helm.Releases = newHelm.Releases
 		newPL.Render.Helm.Flags = newHelm.Flags
 
+		// Copy over removed artifactOverrides & imageStrategy field as identical setValues fields
+		for i := 0; i < len(newPL.Render.Helm.Releases); i++ {
+			// need to append, not override
+			svs := map[string]string(oldPL.Deploy.HelmDeploy.Releases[i].SetValues)
+			svts := map[string]string(oldPL.Deploy.HelmDeploy.Releases[i].SetValueTemplates)
+			aos := map[string]string(oldPL.Deploy.HelmDeploy.Releases[i].ArtifactOverrides)
+			if aos != nil && svs == nil {
+				svs = map[string]string{}
+			}
+			if oldPL.Deploy.HelmDeploy.Releases[i].ImageStrategy.HelmConventionConfig != nil {
+				// is 'helm' imageStrategy
+				for k, v := range aos {
+					if k == "image" {
+						if svts == nil {
+							svts = map[string]string{}
+						}
+						svts["image.tag"] = "{{.IMAGE_TAG}}@{{.IMAGE_DIGEST}}"
+						svts["image.repository"] = "{{.IMAGE_REPO}}"
+						if oldPL.Deploy.HelmDeploy.Releases[i].ImageStrategy.HelmConventionConfig.ExplicitRegistry {
+							// is 'helm' imageStrategy + explicitRegistry
+							svts["image.registry"] = "{{.IMAGE_DOMAIN}}"
+							svts["image.repository"] = "{{.IMAGE_REPO_NO_DOMAIN}}"
+						}
+						continue
+					}
+					svs[k] = v
+				}
+			} else {
+				// is 'fqn' imageStrategy
+				for k, v := range aos {
+					svs[k] = v
+				}
+			}
+			newPL.Render.Helm.Releases[i].SetValues = svs
+			newPL.Render.Helm.Releases[i].SetValueTemplates = svts
+		}
+
 		// Copy over lifecyle hooks for helm deployer
 		newPL.Deploy.LegacyHelmDeploy = &next.LegacyHelmDeploy{}
 		newPL.Deploy.LegacyHelmDeploy.LifecycleHooks = newHelm.LifecycleHooks
diff --git a/pkg/skaffold/schema/validation/validation.go b/pkg/skaffold/schema/validation/validation.go
index bd583d66b..b70e3a4c5 100644
--- a/pkg/skaffold/schema/validation/validation.go
+++ b/pkg/skaffold/schema/validation/validation.go
@@ -760,16 +760,13 @@ func validateKubectlManifests(configs parser.SkaffoldConfigSet) (errs []ErrorWit
 		if c.IsRemote {
 			continue
 		}
-		if c.Deploy.KubectlDeploy == nil {
-			continue
-		}
-		if len(c.Deploy.KubectlDeploy.Manifests) == 1 && c.Deploy.KubectlDeploy.Manifests[0] == constants.DefaultKubectlManifests[0] {
+		if len(c.Render.RawK8s) == 1 && c.Render.RawK8s[0] == constants.DefaultKubectlManifests[0] {
 			log.Entry(context.TODO()).Debug("skipping validating `kubectl` deployer manifests since only the default manifest list is defined")
 			continue
 		}
 
 		// validate that manifest files referenced in config exist
-		for _, pattern := range c.Deploy.KubectlDeploy.Manifests {
+		for _, pattern := range c.Render.RawK8s {
 			if util.IsURL(pattern) {
 				continue
 			}
@@ -787,7 +784,7 @@ func validateKubectlManifests(configs parser.SkaffoldConfigSet) (errs []ErrorWit
 				msg := fmt.Sprintf("Manifest file %q referenced in skaffold config could not be found", pattern)
 				errMsg := wrapWithContext(c, ErrorWithLocation{
 					Error:    fmt.Errorf(msg),
-					Location: c.YAMLInfos.Locate(&c.Deploy.KubectlDeploy.Manifests),
+					Location: c.YAMLInfos.Locate(&c.Render.RawK8s),
 				})
 				errs = append(errs, ErrorWithLocation{
 					Error: sErrors.NewError(errMsg[0].Error,
diff --git a/pkg/skaffold/verify/docker/verify.go b/pkg/skaffold/verify/docker/verify.go
index 08ac787fe..cc9cc7ea5 100644
--- a/pkg/skaffold/verify/docker/verify.go
+++ b/pkg/skaffold/verify/docker/verify.go
@@ -30,6 +30,7 @@ import (
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/go-connections/nat"
 	"github.com/fatih/semgroup"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/google/uuid"
 	"github.com/pkg/errors"
 
@@ -145,7 +146,7 @@ func (v *Verifier) Verify(ctx context.Context, out io.Writer, allbuilds []graph.
 			}
 		}
 		if !foundArtifact {
-			err = v.client.Pull(ctx, out, tc.Container.Image)
+			err = v.client.Pull(ctx, out, tc.Container.Image, v1.Platform{})
 			if err != nil {
 				return err
 			}


Test patch:
diff --git a/cmd/skaffold/app/cmd/dev_test.go b/cmd/skaffold/app/cmd/dev_test.go
index 574dcd596..092aa62d6 100644
--- a/cmd/skaffold/app/cmd/dev_test.go
+++ b/cmd/skaffold/app/cmd/dev_test.go
@@ -34,10 +34,9 @@ import (
 type mockDevRunner struct {
 	runner.Runner
 	hasBuilt          bool
-	hasDeployed       bool
 	errDev            error
 	calls             []string
-	manifestsByConfig manifest.ManifestListByConfig
+	deployedManifests manifest.ManifestListByConfig
 }
 
 func (r *mockDevRunner) Dev(context.Context, io.Writer, []*latest.Artifact) error {
@@ -50,9 +49,9 @@ func (r *mockDevRunner) HasBuilt() bool {
 	return r.hasBuilt
 }
 
-func (r *mockDevRunner) HasDeployed() bool {
-	r.calls = append(r.calls, "HasDeployed")
-	return r.hasDeployed
+func (r *mockDevRunner) DeployManifests() manifest.ManifestListByConfig {
+	r.calls = append(r.calls, "DeployManifests")
+	return r.deployedManifests
 }
 
 func (r *mockDevRunner) Prune(context.Context, io.Writer) error {
@@ -67,42 +66,44 @@ func (r *mockDevRunner) Cleanup(context.Context, io.Writer, bool, manifest.Manif
 
 func (r *mockDevRunner) Render(ctx context.Context, out io.Writer, builds []graph.Artifact, offline bool) (manifest.ManifestListByConfig, error) {
 	r.calls = append(r.calls, "Render")
-	return r.manifestsByConfig, nil
+	return r.deployedManifests, nil
 }
 
 func TestDoDev(t *testing.T) {
 	tests := []struct {
-		description   string
-		hasBuilt      bool
-		hasDeployed   bool
-		expectedCalls []string
+		description       string
+		hasBuilt          bool
+		deployedManifests manifest.ManifestList
+		expectedCalls     []string
 	}{
 		{
-			description:   "cleanup and then prune",
-			hasBuilt:      true,
-			hasDeployed:   true,
-			expectedCalls: []string{"Dev", "HasDeployed", "HasBuilt", "Render", "Cleanup", "Prune"},
+			description:       "cleanup and then prune",
+			hasBuilt:          true,
+			deployedManifests: manifest.ManifestList{[]byte("dummy")},
+			expectedCalls:     []string{"Dev", "DeployManifests", "HasBuilt", "Render", "Cleanup", "Prune"},
 		},
 		{
-			description:   "hasn't deployed",
-			hasBuilt:      true,
-			hasDeployed:   false,
-			expectedCalls: []string{"Dev", "HasDeployed", "HasBuilt", "Prune"},
+			description:       "hasn't deployed",
+			hasBuilt:          true,
+			deployedManifests: manifest.ManifestList{},
+			expectedCalls:     []string{"Dev", "DeployManifests", "HasBuilt", "Prune"},
 		},
 		{
-			description:   "hasn't built",
-			hasBuilt:      false,
-			hasDeployed:   false,
-			expectedCalls: []string{"Dev", "HasDeployed", "HasBuilt"},
+			description:       "hasn't built",
+			hasBuilt:          false,
+			deployedManifests: manifest.ManifestList{},
+			expectedCalls:     []string{"Dev", "DeployManifests", "HasBuilt"},
 		},
 	}
 
 	for _, test := range tests {
 		testutil.Run(t, test.description, func(t *testutil.T) {
+			dm := manifest.NewManifestListByConfig()
+			dm.Add("test", test.deployedManifests)
 			mockRunner := &mockDevRunner{
-				hasBuilt:    test.hasBuilt,
-				hasDeployed: test.hasDeployed,
-				errDev:      context.Canceled,
+				hasBuilt:          test.hasBuilt,
+				deployedManifests: dm,
+				errDev:            context.Canceled,
 			}
 			t.Override(&createRunner, func(context.Context, io.Writer, config.SkaffoldOptions) (runner.Runner, []util.VersionedConfig, *runcontext.RunContext, error) {
 				return mockRunner, []util.VersionedConfig{&latest.SkaffoldConfig{}}, nil, nil
@@ -138,8 +139,8 @@ func (m *mockConfigChangeRunner) HasBuilt() bool {
 	return true
 }
 
-func (m *mockConfigChangeRunner) HasDeployed() bool {
-	return true
+func (m *mockConfigChangeRunner) DeployManifests() manifest.ManifestListByConfig {
+	return manifest.ManifestListByConfig{}
 }
 
 func (m *mockConfigChangeRunner) Prune(context.Context, io.Writer) error {
diff --git a/cmd/skaffold/app/cmd/fix_test.go b/cmd/skaffold/app/cmd/fix_test.go
index 81be22481..c274fc0d0 100644
--- a/cmd/skaffold/app/cmd/fix_test.go
+++ b/cmd/skaffold/app/cmd/fix_test.go
@@ -24,7 +24,6 @@ import (
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	v1 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1"
-	latestV1 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v2beta28"
 	"github.com/GoogleContainerTools/skaffold/testutil"
 )
 
@@ -38,7 +37,7 @@ func TestFix(t *testing.T) {
 	}{
 		{
 			description:   "v1alpha4 to latest",
-			targetVersion: latestV1.Version,
+			targetVersion: latest.Version,
 			inputYaml: `apiVersion: skaffold/v1alpha4
 kind: Config
 build:
@@ -66,15 +65,16 @@ test:
 - image: docker/image
   structureTests:
   - ./test/*
+manifests:
+  rawYaml:
+  - k8s/deployment.yaml
 deploy:
-  kubectl:
-    manifests:
-    - k8s/deployment.yaml
-`, latestV1.Version),
+  kubectl: {}
+`, latest.Version),
 		},
 		{
 			description:   "v1alpha1 to latest",
-			targetVersion: latestV1.Version,
+			targetVersion: latest.Version,
 			inputYaml: `apiVersion: skaffold/v1alpha1
 kind: Config
 build:
@@ -94,11 +94,12 @@ build:
   - image: docker/image
     docker:
       dockerfile: dockerfile.test
+manifests:
+  rawYaml:
+  - k8s/deployment.yaml
 deploy:
-  kubectl:
-    manifests:
-    - k8s/deployment.yaml
-`, latestV1.Version),
+  kubectl: {}
+`, latest.Version),
 		},
 		{
 			description:   "v1alpha1 to v1",
@@ -194,17 +195,18 @@ test:
 - image: docker/image
   structureTests:
   - ./test/*
+manifests:
+  rawYaml:
+  - k8s/deployment.yaml
 deploy:
-  kubectl:
-    manifests:
-    - k8s/deployment.yaml
-`, latestV1.Version)
+  kubectl: {}
+`, latest.Version)
 
 	testutil.Run(t, "", func(t *testutil.T) {
 		cfgFile := t.TempFile("config", []byte(inputYaml))
 
 		var b bytes.Buffer
-		err := fix(&b, cfgFile, cfgFile, latestV1.Version)
+		err := fix(&b, cfgFile, cfgFile, latest.Version)
 
 		output, _ := os.ReadFile(cfgFile)
 
diff --git a/cmd/skaffold/app/cmd/schema/list_test.go b/cmd/skaffold/app/cmd/schema/list_test.go
index 1a780cb5f..007ff2595 100644
--- a/cmd/skaffold/app/cmd/schema/list_test.go
+++ b/cmd/skaffold/app/cmd/schema/list_test.go
@@ -22,7 +22,7 @@ import (
 	"strings"
 	"testing"
 
-	latestV1 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v2beta29"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	"github.com/GoogleContainerTools/skaffold/testutil"
 )
 
@@ -34,7 +34,7 @@ func TestListPlain(t *testing.T) {
 		t.CheckNoError(err)
 
 		versions := out.String()
-		t.CheckTrue(strings.HasSuffix(versions, latestV1.Version+"\n"))
+		t.CheckTrue(strings.HasSuffix(versions, latest.Version+"\n"))
 		t.CheckTrue(strings.HasPrefix(versions, `skaffold/v1alpha1
 skaffold/v1alpha2
 skaffold/v1alpha3
@@ -71,7 +71,7 @@ func TestListJson(t *testing.T) {
 
 		versions := out.String()
 		t.CheckTrue(strings.HasPrefix(versions, `{"versions":["skaffold/v1alpha1","skaffold/v1alpha2",`))
-		t.CheckTrue(strings.HasSuffix(versions, fmt.Sprintf(",\"%s\"]}\n", latestV1.Version)))
+		t.CheckTrue(strings.HasSuffix(versions, fmt.Sprintf(",\"%s\"]}\n", latest.Version)))
 	})
 }
 
diff --git a/integration/run_test.go b/integration/run_test.go
index 5e99a8542..fd3f7e156 100644
--- a/integration/run_test.go
+++ b/integration/run_test.go
@@ -154,6 +154,11 @@ var tests = []struct {
 		deployments: []string{"skaffold-helm"},
 		targetLog:   "Hello world!",
 	},
+	{
+		description: "multiple renderers mixed in",
+		dir:         "examples/multiple-renderers",
+		deployments: []string{"frontend", "backend", "go-guestbook-mongodb"},
+	},
 }
 
 func TestRun(t *testing.T) {
diff --git a/integration/testdata/deploy-multiple/skaffold.yaml b/integration/testdata/deploy-multiple/skaffold.yaml
index 876d3a9b9..c16741cbc 100644
--- a/integration/testdata/deploy-multiple/skaffold.yaml
+++ b/integration/testdata/deploy-multiple/skaffold.yaml
@@ -11,10 +11,4 @@ manifests:
     paths:
       - ./kustomize
 deploy:
-  kustomize:
-    paths:
-    - ./kustomize
-
-  kubectl:
-    manifests:
-      - kubectl/k8s-pod.yaml
+  kubectl: {}
diff --git a/integration/testdata/diagnose/multi-config/diagnose.tmpl b/integration/testdata/diagnose/multi-config/diagnose.tmpl
index 25a6a8b69..393b8ea2f 100644
--- a/integration/testdata/diagnose/multi-config/diagnose.tmpl
+++ b/integration/testdata/diagnose/multi-config/diagnose.tmpl
@@ -12,10 +12,10 @@ build:
     gitCommit: {}
   local:
     concurrency: 1
+manifests:
+  rawYaml:
+  - /k8s/*
 deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
   logs:
     prefix: container
 ---
@@ -33,10 +33,10 @@ build:
     gitCommit: {}
   local:
     concurrency: 1
+manifests:
+  rawYaml:
+  - /k8s/*
 deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
   logs:
     prefix: container
 ---
@@ -52,9 +52,9 @@ build:
     gitCommit: {}
   local:
     concurrency: 1
+manifests:
+  rawYaml:
+  - /k8s/*
 deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
   logs:
     prefix: container
diff --git a/integration/testdata/diagnose/multi-config/skaffold.yaml b/integration/testdata/diagnose/multi-config/skaffold.yaml
index 155c77c42..f3cbb07ab 100644
--- a/integration/testdata/diagnose/multi-config/skaffold.yaml
+++ b/integration/testdata/diagnose/multi-config/skaffold.yaml
@@ -7,7 +7,6 @@ build:
   artifacts:
   - image: app1
     context: foo
-deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
+manifests:
+  rawYaml:
+  - /k8s/*
diff --git a/integration/testdata/diagnose/multi-config/skaffold2.yaml b/integration/testdata/diagnose/multi-config/skaffold2.yaml
index 9933935c0..de0c0fb4e 100644
--- a/integration/testdata/diagnose/multi-config/skaffold2.yaml
+++ b/integration/testdata/diagnose/multi-config/skaffold2.yaml
@@ -6,7 +6,6 @@ build:
   artifacts:
   - image: app2
     context: foo2
-deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
+manifests:
+  rawYaml:
+  - /k8s/*
diff --git a/integration/testdata/diagnose/multi-config/skaffold3.yaml b/integration/testdata/diagnose/multi-config/skaffold3.yaml
index fd0cf6228..6cbb1efd7 100644
--- a/integration/testdata/diagnose/multi-config/skaffold3.yaml
+++ b/integration/testdata/diagnose/multi-config/skaffold3.yaml
@@ -6,7 +6,6 @@ build:
   artifacts:
   - image: app3
     context: foo3
-deploy:
-  kubectl:
-    manifests:
-    - /k8s/*
+manifests:
+  rawYaml:
+  - /k8s/*
diff --git a/integration/testdata/diagnose/temp-config/diagnose.tmpl b/integration/testdata/diagnose/temp-config/diagnose.tmpl
index 9603c0134..d21a5de8d 100644
--- a/integration/testdata/diagnose/temp-config/diagnose.tmpl
+++ b/integration/testdata/diagnose/temp-config/diagnose.tmpl
@@ -10,9 +10,9 @@ build:
     gitCommit: {}
   local:
     concurrency: 1
+manifests:
+  rawYaml:
+  - {{.Root}}/k8s-*
 deploy:
-  kubectl:
-    manifests:
-    - {{.Root}}/k8s-*
   logs:
     prefix: container
diff --git a/integration/testdata/diagnose/temp-config/skaffold.yaml b/integration/testdata/diagnose/temp-config/skaffold.yaml
index 1a671577a..adea0d850 100644
--- a/integration/testdata/diagnose/temp-config/skaffold.yaml
+++ b/integration/testdata/diagnose/temp-config/skaffold.yaml
@@ -3,7 +3,6 @@ kind: Config
 build:
   artifacts:
   - image: skaffold-example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/testdata/hello/skaffold.yaml b/integration/testdata/hello/skaffold.yaml
index bc5ed7168..61676b444 100644
--- a/integration/testdata/hello/skaffold.yaml
+++ b/integration/testdata/hello/skaffold.yaml
@@ -6,12 +6,10 @@ build:
 
 profiles:
   - name: pod
-    deploy:
-      kubectl:
-        manifests:
-          - k8s/pod.yaml
+    manifests:
+      rawYaml:
+      - k8s/pod.yaml
   - name: deployment
-    deploy:
-      kubectl:
-        manifests:
-          - k8s/deployment.yaml
\ No newline at end of file
+    manifests:
+      rawYaml:
+      - k8s/deployment.yaml
\ No newline at end of file
diff --git a/integration/testdata/init/compose/skaffold.yaml b/integration/testdata/init/compose/skaffold.yaml
index 56baeac11..ffff330d7 100644
--- a/integration/testdata/init/compose/skaffold.yaml
+++ b/integration/testdata/init/compose/skaffold.yaml
@@ -7,8 +7,7 @@ build:
   - image: gcr.io/k8s-skaffold/compose
     docker:
       dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
-    - compose-deployment.yaml
-    - compose-service.yaml
+manifests:
+  rawYaml:
+  - compose-deployment.yaml
+  - compose-service.yaml
diff --git a/integration/testdata/init/hello-with-manifest/skaffold.yaml b/integration/testdata/init/hello-with-manifest/skaffold.yaml
index 01e4b15e8..a48d540d6 100644
--- a/integration/testdata/init/hello-with-manifest/skaffold.yaml
+++ b/integration/testdata/init/hello-with-manifest/skaffold.yaml
@@ -8,7 +8,6 @@ build:
     context: ../hello
     docker:
       dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
-    - k8s-pod.yaml
+manifests:
+  rawYaml:
+  - k8s-pod.yaml
diff --git a/integration/testdata/kaniko-insecure-registry/app/skaffold.yaml b/integration/testdata/kaniko-insecure-registry/app/skaffold.yaml
index ecca87e44..adea0d850 100644
--- a/integration/testdata/kaniko-insecure-registry/app/skaffold.yaml
+++ b/integration/testdata/kaniko-insecure-registry/app/skaffold.yaml
@@ -3,7 +3,6 @@ kind: Config
 build:
   artifacts:
   - image: skaffold-example
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/testdata/kaniko-insecure-registry/skaffold.yaml b/integration/testdata/kaniko-insecure-registry/skaffold.yaml
index cdf2ac937..19328c104 100644
--- a/integration/testdata/kaniko-insecure-registry/skaffold.yaml
+++ b/integration/testdata/kaniko-insecure-registry/skaffold.yaml
@@ -16,7 +16,6 @@ profiles:
         - image: devreg
           context: insecure-registry
           docker: {}
-    deploy:
-      kubectl:
-        manifests:
-          - insecure-registry/reg.yaml
+    manifests:
+      rawYaml:
+      - insecure-registry/reg.yaml
diff --git a/integration/testdata/kaniko-microservices/skaffold.yaml b/integration/testdata/kaniko-microservices/skaffold.yaml
index f1616a84b..fec33135f 100644
--- a/integration/testdata/kaniko-microservices/skaffold.yaml
+++ b/integration/testdata/kaniko-microservices/skaffold.yaml
@@ -23,8 +23,7 @@ build:
         cache: {}
   cluster:
     pullSecretName: e2esecret
-deploy:
-  kubectl:
-    manifests:
-      - ./leeroy-web/kubernetes/*
-      - ./leeroy-app/kubernetes/*
+manifests:
+  rawYaml:
+  - ./leeroy-web/kubernetes/*
+  - ./leeroy-app/kubernetes/*
diff --git a/integration/testdata/kaniko-target/skaffold.yaml b/integration/testdata/kaniko-target/skaffold.yaml
index 265557e6e..267e73ced 100644
--- a/integration/testdata/kaniko-target/skaffold.yaml
+++ b/integration/testdata/kaniko-target/skaffold.yaml
@@ -9,7 +9,6 @@ build:
   cluster:
     pullSecretName: e2esecret
     namespace: default
-deploy:
-  kubectl:
-    manifests:
-      - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
diff --git a/integration/testdata/skaffold-in-cluster/skaffold.yaml b/integration/testdata/skaffold-in-cluster/skaffold.yaml
index 3ff8f97ac..c1b76ec72 100644
--- a/integration/testdata/skaffold-in-cluster/skaffold.yaml
+++ b/integration/testdata/skaffold-in-cluster/skaffold.yaml
@@ -13,7 +13,7 @@ profiles:
         - image: skaffold-in-cluster-builder
           kaniko:
             cache: {}
-    deploy:
+    manifests:
       kustomize:
         path: build-step
   - name: build-target
diff --git a/pkg/skaffold/build/local/local_test.go b/pkg/skaffold/build/local/local_test.go
index 8b12dfc7a..f7f45a920 100644
--- a/pkg/skaffold/build/local/local_test.go
+++ b/pkg/skaffold/build/local/local_test.go
@@ -186,7 +186,7 @@ func TestLocalRun(t *testing.T) {
 			}).Add("pull1", ""),
 			tag:              "gcr.io/test/image:tag",
 			expected:         "gcr.io/test/image:1",
-			expectedWarnings: []string{"cacheFrom image couldn't be pulled: pull1\n"},
+			expectedWarnings: []string{"cacheFrom image \"pull1\" couldn't be pulled for platform \"\"\n"},
 		},
 		{
 			description: "error checking cache-from image",
diff --git a/pkg/skaffold/deploy/kubectl/kubectl_test.go b/pkg/skaffold/deploy/kubectl/kubectl_test.go
index 42baf6fca..917bd270c 100644
--- a/pkg/skaffold/deploy/kubectl/kubectl_test.go
+++ b/pkg/skaffold/deploy/kubectl/kubectl_test.go
@@ -344,56 +344,10 @@ func TestKubectlCleanup(t *testing.T) {
 	}
 }
 
-func TestKubectlDeployerRemoteCleanup(t *testing.T) {
-	tests := []struct {
-		description string
-		kubectl     latest.KubectlDeploy
-		commands    util.Command
-	}{
-		{
-			description: "cleanup success",
-			kubectl: latest.KubectlDeploy{
-				RemoteManifests: []string{"pod/leeroy-web"},
-			},
-			commands: testutil.
-				CmdRun("kubectl --context kubecontext --namespace testNamespace get pod/leeroy-web -o yaml").
-				AndRun("kubectl --context kubecontext --namespace testNamespace delete --ignore-not-found=true --wait=false -f -").
-				AndRunInput("kubectl --context kubecontext --namespace testNamespace apply -f -", DeploymentWebYAML),
-		},
-		{
-			description: "cleanup error",
-			kubectl: latest.KubectlDeploy{
-				RemoteManifests: []string{"anotherNamespace:pod/leeroy-web"},
-			},
-			commands: testutil.
-				CmdRun("kubectl --context kubecontext --namespace anotherNamespace get pod/leeroy-web -o yaml").
-				AndRun("kubectl --context kubecontext --namespace testNamespace delete --ignore-not-found=true --wait=false -f -").
-				AndRunInput("kubectl --context kubecontext --namespace anotherNamespace apply -f -", DeploymentWebYAML),
-		},
-	}
-	for _, test := range tests {
-		testutil.Run(t, "cleanup remote", func(t *testutil.T) {
-			t.Override(&util.DefaultExecCommand, test.commands)
-			tmpDir := t.NewTempDir()
-			tmpDir.Write("deployment.yaml", DeploymentWebYAML).Chdir()
-
-			k, err := NewDeployer(&kubectlConfig{
-				workingDir: ".",
-				RunContext: runcontext.RunContext{Opts: config.SkaffoldOptions{Namespace: TestNamespace}},
-			}, &label.DefaultLabeller{}, &test.kubectl, "default")
-			t.RequireNoError(err)
-
-			err = k.Cleanup(context.Background(), io.Discard, false, manifest.ManifestListByConfig{})
-
-			t.CheckNoError(err)
-		})
-	}
-}
-
 func TestKubectlRedeploy(t *testing.T) {
 	testutil.Run(t, "", func(t *testutil.T) {
 		t.Override(&client.Client, deployutil.MockK8sClient)
-		tmpDir := t.NewTempDir().
+		t.NewTempDir().
 			Write("deployment-web.yaml", DeploymentWebYAML).
 			Write("deployment-app.yaml", DeploymentAppYAML)
 
@@ -410,7 +364,7 @@ func TestKubectlRedeploy(t *testing.T) {
 				Enabled: true,
 				Delay:   0 * time.Millisecond,
 				Max:     10 * time.Second},
-		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{Manifests: []string{tmpDir.Path("deployment-app.yaml"), tmpDir.Path("deployment-web.yaml")}}, configName)
+		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{}, configName)
 		t.RequireNoError(err)
 
 		// Deploy both manifests
@@ -486,7 +440,7 @@ func TestKubectlWaitForDeletions(t *testing.T) {
 				Delay:   0 * time.Millisecond,
 				Max:     10 * time.Second,
 			},
-		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{Manifests: []string{tmpDir.Path("deployment-web.yaml")}}, configName)
+		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{}, configName)
 		t.RequireNoError(err)
 
 		var out bytes.Buffer
@@ -501,9 +455,6 @@ func TestKubectlWaitForDeletions(t *testing.T) {
 		}, manifestListByConfig)
 
 		t.CheckNoError(err)
-		t.CheckDeepEqual(` - 2 resources are marked for deletion, waiting for completion: "leeroy-web", "leeroy-app"
- - "leeroy-web" is marked for deletion, waiting for completion
-`, out.String())
 	})
 }
 
@@ -529,7 +480,7 @@ func TestKubectlWaitForDeletionsFails(t *testing.T) {
 				Delay:   10 * time.Second,
 				Max:     100 * time.Millisecond,
 			},
-		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{Manifests: []string{tmpDir.Path("deployment-web.yaml")}}, configName)
+		}, &label.DefaultLabeller{}, &latest.KubectlDeploy{}, configName)
 		t.RequireNoError(err)
 
 		m, err := manifest.Load(bytes.NewReader([]byte(DeploymentWebYAMLv1)))
@@ -546,67 +497,6 @@ func TestKubectlWaitForDeletionsFails(t *testing.T) {
 	})
 }
 
-func TestDependencies(t *testing.T) {
-	tests := []struct {
-		description string
-		manifests   []string
-		expected    []string
-	}{
-		{
-			description: "no manifest",
-			manifests:   []string(nil),
-			expected:    []string(nil),
-		},
-		{
-			description: "missing manifest file",
-			manifests:   []string{"missing.yaml"},
-			expected:    []string(nil),
-		},
-		{
-			description: "ignore non-manifest",
-			manifests:   []string{"*.ignored"},
-			expected:    []string(nil),
-		},
-		{
-			description: "single manifest",
-			manifests:   []string{"deployment.yaml"},
-			expected:    []string{"deployment.yaml"},
-		},
-		{
-			description: "keep manifests order",
-			manifests:   []string{"01_name.yaml", "00_service.yaml"},
-			expected:    []string{"01_name.yaml", "00_service.yaml"},
-		},
-		{
-			description: "sort children",
-			manifests:   []string{"01/*.yaml", "00/*.yaml"},
-			expected:    []string{filepath.Join("01", "a.yaml"), filepath.Join("01", "b.yaml"), filepath.Join("00", "a.yaml"), filepath.Join("00", "b.yaml")},
-		},
-		{
-			description: "http manifest",
-			manifests:   []string{"deployment.yaml", "http://remote.yaml"},
-			expected:    []string{"deployment.yaml"},
-		},
-	}
-	for _, test := range tests {
-		testutil.Run(t, test.description, func(t *testutil.T) {
-			tmpDir := t.NewTempDir()
-			tmpDir.Touch("deployment.yaml", "01_name.yaml", "00_service.yaml", "empty.ignored").
-				Touch("01/a.yaml", "01/b.yaml").
-				Touch("00/b.yaml", "00/a.yaml").
-				Chdir()
-
-			k, err := NewDeployer(&kubectlConfig{}, &label.DefaultLabeller{}, &latest.KubectlDeploy{Manifests: test.manifests}, "default")
-			t.RequireNoError(err)
-
-			dependencies, err := k.Dependencies()
-
-			t.CheckNoError(err)
-			t.CheckDeepEqual(test.expected, dependencies)
-		})
-	}
-}
-
 func TestGCSManifests(t *testing.T) {
 	tests := []struct {
 		description string
diff --git a/pkg/skaffold/deploy/kustomize/kustomize_test.go b/pkg/skaffold/deploy/kustomize/kustomize_test.go
index f2e3b926e..7c65c3b36 100644
--- a/pkg/skaffold/deploy/kustomize/kustomize_test.go
+++ b/pkg/skaffold/deploy/kustomize/kustomize_test.go
@@ -292,7 +292,7 @@ func TestKustomizeCleanup(t *testing.T) {
 					Namespace: kubectl.TestNamespace}},
 			}, &label.DefaultLabeller{}, &test.kustomize, "default")
 			t.RequireNoError(err)
-			err = k.Cleanup(context.Background(), io.Discard, test.dryRun, manifest.ManifestListByConfig{})
+			err = k.Cleanup(context.Background(), io.Discard, test.dryRun, manifest.NewManifestListByConfig())
 
 			t.CheckError(test.shouldErr, err)
 		})
diff --git a/pkg/skaffold/docker/remote_test.go b/pkg/skaffold/docker/remote_test.go
index 970ac202e..c4cc6b419 100644
--- a/pkg/skaffold/docker/remote_test.go
+++ b/pkg/skaffold/docker/remote_test.go
@@ -90,7 +90,7 @@ func TestRemoteImage(t *testing.T) {
 
 			img, err := getRemoteImage(test.image, &mockConfig{
 				insecureRegistries: test.insecureRegistries,
-			}, nil)
+			}, v1.Platform{})
 
 			t.CheckError(test.shouldErr, err)
 			if !test.shouldErr {
diff --git a/pkg/skaffold/initializer/testdata/init/hello-no-manifest/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/hello-no-manifest/skaffold.yaml
index d0fdcd898..29c20ca35 100644
--- a/pkg/skaffold/initializer/testdata/init/hello-no-manifest/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/hello-no-manifest/skaffold.yaml
@@ -5,7 +5,6 @@ metadata:
 build:
   artifacts:
   - image: skaffold-example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-pod.yaml
+manifests:
+  rawYaml:
+  - k8s-pod.yaml
\ No newline at end of file
diff --git a/pkg/skaffold/kubernetes/manifest/manifests_test.go b/pkg/skaffold/kubernetes/manifest/manifests_test.go
index d23351701..1b1524fa6 100644
--- a/pkg/skaffold/kubernetes/manifest/manifests_test.go
+++ b/pkg/skaffold/kubernetes/manifest/manifests_test.go
@@ -162,3 +162,57 @@ func TestAppendServiceAndRoleBinding(t *testing.T) {
 	testutil.CheckDeepEqual(t, service, string(manifests[1]))
 	testutil.CheckDeepEqual(t, manifests.String(), roleBinding+"\n---\n"+service)
 }
+
+func TestManifestListByConfigAdd(t *testing.T) {
+	tests := []struct {
+		description string
+		mlbc        ManifestListByConfig
+		config      string
+		ml          ManifestList
+		expected    ManifestListByConfig
+	}{
+		{
+			description: "same config name appends to original list",
+			mlbc: ManifestListByConfig{
+				manifests: map[string]ManifestList{
+					"config-a": {[]byte(pod1)},
+				},
+				configNames: []string{"config-a"},
+			},
+			config: "config-a",
+			ml:     ManifestList{[]byte(pod2)},
+			expected: ManifestListByConfig{
+				manifests: map[string]ManifestList{
+					"config-a": {[]byte(pod1), []byte(pod2)},
+				},
+				configNames: []string{"config-a"},
+			},
+		},
+		{
+			description: "different config name appends to original list",
+			mlbc: ManifestListByConfig{
+				manifests: map[string]ManifestList{
+					"config-a": {[]byte(pod1)},
+				},
+				configNames: []string{"config-a"},
+			},
+			config: "config-b",
+			ml:     ManifestList{[]byte(pod2)},
+			expected: ManifestListByConfig{
+				manifests: map[string]ManifestList{
+					"config-a": {[]byte(pod1)},
+					"config-b": {[]byte(pod2)},
+				},
+				configNames: []string{"config-a", "config-b"},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			test.mlbc.Add(test.config, test.ml)
+			t.CheckDeepEqual(test.expected.configNames, test.mlbc.configNames)
+			t.CheckDeepEqual(test.expected.manifests, test.mlbc.manifests)
+		})
+	}
+}
diff --git a/pkg/skaffold/lint/k8smanifests_test.go b/pkg/skaffold/lint/k8smanifests_test.go
index 3307eef51..6b3ef4276 100644
--- a/pkg/skaffold/lint/k8smanifests_test.go
+++ b/pkg/skaffold/lint/k8smanifests_test.go
@@ -142,8 +142,7 @@ func TestGetK8sManifestsLintResults(t *testing.T) {
 				} else {
 					configSet = append(configSet, &parser.SkaffoldConfigEntry{SkaffoldConfig: &latest.SkaffoldConfig{
 						Metadata: latest.Metadata{Name: module},
-						Pipeline: latest.Pipeline{Deploy: latest.DeployConfig{DeployType: latest.DeployType{KubectlDeploy: &latest.KubectlDeploy{Manifests: []string{mp}}}}},
-					},
+						Pipeline: latest.Pipeline{Render: latest.RenderConfig{Generate: latest.Generate{RawK8s: []string{mp}}}}},
 					})
 				}
 
diff --git a/pkg/skaffold/lint/skaffoldyamls_test.go b/pkg/skaffold/lint/skaffoldyamls_test.go
index f56025c4a..5adc89590 100644
--- a/pkg/skaffold/lint/skaffoldyamls_test.go
+++ b/pkg/skaffold/lint/skaffoldyamls_test.go
@@ -45,6 +45,20 @@ deploy:
       - leeroy-app/kubernetes/*
 `
 
+var testSkaffoldYamlV3 = `apiVersion: skaffold/v3alpha1
+kind: Config
+build:
+  artifacts:
+    - image: leeroy-app
+      context: leeroy-app
+      requires:
+        - image: base
+          alias: BASE
+manifests:
+  rawYaml:
+  - leeroy-app/kubernetes/*
+`
+
 var testManifest = `apiVersion: v1
 kind: Service
 metadata:
@@ -148,14 +162,14 @@ func TestGetSkaffoldYamlsLintResults(t *testing.T) {
 		{
 			description:            "verify SkaffoldYamlUseStaticPort rule works as intended",
 			rules:                  []RuleID{SkaffoldYamlUseStaticPort},
-			moduleAndSkaffoldYamls: map[string]string{"cfg0": testSkaffoldYaml},
+			moduleAndSkaffoldYamls: map[string]string{"cfg0": testSkaffoldYamlV3},
 			modules:                []string{"cfg0"},
 			expected: map[string]*[]Result{
 				"cfg0": {
 					{
 						Rule:        ruleIDToskaffoldYamlRule[SkaffoldYamlUseStaticPort],
-						StartLine:   14,
-						EndLine:     15,
+						StartLine:   13,
+						EndLine:     14,
 						StartColumn: 1,
 						EndColumn:   0,
 						Explanation: "It is a skaffold best practice to specify a static port (vs skaffold dynamically choosing one) for port forwarding " +
@@ -205,9 +219,9 @@ func TestGetSkaffoldYamlsLintResults(t *testing.T) {
 				}
 				configSet = append(configSet, &parser.SkaffoldConfigEntry{SkaffoldConfig: &latest.SkaffoldConfig{
 					Metadata: latest.Metadata{Name: module},
-					Pipeline: latest.Pipeline{Deploy: latest.DeployConfig{DeployType: latest.DeployType{KubectlDeploy: &latest.KubectlDeploy{Manifests: []string{
+					Pipeline: latest.Pipeline{Render: latest.RenderConfig{Generate: latest.Generate{RawK8s: []string{
 						mp,
-					}}}}},
+					}}}},
 				},
 					SourceFile: fp,
 				})
diff --git a/pkg/skaffold/parser/config_test.go b/pkg/skaffold/parser/config_test.go
index d0add640f..ff3e47121 100644
--- a/pkg/skaffold/parser/config_test.go
+++ b/pkg/skaffold/parser/config_test.go
@@ -1348,37 +1348,34 @@ kind: Config
 build:
   artifacts:
     - image: app-0
-deploy:
-  kubectl:
-    manifests:
-      - manifests-0
+manifests:
+  rawYaml:
+    - manifests-0
 profiles:
   - name: profile-0
     build:
       artifacts:
         - image: app-0-profile
           context: app-0-profile
-    deploy:
-      kubectl:
-        manifests:
-          - manifests-0-profile
+    manifests:
+      rawYaml:
+      - manifests-0-profile
     patches:
       - op: replace
         path: /build/artifacts/0
         value:
           image: app-0-patch
       - op: add
-        path: /deploy/kubectl/manifests/1
+        path: /manifests/rawYaml/1
         value: 'manifests-1'
   - name: profile-1
     build:
       artifacts:
         - image: app-1-profile
           context: app-1-profile
-    deploy:
-      kubectl:
-        manifests:
-          - manifests-1-profile
+    manifests:
+      rawYaml:
+      - manifests-1-profile
 `
 
 func TestConfigLocationsParse(t *testing.T) {
@@ -1398,9 +1395,8 @@ func TestConfigLocationsParse(t *testing.T) {
 				{kyaml.Lookup("kind")},
 				{kyaml.Lookup("build")},
 				{kyaml.Lookup("build", "artifacts")},
-				{kyaml.Lookup("deploy")},
-				{kyaml.Lookup("deploy", "kubectl")},
-				{kyaml.Lookup("deploy", "kubectl", "manifests")},
+				{kyaml.Lookup("manifests")},
+				{kyaml.Lookup("manifests", "rawYaml")},
 			},
 		},
 		{
@@ -1426,9 +1422,9 @@ func TestConfigLocationsParse(t *testing.T) {
 					kyaml.Lookup("patches"), kyaml.GetElementByIndex(0), kyaml.Lookup("value"), kyaml.Lookup("image")},
 				{kyaml.Lookup("profiles"), kyaml.MatchElementList([]string{"name"}, []string{"profile-0"}),
 					kyaml.Lookup("patches"), kyaml.GetElementByIndex(1), kyaml.Lookup("value")},
-				{kyaml.Lookup("deploy")},
-				{kyaml.Lookup("profiles"), kyaml.MatchElementList([]string{"name"}, []string{"profile-0"}), kyaml.Lookup("deploy"), kyaml.Lookup("kubectl")},
-				{kyaml.Lookup("profiles"), kyaml.MatchElementList([]string{"name"}, []string{"profile-0"}), kyaml.Lookup("deploy"), kyaml.Lookup("kubectl"), kyaml.Lookup("manifests")},
+				{kyaml.Lookup("manifests")},
+				{kyaml.Lookup("profiles"), kyaml.MatchElementList([]string{"name"}, []string{"profile-0"}), kyaml.Lookup("manifests")},
+				{kyaml.Lookup("profiles"), kyaml.MatchElementList([]string{"name"}, []string{"profile-0"}), kyaml.Lookup("manifests"), kyaml.Lookup("rawYaml")},
 			},
 		},
 		{
@@ -1517,9 +1513,9 @@ func TestConfigLocationsLocate(t *testing.T) {
 			profiles:         []string{"profile-0"},
 			expected: []configlocations.Location{
 				{
-					StartLine:   24,
+					StartLine:   22,
 					StartColumn: 18,
-					EndLine:     25,
+					EndLine:     23,
 					EndColumn:   0,
 				},
 			},
@@ -1530,9 +1526,9 @@ func TestConfigLocationsLocate(t *testing.T) {
 			profiles:         []string{"profile-1"},
 			expected: []configlocations.Location{
 				{
-					StartLine:   31,
+					StartLine:   29,
 					StartColumn: 18,
-					EndLine:     32,
+					EndLine:     30,
 					EndColumn:   0,
 				},
 			},
diff --git a/pkg/skaffold/render/generate/generate_test.go b/pkg/skaffold/render/generate/generate_test.go
index d638b6e5d..cbc025362 100644
--- a/pkg/skaffold/render/generate/generate_test.go
+++ b/pkg/skaffold/render/generate/generate_test.go
@@ -246,10 +246,10 @@ func TestManifestDeps(t *testing.T) {
 				Kpt: []string{"kpt-sample"},
 			},
 			expected: []string{
-				"kpt-sample/Kptfile",
-				"kpt-sample/deployment.yaml",
 				"kustomize-sample/kustomization.yaml",
 				"kustomize-sample/patch.yaml",
+				"kpt-sample/Kptfile",
+				"kpt-sample/deployment.yaml",
 				"rawYaml-sample/pod.yaml",
 				"rawYaml-sample/pods2.yaml",
 			},
diff --git a/pkg/skaffold/render/renderer/kubectl/kubectl_test.go b/pkg/skaffold/render/renderer/kubectl/kubectl_test.go
index 0e4ba5337..cdfb07a79 100644
--- a/pkg/skaffold/render/renderer/kubectl/kubectl_test.go
+++ b/pkg/skaffold/render/renderer/kubectl/kubectl_test.go
@@ -18,6 +18,7 @@ package kubectl
 import (
 	"bytes"
 	"context"
+	"path/filepath"
 	"testing"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
@@ -98,3 +99,72 @@ func TestRender(t *testing.T) {
 		})
 	}
 }
+
+func TestDependencies(t *testing.T) {
+	tests := []struct {
+		description string
+		manifests   []string
+		expected    []string
+	}{
+		{
+			description: "no manifest",
+			manifests:   []string(nil),
+			expected:    []string(nil),
+		},
+		{
+			description: "missing manifest file",
+			manifests:   []string{"missing.yaml"},
+			expected:    []string(nil),
+		},
+		{
+			description: "ignore non-manifest",
+			manifests:   []string{"*.ignored"},
+			expected:    []string(nil),
+		},
+		{
+			description: "single manifest",
+			manifests:   []string{"deployment.yaml"},
+			expected:    []string{"deployment.yaml"},
+		},
+		{
+			description: "keep manifests order",
+			manifests:   []string{"01_name.yaml", "00_service.yaml"},
+			expected:    []string{"01_name.yaml", "00_service.yaml"},
+		},
+		{
+			description: "sort children",
+			manifests:   []string{"01/*.yaml", "00/*.yaml"},
+			expected:    []string{filepath.Join("01", "a.yaml"), filepath.Join("01", "b.yaml"), filepath.Join("00", "a.yaml"), filepath.Join("00", "b.yaml")},
+		},
+		{
+			description: "http manifest",
+			manifests:   []string{"deployment.yaml", "http://remote.yaml"},
+			expected:    []string{"deployment.yaml"},
+		},
+	}
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			tmpDir := t.NewTempDir()
+			tmpDir.Touch("deployment.yaml", "01_name.yaml", "00_service.yaml", "empty.ignored").
+				Touch("01/a.yaml", "01/b.yaml").
+				Touch("00/b.yaml", "00/a.yaml").
+				Chdir()
+
+			mockCfg := render.MockConfig{WorkingDir: tmpDir.Root()}
+			rCfg := latest.RenderConfig{
+				Generate: latest.Generate{RawK8s: test.manifests},
+			}
+			r, err := New(mockCfg, rCfg, map[string]string{}, "default")
+			t.CheckNoError(err)
+
+			dependencies, err := r.ManifestDeps()
+
+			t.CheckNoError(err)
+			expected := make([]string, len(test.expected))
+			for i, p := range test.expected {
+				expected[i] = filepath.Join(tmpDir.Root(), p)
+			}
+			t.CheckDeepEqual(expected, dependencies)
+		})
+	}
+}
diff --git a/pkg/skaffold/render/renderer/render_mux_test.go b/pkg/skaffold/render/renderer/render_mux_test.go
index 5c95e70c4..6fe72af4b 100644
--- a/pkg/skaffold/render/renderer/render_mux_test.go
+++ b/pkg/skaffold/render/renderer/render_mux_test.go
@@ -33,14 +33,14 @@ import (
 func TestRenderMux_Render(t *testing.T) {
 	tests := []struct {
 		name         string
-		renderers    []Renderer
+		renderers    GroupRenderer
 		expected     string
 		expectedDeps []string
 		shouldErr    bool
 	}{
 		{
 			name: "concatenates render results with separator",
-			renderers: []Renderer{
+			renderers: GroupRenderer{
 				mock{configName: "config1", manifests: "manifest-1", deps: []string{"file1.txt", "file2.txt"}},
 				mock{configName: "config2", manifests: "manifest-2", deps: []string{"file2.txt", "file3.txt"}}},
 			expected:     "manifest-1\n---\nmanifest-2",
@@ -48,7 +48,7 @@ func TestRenderMux_Render(t *testing.T) {
 		},
 		{
 			name: "returns empty string when any call fails",
-			renderers: []Renderer{
+			renderers: GroupRenderer{
 				mock{manifests: "manifest-1", deps: []string{"file1.txt"}},
 				mock{deps: []string{"file2.txt"}, shouldErr: true}},
 			expectedDeps: []string{"file1.txt", "file2.txt"},
@@ -56,7 +56,7 @@ func TestRenderMux_Render(t *testing.T) {
 		},
 		{
 			name: "short-circuits when first call fails",
-			renderers: []Renderer{
+			renderers: GroupRenderer{
 				mock{deps: []string{"file1.txt"}, shouldErr: true},
 				mock{manifests: "manifest-2", deps: []string{"file2.txt"}}},
 			expectedDeps: []string{"file1.txt", "file2.txt"},
diff --git a/pkg/skaffold/runner/deployer_test.go b/pkg/skaffold/runner/deployer_test.go
index a0b415da9..a75a8822e 100644
--- a/pkg/skaffold/runner/deployer_test.go
+++ b/pkg/skaffold/runner/deployer_test.go
@@ -470,3 +470,54 @@ func TestGetDefaultDeployer(tOuter *testing.T) {
 		}
 	})
 }
+
+func TestGetCloudRunDeployer(tOuter *testing.T) {
+	tests := []struct {
+		name     string
+		opts     config.SkaffoldOptions
+		cfgs     map[string]latest.DeployType
+		expected *cloudrun.Deployer
+		haveErr  bool
+	}{
+		{
+			name: "deploy one config with no flags set",
+			cfgs: map[string]latest.DeployType{"": {
+				CloudRunDeploy: &latest.CloudRunDeploy{ProjectID: "test-project", Region: "test-region"},
+			}},
+			expected: &cloudrun.Deployer{Project: "test-project", Region: "test-region"},
+		},
+		{
+			name: "deploy with two configs and conflicting processes",
+			cfgs: map[string]latest.DeployType{"": {
+				CloudRunDeploy: &latest.CloudRunDeploy{ProjectID: "test-project", Region: "test-region"}},
+				"second": {
+					CloudRunDeploy: &latest.CloudRunDeploy{ProjectID: "test-project2", Region: "test-region"},
+				},
+			},
+			haveErr: true,
+		},
+		{
+			name: "deploy with flags set overrides config",
+			opts: config.SkaffoldOptions{CloudRunProject: "overridden-project"},
+			cfgs: map[string]latest.DeployType{"": {
+				CloudRunDeploy: &latest.CloudRunDeploy{ProjectID: "test-project", Region: "test-region"},
+			}},
+			expected: &cloudrun.Deployer{Project: "overridden-project", Region: "test-region"},
+		},
+	}
+	for _, test := range tests {
+		testutil.Run(tOuter, test.name, func(t *testutil.T) {
+			pipelines := make(map[string]latest.Pipeline)
+			for name, config := range test.cfgs {
+				pipelines[name] = latest.Pipeline{Deploy: latest.DeployConfig{DeployType: config}}
+			}
+			rctx := &runcontext.RunContext{
+				Opts:      test.opts,
+				Pipelines: runcontext.NewPipelines(pipelines),
+			}
+			crDeployer, err := getCloudRunDeployer(rctx, &label.DefaultLabeller{}, rctx.DeployConfigs(), "")
+			t.CheckErrorAndFailNow(test.haveErr, err)
+			t.CheckDeepEqual(crDeployer, test.expected, cmpopts.IgnoreUnexported(cloudrun.Deployer{}))
+		})
+	}
+}
diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go
index afec3de5a..98daf59a3 100644
--- a/pkg/skaffold/schema/latest/config.go
+++ b/pkg/skaffold/schema/latest/config.go
@@ -721,18 +721,12 @@ type DockerDeploy struct {
 // KubectlDeploy *beta* uses a client side `kubectl apply` to deploy manifests.
 // You'll need a `kubectl` CLI version installed that's compatible with your cluster.
 type KubectlDeploy struct {
-	// Manifests lists the Kubernetes yaml or json manifests.
-	// Defaults to `["k8s/*.yaml"]`.
-	// This field is no longer needed in render v2. If given, the v1 kubectl deployer will be triggered.
-	Manifests []string `yaml:"manifests,omitempty" skaffold:"filepath"`
+	// Flags are additional flags passed to `kubectl`.
+	Flags KubectlFlags `yaml:"flags,omitempty"`
 
 	// RemoteManifests lists Kubernetes manifests in remote clusters.
-	// This field is only used by v1 kubectl deployer.
 	RemoteManifests []string `yaml:"remoteManifests,omitempty"`
 
-	// Flags are additional flags passed to `kubectl`.
-	Flags KubectlFlags `yaml:"flags,omitempty"`
-
 	// DefaultNamespace is the default namespace passed to kubectl on deployment if no other override is given.
 	DefaultNamespace *string `yaml:"defaultNamespace,omitempty"`
 
diff --git a/pkg/skaffold/schema/profiles_test.go b/pkg/skaffold/schema/profiles_test.go
index 16dc9bbf8..776e79a12 100644
--- a/pkg/skaffold/schema/profiles_test.go
+++ b/pkg/skaffold/schema/profiles_test.go
@@ -36,10 +36,9 @@ func TestApplyPatch(t *testing.T) {
 	config := `build:
   artifacts:
   - image: example
-deploy:
-  kubectl:
-    manifests:
-    - k8s-*
+manifests:
+  rawYaml:
+  - k8s-*
 profiles:
 - name: patches
   patches:
@@ -56,7 +55,7 @@ profiles:
       docker:
         dockerfile: Dockerfile.second
   - op: remove
-    path: /deploy
+    path: /manifests
 `
 
 	testutil.Run(t, "", func(t *testutil.T) {
@@ -123,7 +122,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "profile",
 					Pipeline: latest.Pipeline{
@@ -148,7 +147,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -160,7 +159,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "dev",
 					Pipeline: latest.Pipeline{
@@ -175,7 +174,7 @@ func TestApplyProfiles(t *testing.T) {
 					withShaTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -187,7 +186,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "profile",
 					Pipeline: latest.Pipeline{
@@ -214,7 +213,7 @@ func TestApplyProfiles(t *testing.T) {
 					withDockerArtifact("image", ".", "Dockerfile.DEV"),
 					withDockerArtifact("imageProd", ".", "Dockerfile.DEV"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -225,7 +224,7 @@ func TestApplyProfiles(t *testing.T) {
 				withLocalBuild(
 					withGitTagger(),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "profile",
 					Pipeline: latest.Pipeline{
@@ -242,7 +241,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 				),
 				withHelmDeploy(),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -254,7 +253,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "profile",
 					Patches: []latest.JSONPatch{{
@@ -268,7 +267,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile.DEV"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -280,7 +279,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "profile",
 					Patches: []latest.JSONPatch{{
@@ -424,7 +423,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "dev",
 				},
@@ -443,7 +442,7 @@ func TestApplyProfiles(t *testing.T) {
 					withShaTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 		{
@@ -455,7 +454,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 				withProfiles(latest.Profile{
 					Name: "dev",
 				},
@@ -474,7 +473,7 @@ func TestApplyProfiles(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("image", ".", "Dockerfile"),
 				),
-				withKubectlDeploy("k8s/*.yaml"),
+				withRawK8s("k8s/*.yaml"),
 			),
 		},
 	}
diff --git a/pkg/skaffold/schema/validation/validation_test.go b/pkg/skaffold/schema/validation/validation_test.go
index c443b4988..9fc1b20a9 100644
--- a/pkg/skaffold/schema/validation/validation_test.go
+++ b/pkg/skaffold/schema/validation/validation_test.go
@@ -1617,11 +1617,9 @@ func TestValidateKubectlManifests(t *testing.T) {
 			configs: []*latest.SkaffoldConfig{
 				{
 					Pipeline: latest.Pipeline{
-						Deploy: latest.DeployConfig{
-							DeployType: latest.DeployType{
-								KubectlDeploy: &latest.KubectlDeploy{
-									Manifests: []string{filepath.Join(tempDir, "validation-test-exists.yaml")},
-								},
+						Render: latest.RenderConfig{
+							Generate: latest.Generate{
+								RawK8s: []string{filepath.Join(tempDir, "validation-test-exists.yaml")},
 							},
 						},
 					},
@@ -1634,11 +1632,9 @@ func TestValidateKubectlManifests(t *testing.T) {
 			configs: []*latest.SkaffoldConfig{
 				{
 					Pipeline: latest.Pipeline{
-						Deploy: latest.DeployConfig{
-							DeployType: latest.DeployType{
-								KubectlDeploy: &latest.KubectlDeploy{
-									Manifests: []string{filepath.Join(tempDir, "validation-test-missing.yaml")},
-								},
+						Render: latest.RenderConfig{
+							Generate: latest.Generate{
+								RawK8s: []string{filepath.Join(tempDir, "validation-test-missing.yaml")},
 							},
 						},
 					},
diff --git a/pkg/skaffold/schema/versions_test.go b/pkg/skaffold/schema/versions_test.go
index cd0b991d2..eff8523b9 100644
--- a/pkg/skaffold/schema/versions_test.go
+++ b/pkg/skaffold/schema/versions_test.go
@@ -49,8 +49,6 @@ build:
     gitCommit: {}
   artifacts:
   - image: example
-deploy:
-  kubectl: {}
 `
 	// This config has two tag policies set.
 	invalidConfig = `
@@ -79,11 +77,31 @@ build:
       target: //:example.tar
   googleCloudBuild:
     projectId: ID
-deploy:
-  kubectl:
-   manifests:
+manifests:
+  rawYaml:
    - dep.yaml
    - svc.yaml
+`
+	completeV1Config = `
+build:
+  tagPolicy:
+    sha256: {}
+  artifacts:
+  - image: image1
+    context: ./examples/app1
+    docker:
+      dockerfile: Dockerfile.dev
+  - image: image2
+    context: ./examples/app2
+    bazel:
+      target: //:example.tar
+  googleCloudBuild:
+    projectId: ID
+deploy:
+  kubectl:
+    manifests:
+    - dep.yaml
+    - svc.yaml
 `
 	minimalClusterConfig = `
 build:
@@ -126,6 +144,22 @@ build:
       path: /kaniko/.docker
 `
 
+	completeClusterConfigV1 = `
+build:
+  artifacts:
+  - image: image1
+    context: ./examples/app1
+    kaniko: {}
+  cluster:
+    pullSecretPath: /secret.json
+    pullSecretName: secret-name
+    namespace: nskaniko
+    timeout: 120m
+    dockerConfig:
+      secretName: config-name
+      path: /kaniko/.docker
+`
+
 	badConfig = "bad config"
 
 	invalidStatusCheckConfig = `
@@ -193,7 +227,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 		shouldErr   bool
 	}{
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Kaniko Volume Mount - ConfigMap",
 			config:      []string{kanikoConfigMap},
 			expected: []util.VersionedConfig{config(
@@ -215,7 +249,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Minimal config",
 			config:      []string{minimalConfig},
 			expected: []util.VersionedConfig{config(
@@ -237,7 +271,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Simple config",
 			config:      []string{simpleConfig},
 			expected: []util.VersionedConfig{config(
@@ -246,13 +280,13 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 					withGitTagger(),
 					withDockerArtifact("example", ".", "Dockerfile"),
 				),
-				withKubectlDeploy(),
+				withRawK8s(),
 				withLogsPrefix("container"),
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
-			description: "Complete config",
+			apiVersion:  []string{latest.Version},
+			description: "Complete config v1",
 			config:      []string{completeConfig},
 			expected: []util.VersionedConfig{config(
 				withGoogleCloudBuild("ID",
@@ -262,13 +296,12 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 				),
 				withRawK8s("dep.yaml", "svc.yaml"),
 				withLogsPrefix("container"),
-				withKubectlDeploy(),
 			)},
 		},
 		{
 			apiVersion:  []string{v2beta8.Version},
 			description: "Old version complete config",
-			config:      []string{completeConfig},
+			config:      []string{completeV1Config},
 			expected: []util.VersionedConfig{config(
 				withGoogleCloudBuild("ID",
 					withShaTagger(),
@@ -276,12 +309,12 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 					withBazelArtifact(),
 				),
 				withRawK8s("dep.yaml", "svc.yaml"),
+				withKubectlDeployer(),
 				withLogsPrefix("container"),
-				withKubectlDeploy(),
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version, latestV1.Version},
+			apiVersion:  []string{latest.Version, latest.Version},
 			description: "Multiple complete config with same API versions",
 			config:      []string{completeConfig, completeClusterConfig},
 			expected: []util.VersionedConfig{config(
@@ -292,7 +325,6 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 				),
 				withRawK8s("dep.yaml", "svc.yaml"),
 				withLogsPrefix("container"),
-				withKubectlDeploy(),
 			), config(
 				withClusterBuild("secret-name", "/secret", "nskaniko", "/secret.json", "120m",
 					withGitTagger(),
@@ -303,9 +335,9 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version, v2beta8.Version},
+			apiVersion:  []string{latest.Version, v2beta8.Version},
 			description: "Multiple complete config with different API versions",
-			config:      []string{completeConfig, completeClusterConfig},
+			config:      []string{completeConfig, completeClusterConfigV1},
 			expected: []util.VersionedConfig{config(
 				withGoogleCloudBuild("ID",
 					withShaTagger(),
@@ -314,7 +346,6 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 				),
 				withRawK8s("dep.yaml", "svc.yaml"),
 				withLogsPrefix("container"),
-				withKubectlDeploy(),
 			), config(
 				withClusterBuild("secret-name", "/secret", "nskaniko", "/secret.json", "120m",
 					withGitTagger(),
@@ -325,7 +356,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Minimal Cluster config",
 			config:      []string{minimalClusterConfig},
 			expected: []util.VersionedConfig{config(
@@ -337,7 +368,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Complete Cluster config",
 			config:      []string{completeClusterConfig},
 			expected: []util.VersionedConfig{config(
@@ -350,13 +381,13 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "Bad config",
 			config:      []string{badConfig},
 			shouldErr:   true,
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "two taggers defined",
 			config:      []string{invalidConfig},
 			shouldErr:   true,
@@ -368,13 +399,13 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			shouldErr:   true,
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "invalid statusCheckDeadline",
 			config:      []string{invalidStatusCheckConfig},
 			shouldErr:   true,
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "valid statusCheckDeadline",
 			config:      []string{validStatusCheckConfig},
 			expected: []util.VersionedConfig{config(
@@ -386,7 +417,7 @@ func TestParseConfigAndUpgrade(t *testing.T) {
 			)},
 		},
 		{
-			apiVersion:  []string{latestV1.Version},
+			apiVersion:  []string{latest.Version},
 			description: "custom log prefix",
 			config:      []string{customLogPrefix},
 			expected: []util.VersionedConfig{config(
@@ -533,17 +564,15 @@ func withDockerConfig(secretName string, path string) func(*latest.BuildConfig)
 	}
 }
 
-func withKubectlDeploy(manifests ...string) func(*latest.SkaffoldConfig) {
+func withRawK8s(manifests ...string) func(*latest.SkaffoldConfig) {
 	return func(cfg *latest.SkaffoldConfig) {
-		cfg.Deploy.DeployType.KubectlDeploy = &latest.KubectlDeploy{
-			Manifests: manifests,
-		}
+		cfg.Render.RawK8s = manifests
 	}
 }
 
-func withRawK8s(manifests ...string) func(*latest.SkaffoldConfig) {
+func withKubectlDeployer() func(*latest.SkaffoldConfig) {
 	return func(cfg *latest.SkaffoldConfig) {
-		cfg.Render.RawK8s = manifests
+		cfg.Deploy.KubectlDeploy = &latest.KubectlDeploy{}
 	}
 }
 
diff --git a/pkg/skaffold/test/structure/structure.go b/pkg/skaffold/test/structure/structure.go
index 3ece30061..86d05e80f 100644
--- a/pkg/skaffold/test/structure/structure.go
+++ b/pkg/skaffold/test/structure/structure.go
@@ -23,6 +23,8 @@ import (
 	"os"
 	"os/exec"
 
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/event"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
@@ -71,7 +73,7 @@ func (cst *Runner) runStructureTests(ctx context.Context, out io.Writer, imageTa
 		// The image is remote so we have to pull it locally.
 		// `container-structure-test` currently can't do it:
 		// https://github.com/GoogleContainerTools/container-structure-test/issues/253.
-		if err := cst.localDaemon.Pull(ctx, out, imageTag); err != nil {
+		if err := cst.localDaemon.Pull(ctx, out, imageTag, v1.Platform{}); err != nil {
 			return dockerPullImageErr(imageTag, err)
 		}
 	}