Repository: linkerd/linkerd2
Pull request #12509 (2024-04-26 03:20:15)

build(deps): bump parking_lot_core from 0.9.9 to 0.9.10
Bumps [parking_lot_core](https://github.com/Amanieu/parking_lot) from 0.9.9 to 0.9.10.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md">parking_lot_core's changelog</a>.</em></p>
<blockquote>
<h2>parking_lot 0.12.2, parking_lot_core 0.9.10, lock_api 0.4.12 (2024-04-15)</h2>
<ul>
<li>Fixed panic when calling <code>with_upgraded</code> twice on a <code>ArcRwLockUpgradableReadGuard</code> (<a href="https://redirect.github.com/Amanieu/parking_lot/issues/431">#431</a>)</li>
<li>Fixed <code>RwLockUpgradeableReadGuard::with_upgraded</code></li>
<li>Added lock_api::{Mutex, ReentrantMutex, RwLock}::from_raw methods (<a href="https://redirect.github.com/Amanieu/parking_lot/issues/429">#429</a>)</li>
<li>Added Apple visionOS support (<a href="https://redirect.github.com/Amanieu/parking_lot/issues/433">#433</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/Amanieu/parking_lot/commit/9dace42690f78bcf30f387ba42024bff4e8b6c18"><code>9dace42</code></a> Release parking_lot 0.12.2, parking_lot_core 0.9.10, lock_api 0.4.12</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/4f898be372479d7cb00809f570dfedd265865393"><code>4f898be</code></a> Merge pull request <a href="https://redirect.github.com/Amanieu/parking_lot/issues/435">#435</a> from sorcio/wasm-atomics-feature</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/9ee3a5461299b904c5707c27988ddcf92d642c04"><code>9ee3a54</code></a> stdarch_wasm_atomic_wait instead of stdsimd</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/7aeb2f1306ea7863cdb3ad3bbff835269aa19dd7"><code>7aeb2f1</code></a> Merge pull request <a href="https://redirect.github.com/Amanieu/parking_lot/issues/433">#433</a> from QuentinPerez/master</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/c0a9077b87bd72ea99600ba8c230736eefdf286e"><code>c0a9077</code></a> Add Apple visionOS support</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/7ab94b663825ec204bdbe3e295168e8e62b35a16"><code>7ab94b6</code></a> Merge pull request <a href="https://redirect.github.com/Amanieu/parking_lot/issues/432">#432</a> from alex/patch-1</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/75a97b267081cffca4b00aa476711314d1adbdf2"><code>75a97b2</code></a> Update redox_syscall dependency version</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/66d025be4b098fe5526dfbcdc9265a41856da709"><code>66d025b</code></a> Merge pull request <a href="https://redirect.github.com/Amanieu/parking_lot/issues/431">#431</a> from mbyzhang/master</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/cd7bda057531e8e5098cdab54f03bbe438e85436"><code>cd7bda0</code></a> Merge pull request <a href="https://redirect.github.com/Amanieu/parking_lot/issues/429">#429</a> from waywardmonkeys/fix-typos</li>
<li><a href="https://github.com/Amanieu/parking_lot/commit/1bb45aaac4c13269606fc9fe170ea580b36d797b"><code>1bb45aa</code></a> Fix panic when calling <code>with_upgraded</code> twice on a <code>ArcRwLockUpgradableReadGuard</code></li>
<li>Additional commits viewable in <a href="https://github.com/Amanieu/parking_lot/compare/core-0.9.9...core-0.9.10">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=parking_lot_core&package-manager=cargo&previous-version=0.9.9&new-version=0.9.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 77188e2a5..461f7f9bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1536,15 +1536,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.9"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.48.2",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
@@ -1780,11 +1780,11 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.4.1"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.0",
 ]
 
 [[package]]
@@ -1867,9 +1867,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.21.11"
+version = "0.21.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4"
+checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
 dependencies = [
  "log",
  "ring",
@@ -1931,9 +1931,9 @@ dependencies = [
 
 [[package]]
 name = "schemars"
-version = "0.8.16"
+version = "0.8.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
+checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309"
 dependencies = [
  "dyn-clone",
  "schemars_derive",
@@ -1943,14 +1943,14 @@ dependencies = [
 
 [[package]]
 name = "schemars_derive"
-version = "0.8.16"
+version = "0.8.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
+checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108"
 dependencies = [
  "proc-macro2",
  "quote",
  "serde_derive_internals",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -2004,9 +2004,9 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.198"
+version = "1.0.199"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
+checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
 dependencies = [
  "serde_derive",
 ]
@@ -2023,9 +2023,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.198"
+version = "1.0.199"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
+checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2034,13 +2034,13 @@ dependencies = [
 
 [[package]]
 name = "serde_derive_internals"
-version = "0.26.0"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
+checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
diff --git a/cli/cmd/identity.go b/cli/cmd/identity.go
index cd25cbc39..62e4c88ea 100644
--- a/cli/cmd/identity.go
+++ b/cli/cmd/identity.go
@@ -161,7 +161,8 @@ func getContainerWithPort(pod corev1.Pod, portName string) (corev1.Container, er
 		return container, fmt.Errorf("pod not running: %s", pod.GetName())
 	}
 
-	for _, c := range pod.Spec.Containers {
+	containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+	for _, c := range containers {
 		if c.Name != k8s.ProxyContainerName {
 			continue
 		}
diff --git a/cli/cmd/metrics_diagnostics_util.go b/cli/cmd/metrics_diagnostics_util.go
index 9b1a5cc13..c658dde70 100644
--- a/cli/cmd/metrics_diagnostics_util.go
+++ b/cli/cmd/metrics_diagnostics_util.go
@@ -43,7 +43,8 @@ func getAllContainersWithPort(
 	}
 	var containers []corev1.Container
 
-	for _, c := range pod.Spec.Containers {
+	allContainers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+	for _, c := range allContainers {
 		for _, p := range c.Ports {
 			if p.Name == portName {
 				containers = append(containers, c)
diff --git a/controller/api/destination/endpoint_translator.go b/controller/api/destination/endpoint_translator.go
index 1d32c220e..60b68ddee 100644
--- a/controller/api/destination/endpoint_translator.go
+++ b/controller/api/destination/endpoint_translator.go
@@ -665,7 +665,8 @@ func newEmptyAddressSet() watcher.AddressSet {
 // getInboundPort gets the inbound port from the proxy container's environment
 // variable.
 func getInboundPort(podSpec *corev1.PodSpec) (uint32, error) {
-	for _, containerSpec := range podSpec.Containers {
+	containers := append(podSpec.InitContainers, podSpec.Containers...)
+	for _, containerSpec := range containers {
 		if containerSpec.Name != pkgK8s.ProxyContainerName {
 			continue
 		}
diff --git a/multicluster/service-mirror/cluster_watcher.go b/multicluster/service-mirror/cluster_watcher.go
index 8d6915ef4..0598b9f36 100644
--- a/multicluster/service-mirror/cluster_watcher.go
+++ b/multicluster/service-mirror/cluster_watcher.go
@@ -309,7 +309,14 @@ func (rcsw *RemoteClusterServiceWatcher) cleanupOrphanedServices(ctx context.Con
 
 	var errors []error
 	for _, srv := range servicesOnLocalCluster {
-		_, err := rcsw.remoteAPIClient.Svc().Lister().Services(srv.Namespace).Get(rcsw.originalResourceName(srv.Name))
+		mirroredName := srv.Name
+		// For headless services with cluster IPs representing the backing pods, the mirrored service name
+		// is the root headless service in the source cluster
+		if remoteHeadlessSvcName, headlessMirror := srv.Labels[consts.MirroredHeadlessSvcNameLabel]; headlessMirror {
+			mirroredName = remoteHeadlessSvcName
+		}
+		remoteServiceName := rcsw.originalResourceName(mirroredName)
+		_, err := rcsw.remoteAPIClient.Svc().Lister().Services(srv.Namespace).Get(remoteServiceName)
 		if err != nil {
 			if kerrors.IsNotFound(err) {
 				// service does not exist anymore. Need to delete
diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go
index b059c878f..30fa65ec2 100644
--- a/pkg/healthcheck/healthcheck.go
+++ b/pkg/healthcheck/healthcheck.go
@@ -2257,7 +2257,8 @@ func GetMeshedPodsIdentityData(ctx context.Context, api kubernetes.Interface, da
 	}
 	pods := []MeshedPodIdentityData{}
 	for _, pod := range podList.Items {
-		for _, containerSpec := range pod.Spec.Containers {
+		containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+		for _, containerSpec := range containers {
 			if containerSpec.Name != k8s.ProxyContainerName {
 				continue
 			}
@@ -2937,7 +2938,8 @@ func CheckIfDataPlanePodsExist(pods []corev1.Pod) error {
 }
 
 func containsProxy(pod corev1.Pod) bool {
-	for _, containerSpec := range pod.Spec.Containers {
+	containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+	for _, containerSpec := range containers {
 		if containerSpec.Name == k8s.ProxyContainerName {
 			return true
 		}
diff --git a/pkg/healthcheck/sidecar.go b/pkg/healthcheck/sidecar.go
index 1ed54f491..40e713818 100644
--- a/pkg/healthcheck/sidecar.go
+++ b/pkg/healthcheck/sidecar.go
@@ -10,7 +10,8 @@ import (
 // HasExistingSidecars returns true if the pod spec already has the proxy init
 // and sidecar containers injected. Otherwise, it returns false.
 func HasExistingSidecars(podSpec *corev1.PodSpec) bool {
-	for _, container := range podSpec.Containers {
+	containers := append(podSpec.InitContainers, podSpec.Containers...)
+	for _, container := range containers {
 		if strings.HasPrefix(container.Image, "cr.l5d.io/linkerd/proxy:") ||
 			strings.HasPrefix(container.Image, "gcr.io/istio-release/proxyv2:") ||
 			container.Name == k8s.ProxyContainerName ||
diff --git a/pkg/inject/uninject.go b/pkg/inject/uninject.go
index 136502398..c652b54c3 100644
--- a/pkg/inject/uninject.go
+++ b/pkg/inject/uninject.go
@@ -36,10 +36,13 @@ func (conf *ResourceConfig) uninjectPodSpec(report *Report) {
 	t := conf.pod.spec
 	initContainers := []v1.Container{}
 	for _, container := range t.InitContainers {
-		if container.Name != k8s.InitContainerName {
-			initContainers = append(initContainers, container)
-		} else {
+		switch container.Name {
+		case k8s.InitContainerName:
 			report.Uninjected.ProxyInit = true
+		case k8s.ProxyContainerName:
+			report.Uninjected.Proxy = true
+		default:
+			initContainers = append(initContainers, container)
 		}
 	}
 	t.InitContainers = initContainers
diff --git a/pkg/k8s/api.go b/pkg/k8s/api.go
index b8f74ba51..8985da427 100644
--- a/pkg/k8s/api.go
+++ b/pkg/k8s/api.go
@@ -229,19 +229,27 @@ func (kubeAPI *KubernetesAPI) GetNamespaceWithExtensionLabel(ctx context.Context
 
 // GetPodStatus receives a pod and returns the pod status, based on `kubectl` logic.
 // This logic is imported and adapted from the github.com/kubernetes/kubernetes project:
-// https://github.com/kubernetes/kubernetes/blob/33a3e325f754d179b25558dee116fca1c67d353a/pkg/printers/internalversion/printers.go#L558-L640
+// https://github.com/kubernetes/kubernetes/blob/v1.31.0-alpha.0/pkg/printers/internalversion/printers.go#L860
 func GetPodStatus(pod corev1.Pod) string {
 	reason := string(pod.Status.Phase)
 	if pod.Status.Reason != "" {
 		reason = pod.Status.Reason
 	}
 
+	initContainers := make(map[string]*corev1.Container)
+	for i := range pod.Spec.InitContainers {
+		initContainers[pod.Spec.InitContainers[i].Name] = &pod.Spec.InitContainers[i]
+	}
+
 	initializing := false
 	for i := range pod.Status.InitContainerStatuses {
 		container := pod.Status.InitContainerStatuses[i]
 		switch {
 		case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0 && container.State.Terminated.Signal == 0:
 			continue
+		case isRestartableInitContainer(initContainers[container.Name]) &&
+			container.Started != nil && *container.Started && container.Ready:
+			continue
 		case container.State.Terminated != nil:
 			// initialization is failed
 			if container.State.Terminated.Reason == "" {
@@ -292,9 +300,20 @@ func GetPodStatus(pod corev1.Pod) string {
 	return reason
 }
 
+// Borrowed from
+// https://github.com/kubernetes/kubernetes/blob/v1.31.0-alpha.0/pkg/printers/internalversion/printers.go#L3209
+func isRestartableInitContainer(initContainer *corev1.Container) bool {
+	if initContainer.RestartPolicy == nil {
+		return false
+	}
+
+	return *initContainer.RestartPolicy == corev1.ContainerRestartPolicyAlways
+}
+
 // GetProxyReady returns true if the pod contains a proxy that is ready
 func GetProxyReady(pod corev1.Pod) bool {
-	for _, container := range pod.Status.ContainerStatuses {
+	statuses := append(pod.Status.InitContainerStatuses, pod.Status.ContainerStatuses...)
+	for _, container := range statuses {
 		if container.Name == ProxyContainerName {
 			return container.Ready
 		}
@@ -304,7 +323,8 @@ func GetProxyReady(pod corev1.Pod) bool {
 
 // GetProxyVersion returns the container proxy's version, if any
 func GetProxyVersion(pod corev1.Pod) string {
-	for _, container := range pod.Spec.Containers {
+	containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+	for _, container := range containers {
 		if container.Name == ProxyContainerName {
 			if strings.Contains(container.Image, "@") {
 				// Proxy container image is specified with digest instead of
diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go
index 26beac805..7d3d52f1d 100644
--- a/pkg/k8s/k8s.go
+++ b/pkg/k8s/k8s.go
@@ -239,7 +239,8 @@ func PodIdentity(pod *corev1.Pod) (string, error) {
 
 	podsa := pod.Spec.ServiceAccountName
 	podns := pod.ObjectMeta.Namespace
-	for _, c := range pod.Spec.Containers {
+	containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+	for _, c := range containers {
 		if c.Name == ProxyContainerName {
 			for _, env := range c.Env {
 				if env.Name == "LINKERD2_PROXY_IDENTITY_LOCAL_NAME" {
diff --git a/viz/pkg/healthcheck/healthcheck.go b/viz/pkg/healthcheck/healthcheck.go
index 4a388f454..6a15a6a27 100644
--- a/viz/pkg/healthcheck/healthcheck.go
+++ b/viz/pkg/healthcheck/healthcheck.go
@@ -474,7 +474,8 @@ func (hc *HealthChecker) checkPromAuthorized(ctx context.Context) error {
 			// default inbound policy is `deny`, there won't be an override
 			// annotation, but the proxy-injector will have set the env variable
 			// directly.
-			for _, c := range pod.Spec.Containers {
+			containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
+			for _, c := range containers {
 				if c.Name == k8s.ProxyContainerName {
 					for _, env := range c.Env {
 						if env.Name == "LINKERD2_PROXY_INBOUND_DEFAULT_POLICY" && env.Value == "deny" {


Test patch:
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_nativesidecar.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_nativesidecar.golden.yml
new file mode 100644
index 000000000..1bdd05277
--- /dev/null
+++ b/cli/cmd/testdata/inject_emojivoto_pod_nativesidecar.golden.yml
@@ -0,0 +1,228 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  annotations:
+    linkerd.io/created-by: linkerd/cli dev-undefined
+    linkerd.io/proxy-version: test-inject-proxy-version
+    linkerd.io/trust-root-sha256: 8dc603abd4e755c25c94da05abbf29b9b283a784733651020d72f97ca8ab98e4
+  labels:
+    app: vote-bot
+    linkerd.io/control-plane-ns: linkerd
+    linkerd.io/workload-ns: emojivoto
+  name: vote-bot
+  namespace: emojivoto
+spec:
+  containers:
+  - command:
+    - emojivoto-vote-bot
+    env:
+    - name: WEB_HOST
+      value: web-svc.emojivoto:80
+    image: buoyantio/emojivoto-web:v10
+    name: vote-bot
+  initContainers:
+  - args:
+    - --incoming-proxy-port
+    - "4143"
+    - --outgoing-proxy-port
+    - "4140"
+    - --proxy-uid
+    - "2102"
+    - --inbound-ports-to-ignore
+    - 4190,4191,4567,4568
+    - --outbound-ports-to-ignore
+    - 4567,4568
+    image: cr.l5d.io/linkerd/proxy-init:v2.3.0
+    imagePullPolicy: IfNotPresent
+    name: linkerd-init
+    resources:
+      limits:
+        cpu: 100m
+        memory: 20Mi
+      requests:
+        cpu: 100m
+        memory: 20Mi
+    securityContext:
+      allowPrivilegeEscalation: false
+      capabilities:
+        add:
+        - NET_ADMIN
+        - NET_RAW
+      privileged: false
+      readOnlyRootFilesystem: true
+      runAsNonRoot: true
+      runAsUser: 65534
+      seccompProfile:
+        type: RuntimeDefault
+    terminationMessagePolicy: FallbackToLogsOnError
+    volumeMounts:
+    - mountPath: /run
+      name: linkerd-proxy-init-xtables-lock
+  - env:
+    - name: _pod_name
+      valueFrom:
+        fieldRef:
+          fieldPath: metadata.name
+    - name: _pod_ns
+      valueFrom:
+        fieldRef:
+          fieldPath: metadata.namespace
+    - name: _pod_nodeName
+      valueFrom:
+        fieldRef:
+          fieldPath: spec.nodeName
+    - name: LINKERD2_PROXY_LOG
+      value: warn,linkerd=info,trust_dns=error
+    - name: LINKERD2_PROXY_LOG_FORMAT
+      value: plain
+    - name: LINKERD2_PROXY_DESTINATION_SVC_ADDR
+      value: linkerd-dst-headless.linkerd.svc.cluster.local.:8086
+    - name: LINKERD2_PROXY_DESTINATION_PROFILE_NETWORKS
+      value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16,fd00::/8
+    - name: LINKERD2_PROXY_POLICY_SVC_ADDR
+      value: linkerd-policy.linkerd.svc.cluster.local.:8090
+    - name: LINKERD2_PROXY_POLICY_WORKLOAD
+      value: |
+        {"ns":"$(_pod_ns)", "pod":"$(_pod_name)"}
+    - name: LINKERD2_PROXY_INBOUND_DEFAULT_POLICY
+      value: all-unauthenticated
+    - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
+      value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16,fd00::/8
+    - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+      value: 3s
+    - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+      value: 5m
+    - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+      value: 1h
+    - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
+      value: 100ms
+    - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
+      value: 1000ms
+    - name: LINKERD2_PROXY_OUTBOUND_DISCOVERY_IDLE_TIMEOUT
+      value: 5s
+    - name: LINKERD2_PROXY_INBOUND_DISCOVERY_IDLE_TIMEOUT
+      value: 90s
+    - name: LINKERD2_PROXY_CONTROL_LISTEN_ADDR
+      value: 0.0.0.0:4190
+    - name: LINKERD2_PROXY_ADMIN_LISTEN_ADDR
+      value: 0.0.0.0:4191
+    - name: LINKERD2_PROXY_OUTBOUND_LISTEN_ADDR
+      value: 127.0.0.1:4140
+    - name: LINKERD2_PROXY_INBOUND_LISTEN_ADDR
+      value: 0.0.0.0:4143
+    - name: LINKERD2_PROXY_INBOUND_IPS
+      valueFrom:
+        fieldRef:
+          fieldPath: status.podIPs
+    - name: LINKERD2_PROXY_INBOUND_PORTS
+    - name: LINKERD2_PROXY_DESTINATION_PROFILE_SUFFIXES
+      value: svc.cluster.local.
+    - name: LINKERD2_PROXY_INBOUND_ACCEPT_KEEPALIVE
+      value: 10000ms
+    - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
+      value: 10000ms
+    - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+      value: 25,587,3306,4444,5432,6379,9300,11211
+    - name: LINKERD2_PROXY_DESTINATION_CONTEXT
+      value: |
+        {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)", "pod":"$(_pod_name)"}
+    - name: _pod_sa
+      valueFrom:
+        fieldRef:
+          fieldPath: spec.serviceAccountName
+    - name: _l5d_ns
+      value: linkerd
+    - name: _l5d_trustdomain
+      value: cluster.local
+    - name: LINKERD2_PROXY_IDENTITY_DIR
+      value: /var/run/linkerd/identity/end-entity
+    - name: LINKERD2_PROXY_IDENTITY_TRUST_ANCHORS
+      value: |
+        -----BEGIN CERTIFICATE-----
+        MIIBwTCCAWagAwIBAgIQeDZp5lDaIygQ5UfMKZrFATAKBggqhkjOPQQDAjApMScw
+        JQYDVQQDEx5pZGVudGl0eS5saW5rZXJkLmNsdXN0ZXIubG9jYWwwHhcNMjAwODI4
+        MDcxMjQ3WhcNMzAwODI2MDcxMjQ3WjApMScwJQYDVQQDEx5pZGVudGl0eS5saW5r
+        ZXJkLmNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARqc70Z
+        l1vgw79rjB5uSITICUA6GyfvSFfcuIis7B/XFSkkwAHU5S/s1AAP+R0TX7HBWUC4
+        uaG4WWsiwJKNn7mgo3AwbjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB
+        /wIBATAdBgNVHQ4EFgQU5YtjVVPfd7I7NLHsn2C26EByGV0wKQYDVR0RBCIwIIIe
+        aWRlbnRpdHkubGlua2VyZC5jbHVzdGVyLmxvY2FsMAoGCCqGSM49BAMCA0kAMEYC
+        IQCN7lBFLDDvjx6V0+XkjpKERRsJYf5adMvnloFl48ilJgIhANtxhndcr+QJPuC8
+        vgUC0d2/9FMueIVMb+46WTCOjsqr
+        -----END CERTIFICATE-----
+    - name: LINKERD2_PROXY_IDENTITY_TOKEN_FILE
+      value: /var/run/secrets/tokens/linkerd-identity-token
+    - name: LINKERD2_PROXY_IDENTITY_SVC_ADDR
+      value: linkerd-identity-headless.linkerd.svc.cluster.local.:8080
+    - name: LINKERD2_PROXY_IDENTITY_LOCAL_NAME
+      value: $(_pod_sa).$(_pod_ns).serviceaccount.identity.linkerd.cluster.local
+    - name: LINKERD2_PROXY_IDENTITY_SVC_NAME
+      value: linkerd-identity.linkerd.serviceaccount.identity.linkerd.cluster.local
+    - name: LINKERD2_PROXY_DESTINATION_SVC_NAME
+      value: linkerd-destination.linkerd.serviceaccount.identity.linkerd.cluster.local
+    - name: LINKERD2_PROXY_POLICY_SVC_NAME
+      value: linkerd-destination.linkerd.serviceaccount.identity.linkerd.cluster.local
+    image: cr.l5d.io/linkerd/proxy:test-inject-proxy-version
+    imagePullPolicy: IfNotPresent
+    lifecycle:
+      postStart:
+        exec:
+          command:
+          - /usr/lib/linkerd/linkerd-await
+          - --timeout=2m
+          - --port=4191
+    livenessProbe:
+      httpGet:
+        path: /live
+        port: 4191
+      initialDelaySeconds: 10
+      timeoutSeconds: 1
+    name: linkerd-proxy
+    ports:
+    - containerPort: 4143
+      name: linkerd-proxy
+    - containerPort: 4191
+      name: linkerd-admin
+    readinessProbe:
+      httpGet:
+        path: /ready
+        port: 4191
+      initialDelaySeconds: 2
+      timeoutSeconds: 1
+    restartPolicy: Always
+    securityContext:
+      allowPrivilegeEscalation: false
+      readOnlyRootFilesystem: true
+      runAsNonRoot: true
+      runAsUser: 2102
+      seccompProfile:
+        type: RuntimeDefault
+    startupProbe:
+      failureThreshold: 120
+      httpGet:
+        path: /ready
+        port: 4191
+        scheme: HTTP
+      periodSeconds: 1
+      successThreshold: 1
+      timeoutSeconds: 1
+    terminationMessagePolicy: FallbackToLogsOnError
+    volumeMounts:
+    - mountPath: /var/run/linkerd/identity/end-entity
+      name: linkerd-identity-end-entity
+    - mountPath: /var/run/secrets/tokens
+      name: linkerd-identity-token
+  volumes:
+  - emptyDir: {}
+    name: linkerd-proxy-init-xtables-lock
+  - emptyDir:
+      medium: Memory
+    name: linkerd-identity-end-entity
+  - name: linkerd-identity-token
+    projected:
+      sources:
+      - serviceAccountToken:
+          audience: identity.l5d.io
+          expirationSeconds: 86400
+          path: linkerd-identity-token
+---
diff --git a/cli/cmd/uninject_test.go b/cli/cmd/uninject_test.go
index 9bbbb142e..ba4d41f9f 100644
--- a/cli/cmd/uninject_test.go
+++ b/cli/cmd/uninject_test.go
@@ -61,6 +61,11 @@ func TestUninjectYAML(t *testing.T) {
 			goldenFileName: "inject_emojivoto_pod.input.yml",
 			reportFileName: "inject_emojivoto_pod_uninject.report",
 		},
+		{
+			inputFileName:  "inject_emojivoto_pod_nativesidecar.golden.yml",
+			goldenFileName: "inject_emojivoto_pod.input.yml",
+			reportFileName: "inject_emojivoto_pod_uninject.report",
+		},
 		{
 			inputFileName:  "inject_emojivoto_deployment_udp.golden.yml",
 			goldenFileName: "inject_emojivoto_deployment_udp.input.yml",
diff --git a/controller/api/destination/server_test.go b/controller/api/destination/server_test.go
index 66eb1f98a..62ff6ab3d 100644
--- a/controller/api/destination/server_test.go
+++ b/controller/api/destination/server_test.go
@@ -29,7 +29,6 @@ const fullyQualifiedNameOpaque = "name3.ns.svc.mycluster.local"
 const fullyQualifiedNameOpaqueService = "name4.ns.svc.mycluster.local"
 const fullyQualifiedNameSkipped = "name5.ns.svc.mycluster.local"
 const fullyQualifiedPodDNS = "pod-0.statefulset-svc.ns.svc.mycluster.local"
-const fullyQualifiedNamePolicy = "policy-test.ns.svc.mycluster.local"
 const clusterIP = "172.17.12.0"
 const clusterIPv6 = "2001:db8::88"
 const clusterIPOpaque = "172.17.12.1"
@@ -160,9 +159,20 @@ func TestGet(t *testing.T) {
 	})
 
 	t.Run("Return endpoint opaque protocol controlled by a server", func(t *testing.T) {
-		server, client := getServerWithClient(t)
+		testOpaque(t, "policy-test")
+	})
+
+	t.Run("Return endpoint opaque protocol controlled by a server (native sidecar)", func(t *testing.T) {
+		testOpaque(t, "native")
+	})
+
+	t.Run("Remote discovery", func(t *testing.T) {
+		server := makeServer(t)
 		defer server.clusterStore.UnregisterGauges()
 
+		// Wait for cluster store to be synced.
+		time.Sleep(50 * time.Millisecond)
+
 		stream := &bufferingGetStream{
 			updates:          make(chan *pb.Update, 50),
 			MockServerStream: util.NewMockServerStream(),
@@ -170,124 +180,121 @@ func TestGet(t *testing.T) {
 		defer stream.Cancel()
 		errs := make(chan error)
 
-		path := fmt.Sprintf("%s:%d", fullyQualifiedNamePolicy, 80)
-
 		// server.Get blocks until the grpc stream is complete so we call it
 		// in a goroutine and watch stream.updates for updates.
 		go func() {
-			err := server.Get(&pb.GetDestination{
-				Scheme: "k8s",
-				Path:   path,
-			}, stream)
+			err := server.Get(&pb.GetDestination{Scheme: "k8s", Path: fmt.Sprintf("%s:%d", "foo-target.ns.svc.mycluster.local", 80)}, stream)
 			if err != nil {
 				errs <- err
 			}
 		}()
 
 		select {
-		case err := <-errs:
-			t.Fatalf("Got error: %s", err)
 		case update := <-stream.updates:
-			addrs := update.GetAdd().Addrs
-			if len(addrs) == 0 {
-				t.Fatalf("Expected len(addrs) to be > 0")
-			}
-
-			if addrs[0].GetProtocolHint().GetOpaqueTransport() == nil {
-				t.Fatalf("Expected opaque transport for %s but was nil", path)
+			if updateAddAddress(t, update)[0] != fmt.Sprintf("%s:%d", "172.17.55.1", 80) {
+				t.Fatalf("Expected %s but got %s", fmt.Sprintf("%s:%d", podIP1, port), updateAddAddress(t, update)[0])
 			}
-		}
 
-		// Update the Server's pod selector so that it no longer selects the
-		// pod. This should result in the proxy protocol no longer being marked
-		// as opaque.
-		srv, err := client.ServerV1beta2().Servers("ns").Get(context.Background(), "srv", metav1.GetOptions{})
-		if err != nil {
-			t.Fatal(err)
-		}
-		// PodSelector is updated to NOT select the pod
-		srv.Spec.PodSelector.MatchLabels = map[string]string{"app": "FOOBAR"}
-		_, err = client.ServerV1beta2().Servers("ns").Update(context.Background(), srv, metav1.UpdateOptions{})
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		select {
-		case update := <-stream.updates:
-			addrs := update.GetAdd().Addrs
-			if len(addrs) == 0 {
-				t.Fatalf("Expected len(addrs) to be > 0")
+			if len(stream.updates) != 0 {
+				t.Fatalf("Expected 1 update but got %d: %v", 1+len(stream.updates), stream.updates)
 			}
 
-			if addrs[0].GetProtocolHint().GetOpaqueTransport() != nil {
-				t.Fatalf("Expected opaque transport to be nil for %s but was %+v", path, *addrs[0].GetProtocolHint().GetOpaqueTransport())
-			}
 		case err := <-errs:
 			t.Fatalf("Got error: %s", err)
 		}
+	})
+}
+
+func testOpaque(t *testing.T, name string) {
+	server, client := getServerWithClient(t)
+	defer server.clusterStore.UnregisterGauges()
+
+	stream := &bufferingGetStream{
+		updates:          make(chan *pb.Update, 50),
+		MockServerStream: util.NewMockServerStream(),
+	}
+	defer stream.Cancel()
+	errs := make(chan error)
 
-		// Update the Server's pod selector so that it once again selects the
-		// pod. This should result in the proxy protocol once again being marked
-		// as opaque.
-		srv.Spec.PodSelector.MatchLabels = map[string]string{"app": "policy-test"}
+	path := fmt.Sprintf("%s.ns.svc.mycluster.local:%d", name, 80)
 
-		_, err = client.ServerV1beta2().Servers("ns").Update(context.Background(), srv, metav1.UpdateOptions{})
+	// server.Get blocks until the grpc stream is complete so we call it
+	// in a goroutine and watch stream.updates for updates.
+	go func() {
+		err := server.Get(&pb.GetDestination{
+			Scheme: "k8s",
+			Path:   path,
+		}, stream)
 		if err != nil {
-			t.Fatal(err)
+			errs <- err
 		}
+	}()
 
-		select {
-		case update := <-stream.updates:
-			addrs := update.GetAdd().Addrs
-			if len(addrs) == 0 {
-				t.Fatalf("Expected len(addrs) to be > 0")
-			}
+	select {
+	case err := <-errs:
+		t.Fatalf("Got error: %s", err)
+	case update := <-stream.updates:
+		addrs := update.GetAdd().Addrs
+		if len(addrs) == 0 {
+			t.Fatalf("Expected len(addrs) to be > 0")
+		}
 
-			if addrs[0].GetProtocolHint().GetOpaqueTransport() == nil {
-				t.Fatalf("Expected opaque transport for %s but was nil", path)
-			}
-		case err := <-errs:
-			t.Fatalf("Got error: %s", err)
+		if addrs[0].GetProtocolHint().GetOpaqueTransport() == nil {
+			t.Fatalf("Expected opaque transport for %s but was nil", path)
 		}
-	})
+	}
 
-	t.Run("Remote discovery", func(t *testing.T) {
-		server := makeServer(t)
-		defer server.clusterStore.UnregisterGauges()
+	// Update the Server's pod selector so that it no longer selects the
+	// pod. This should result in the proxy protocol no longer being marked
+	// as opaque.
+	srv, err := client.ServerV1beta2().Servers("ns").Get(context.Background(), name, metav1.GetOptions{})
+	if err != nil {
+		t.Fatal(err)
+	}
+	// PodSelector is updated to NOT select the pod
+	srv.Spec.PodSelector.MatchLabels = map[string]string{"app": "FOOBAR"}
+	_, err = client.ServerV1beta2().Servers("ns").Update(context.Background(), srv, metav1.UpdateOptions{})
+	if err != nil {
+		t.Fatal(err)
+	}
 
-		// Wait for cluster store to be synced.
-		time.Sleep(50 * time.Millisecond)
+	select {
+	case update := <-stream.updates:
+		addrs := update.GetAdd().Addrs
+		if len(addrs) == 0 {
+			t.Fatalf("Expected len(addrs) to be > 0")
+		}
 
-		stream := &bufferingGetStream{
-			updates:          make(chan *pb.Update, 50),
-			MockServerStream: util.NewMockServerStream(),
+		if addrs[0].GetProtocolHint().GetOpaqueTransport() != nil {
+			t.Fatalf("Expected opaque transport to be nil for %s but was %+v", path, *addrs[0].GetProtocolHint().GetOpaqueTransport())
 		}
-		defer stream.Cancel()
-		errs := make(chan error)
+	case err := <-errs:
+		t.Fatalf("Got error: %s", err)
+	}
 
-		// server.Get blocks until the grpc stream is complete so we call it
-		// in a goroutine and watch stream.updates for updates.
-		go func() {
-			err := server.Get(&pb.GetDestination{Scheme: "k8s", Path: fmt.Sprintf("%s:%d", "foo-target.ns.svc.mycluster.local", 80)}, stream)
-			if err != nil {
-				errs <- err
-			}
-		}()
+	// Update the Server's pod selector so that it once again selects the
+	// pod. This should result in the proxy protocol once again being marked
+	// as opaque.
+	srv.Spec.PodSelector.MatchLabels = map[string]string{"app": name}
 
-		select {
-		case update := <-stream.updates:
-			if updateAddAddress(t, update)[0] != fmt.Sprintf("%s:%d", "172.17.55.1", 80) {
-				t.Fatalf("Expected %s but got %s", fmt.Sprintf("%s:%d", podIP1, port), updateAddAddress(t, update)[0])
-			}
+	_, err = client.ServerV1beta2().Servers("ns").Update(context.Background(), srv, metav1.UpdateOptions{})
+	if err != nil {
+		t.Fatal(err)
+	}
 
-			if len(stream.updates) != 0 {
-				t.Fatalf("Expected 1 update but got %d: %v", 1+len(stream.updates), stream.updates)
-			}
+	select {
+	case update := <-stream.updates:
+		addrs := update.GetAdd().Addrs
+		if len(addrs) == 0 {
+			t.Fatalf("Expected len(addrs) to be > 0")
+		}
 
-		case err := <-errs:
-			t.Fatalf("Got error: %s", err)
+		if addrs[0].GetProtocolHint().GetOpaqueTransport() == nil {
+			t.Fatalf("Expected opaque transport for %s but was nil", path)
 		}
-	})
+	case err := <-errs:
+		t.Fatalf("Got error: %s", err)
+	}
 }
 
 func TestGetProfiles(t *testing.T) {
diff --git a/controller/api/destination/test_util.go b/controller/api/destination/test_util.go
index 316060dfb..f50c37fce 100644
--- a/controller/api/destination/test_util.go
+++ b/controller/api/destination/test_util.go
@@ -376,7 +376,7 @@ endpoints:
   - 172.17.0.16
   targetRef:
     kind: Pod
-    name: pod-policyResources
+    name: policy-test
     namespace: ns
 ports:
 - port: 80
@@ -388,7 +388,7 @@ metadata:
   labels:
     linkerd.io/control-plane-ns: linkerd
     app: policy-test
-  name: pod-policyResources
+  name: policy-test
   namespace: ns
 status:
   phase: Running
@@ -414,7 +414,7 @@ spec:
 apiVersion: policy.linkerd.io/v1beta2
 kind: Server
 metadata:
-  name: srv
+  name: policy-test
   namespace: ns
 spec:
   podSelector:
@@ -426,7 +426,7 @@ spec:
 apiVersion: policy.linkerd.io/v1beta2
 kind: Server
 metadata:
-  name: srv-external-workload
+  name: policy-test-external-workload
   namespace: ns
 spec:
   externalWorkloadSelector:
@@ -436,6 +436,80 @@ spec:
   proxyProtocol: opaque`,
 	}
 
+	policyResourcesNativeSidecar := []string{
+		`
+apiVersion: v1
+kind: Service
+metadata:
+  name: native
+  namespace: ns
+spec:
+  type: LoadBalancer
+  clusterIP: 172.17.12.4
+  ports:
+  - port: 80`,
+		`
+apiVersion: discovery.k8s.io/v1
+kind: EndpointSlice
+metadata:
+  name: native
+  namespace: ns
+  labels:
+    kubernetes.io/service-name: native
+addressType: IPv4
+endpoints:
+- addresses:
+  - 172.17.0.18
+  targetRef:
+    kind: Pod
+    name: native
+    namespace: ns
+ports:
+- port: 80
+  protocol: TCP`,
+		`
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    linkerd.io/control-plane-ns: linkerd
+    app: native
+  name: native
+  namespace: ns
+status:
+  phase: Running
+  conditions:
+  - type: Ready
+    status: "True"
+  podIP: 172.17.0.18
+  podIPs:
+  - ip: 172.17.0.18
+spec:
+  initContainers:
+    - name: linkerd-proxy
+      env:
+      - name: LINKERD2_PROXY_INBOUND_LISTEN_ADDR
+        value: 0.0.0.0:4143
+    - name: app
+      image: nginx
+      ports:
+      - containerPort: 80
+        name: http
+        protocol: TCP`,
+		`
+apiVersion: policy.linkerd.io/v1beta2
+kind: Server
+metadata:
+  name: native
+  namespace: ns
+spec:
+  podSelector:
+    matchLabels:
+      app: native
+  port: 80
+  proxyProtocol: opaque`,
+	}
+
 	hostPortMapping := []string{
 		`
 kind: Pod
@@ -643,6 +717,7 @@ spec:
 	res = append(res, meshedSkippedPodResource...)
 	res = append(res, meshedStatefulSetPodResource...)
 	res = append(res, policyResources...)
+	res = append(res, policyResourcesNativeSidecar...)
 	res = append(res, hostPortMapping...)
 	res = append(res, mirrorServiceResources...)
 	res = append(res, destinationCredentialsResources...)
diff --git a/multicluster/service-mirror/cluster_watcher_mirroring_test.go b/multicluster/service-mirror/cluster_watcher_mirroring_test.go
index 728e9f6f9..378e50778 100644
--- a/multicluster/service-mirror/cluster_watcher_mirroring_test.go
+++ b/multicluster/service-mirror/cluster_watcher_mirroring_test.go
@@ -824,10 +824,14 @@ func TestGcOrphanedServicesMirroring(t *testing.T) {
 			environment: gcTriggered,
 			expectedLocalServices: []*corev1.Service{
 				mirrorService("test-service-1-remote", "test-namespace", "", nil),
+				headlessMirrorService("test-headless-service-remote", "test-namespace", "", nil),
+				endpointMirrorService("pod-0", "test-headless-service-remote", "test-namespace", "", nil),
 			},
 
 			expectedLocalEndpoints: []*corev1.Endpoints{
 				endpoints("test-service-1-remote", "test-namespace", "", "", nil),
+				headlessMirrorEndpoints("test-headless-service-remote", "test-namespace", "pod-0", "", "", nil),
+				endpointMirrorEndpoints("test-headless-service-remote", "test-namespace", "pod-0", "", "", nil),
 			},
 		},
 	} {
diff --git a/multicluster/service-mirror/cluster_watcher_test_util.go b/multicluster/service-mirror/cluster_watcher_test_util.go
index abf1e29ad..2c88fc38e 100644
--- a/multicluster/service-mirror/cluster_watcher_test_util.go
+++ b/multicluster/service-mirror/cluster_watcher_test_util.go
@@ -485,9 +485,14 @@ var gcTriggered = &testEnvironment{
 		endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", nil),
 		mirrorServiceAsYaml("test-service-2-remote", "test-namespace", "", nil),
 		endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", nil),
+		headlessMirrorAsYaml("test-headless-service-remote", "test-namespace", "", nil),
+		endpointMirrorAsYaml("pod-0", "test-headless-service-remote", "test-namespace", "", nil),
+		headlessMirrorEndpointsAsYaml("test-headless-service-remote", "test-namespace", "pod-0", "", "", nil),
+		endpointMirrorEndpointsAsYaml("test-headless-service-remote", "test-namespace", "pod-0", "", "", nil),
 	},
 	remoteResources: []string{
 		remoteServiceAsYaml("test-service-1", "test-namespace", "", nil),
+		remoteHeadlessSvcAsYaml("test-headless-service", "test-namespace", "", nil),
 	},
 	link: multicluster.Link{
 		TargetClusterName: clusterName,
diff --git a/pkg/healthcheck/sidecar_test.go b/pkg/healthcheck/sidecar_test.go
index 7697cc0bd..687c5bd68 100644
--- a/pkg/healthcheck/sidecar_test.go
+++ b/pkg/healthcheck/sidecar_test.go
@@ -44,6 +44,16 @@ func TestHasExistingSidecars(t *testing.T) {
 			},
 			expected: true,
 		},
+		{
+			podSpec: &corev1.PodSpec{
+				InitContainers: []corev1.Container{
+					{
+						Name: k8s.ProxyContainerName,
+					},
+				},
+			},
+			expected: true,
+		},
 		{
 			podSpec: &corev1.PodSpec{
 				Containers: []corev1.Container{
diff --git a/pkg/k8s/api_test.go b/pkg/k8s/api_test.go
index b0d78f24e..d7959e36f 100644
--- a/pkg/k8s/api_test.go
+++ b/pkg/k8s/api_test.go
@@ -27,6 +27,30 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
 status:
   phase: Running
+`,
+		},
+		{
+			desc:     "Pod with proxy native sidecar is running",
+			expected: "Running",
+			pod: `
+apiVersion: v1
+kind: Pod
+metadata:
+  name: emoji
+  namespace: emojivoto
+  labels:
+    app: emoji-svc
+    linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: linkerd-proxy
+      restartPolicy: Always
+status:
+  phase: Running
+  initContainerStatuses:
+  - name: linkerd-proxy
+    ready: true
+    started: true
 `,
 		},
 		{
@@ -165,6 +189,9 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
 status:
   phase: Running
   containerStatuses:
@@ -172,7 +199,8 @@ status:
       running:
         startedAt: 1995-02-10T00:42:42Z
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       terminated:
         exitCode: 0
         reason: Completed
@@ -190,14 +218,21 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
+    containers:
+    - name: bar
 status:
   phase: Running
   containerStatuses:
-  - state:
+  - name: bar
+    state:
       running:
         startedAt: 1995-02-10T00:42:42Z
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       terminated:
         exitCode: 2
 `,
@@ -214,14 +249,21 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
+    containers:
+    - name: bar
 status:
   phase: Running
   containerStatuses:
-  - state:
+  - name: bar
+    state:
       running:
         startedAt: 1995-02-10T00:42:42Z
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       terminated:
         signal: 9
 `,
@@ -238,10 +280,14 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
 status:
   phase: Pending
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       terminated:
         exitCode: 2
         reason: CrashLoopBackOff
@@ -259,17 +305,21 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
 status:
   phase: Pending
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       waiting:
         reason: someReason
 `,
 		},
 		{
 			desc:     "Pod init container is waiting on PodInitializing",
-			expected: "Init:0/0",
+			expected: "Init:0/1",
 			pod: `
 apiVersion: v1
 kind: Pod
@@ -279,10 +329,14 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
 status:
   phase: Pending
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       waiting:
         reason: PodInitializing
 `,
diff --git a/viz/metrics-api/stat_summary_test.go b/viz/metrics-api/stat_summary_test.go
index b689362ec..c7a9206fd 100644
--- a/viz/metrics-api/stat_summary_test.go
+++ b/viz/metrics-api/stat_summary_test.go
@@ -229,10 +229,14 @@ metadata:
   labels:
     app: emoji-svc
     linkerd.io/control-plane-ns: linkerd
+spec:
+    initContainers:
+    - name: foo
 status:
   phase: Pending
   initContainerStatuses:
-  - state:
+  - name: foo
+    state:
       waiting:
         reason: PodInitializing
 `,
@@ -249,7 +253,7 @@ status:
 					TimeWindow: "1m",
 				},
 				expectedResponse: GenStatSummaryResponse("emoji", pkgK8s.Pod, []string{"emojivoto"}, &PodCounts{
-					Status:      "Init:0/0",
+					Status:      "Init:0/1",
 					MeshedPods:  1,
 					RunningPods: 1,
 					FailedPods:  0,
@@ -259,7 +263,8 @@ status:
 								{
 									Error: &pb.PodErrors_PodError_Container{
 										Container: &pb.PodErrors_PodError_ContainerError{
-											Reason: "PodInitializing",
+											Container: "foo",
+											Reason:    "PodInitializing",
 										},
 									},
 								},