Port 47010 is already in use when running az connectedk8s proxy in Azure DevOps Pipeline, causing cascading failures in subsequent deployment steps

승록 이 45 Reputation points
2026-06-30T05:03:45.3333333+00:00

Environment

  • CI/CD: Azure DevOps Pipelines
  • Agent: Microsoft-hosted (Ubuntu) (not self-hosted)
  • Agent pool: 10
  • Deployment target: Azure Local AKS (Arc-enabled)
  • Deployment method: az connectedk8s proxy + kubectl / helm
  • Related template: templates/arc-proxy.yml
  • az CLI: connectedk8s extension

Symptom

In the "Setup proxy to local arc" step, az connectedk8s proxy is started in the background (&), but the proxy fails to start and exits immediately with the following error:

ERROR: Port 47010 is already in use. This is an internal port that proxy uses.

Please ensure that this port is open before running 'az connectedk8s proxy'.

Even though the proxy has died, the script does not verify that it is alive and continues, so subsequent steps run against an empty kubeconfig and fail in a cascade:

apiVersion: v1

clusters: null

contexts: null

current-context: ""

error: current-context is not set

Using Kubernetes context: ← KUBE_CONTEXT is set to an empty value

In the next "Test connection to local arc" step, the empty --context / --kube-context causes:

Error: flags cannot be placed before plugin name: --context

Error: "helm list" accepts no arguments

##[error]Bash exited with code '1'.

Analysis (please confirm)

  1. The root error is a local port conflict on 47010/47011; all the errors that follow appear to be secondary effects.
  2. az connectedk8s proxy listens on default port 47011 (+ internal 47010) (confirmed in CLI docs). The port can be changed via the --port option.
  3. Since Microsoft-hosted agents get a fresh VM per job, the "another pipeline occupying the same host" scenario does not apply. Therefore we suspect that the proxy was started more than once within the same job, or a previous proxy from the same job did not terminate.

Questions

  1. Are there any known cases of this port conflict occurring on Microsoft-hosted agents?
  2. Could this deployment job be deploying multiple apps/namespaces (e.g. BIZ, COP) in a single job and including the arc-proxy.yml template more than once? (If so, the second proxy would conflict on 47010.)
  3. Please confirm the recommended resolution direction:
  • (A) Start only one proxy per job, and clean up the proxy process with condition: always() when done.
  • (B) If multiple concurrent proxies are unavoidable, separate them using --port.
  • Add a guard so that the pipeline does not proceed to the next step until the proxy is confirmed to be listening (liveness check).
Azure Arc
Azure Arc

A Microsoft cloud service that enables deployment of Azure services across hybrid and multicloud environments.

0 comments No comments

Answer accepted by question author
Bharath Y P 10,610 Reputation points Microsoft External Staff Moderator
2026-07-01T03:24:18.03+00:00

Hello 승록 이, As per your query you are facing issue during deployment, the step using az connectedk8s proxyfails with a port conflict error: ERROR: Port <port> is already in use

This causes the proxy to terminate, leading to empty kubeconfig, and subsequent failures in kubectl / helm.

The failure occurs because the az connectedk8s proxy command is being invoked multiple times within the same pipeline job, causing port collisions.

  • Azure CLI proxy fails if another instance is already running or if the port is already in use
  • The command supports a default listening port (commonly ~47011) and can be overridden via --port

In your pipeline:

  • Proxy is started in background (&)
  • Previous instance is not terminated
  • Second invocation > port already in use > failure

Your analysis is correct on all points, and I can confirm the specifics:

  • az connectedk8s proxy uses 47011 as the listen port and 47010 as an internal port (hardcoded defaults). A second proxy in the same job collides on these — that's your error.
  • Microsoft-hosted agents get a fresh isolated VM per job, so cross-pipeline contention is impossible. The conflict is intra-job — the proxy is started more than once in one job (very likely because your job loops over multiple apps/namespaces like BIZ/COP and includes arc-proxy.yml per iteration), or a prior proxy in the job didn't exit first.
  • The cascade (current-context is not set → helm flags cannot be placed before plugin name) is all secondary to the dead proxy + missing liveness check.

Recommended fix = both of your options plus a liveness gate:

  1. Start one proxy per job (outside the per-app loop) and kill it in a condition: always() teardown step so nothing is orphaned on retries.
  2. Add a liveness gate: after launching the proxy with &, loop kubectl get ns (with the proxy's --file kubeconfig) until it succeeds, and kill -0 $PID to fail fast if it died. This turns the silent cascade into an immediate, clear failure.
  3. Only if you truly need concurrent proxies in one job, give each a unique --port and its own --file kubeconfig (space the ports out; don't reuse 47010).
  4. Helm hygiene: helm list --kube-context "$CTX" (flag after subcommand) and guard : "${KUBE_CONTEXT:?not set}".

Also: upgrade the connectedk8s extension on the agent (az extension add --upgrade -n connectedk8s). The cleanest design for multi-app deploys is one proxy → loop deployments against that single kubeconfig via --kube-context, which sidesteps the port issue entirely.

Refs:

az connectedk8s proxy https://learn.microsoft.com/cli/azure/connectedk8s#az-connectedk8s-proxy

port 47011 shown at https://learn.microsoft.com/azure/aks/aksarc/aks-create-clusters-cli#connect-to-the-kubernetes-cluster

Hope this helps! thank you

Was this answer helpful?

1 person found this answer helpful.
0 comments No comments

Answer accepted by question author
Alex Burlachenko 25,285 Reputation points MVP Volunteer Moderator
2026-06-30T09:52:49.3566667+00:00

hi 승록 이 & thx for sharing urs issue here at Q&A portal,

Yep, ur analysis is right. The first real failure is the az connectedk8s proxy port conflict. The kubeconfig/context/helm errors after that are just fallout bc the proxy never started.

On Microsoft-hosted agents, a conflict from another customer pipeline is unlikely. More likely the same job starts the Arc proxy more than once, or a previous background proxy process in the same job didn’t get killed.

Best fix: start one proxy per job, store its PID, wait until it’s actually listening, and always clean it up at the end.

az connectedk8s proxy \

--name <cluster-name> \

--resource-group <rg> \

--port 47011 &

PROXY_PID=$!

for i in {1..30}; do

if nc -z 127.0.0.1 47011; then

echo 'Arc proxy is ready'

break

fi

sleep 2

done

if ! kill -0 $PROXY_PID 2>/dev/null; then

echo 'Arc proxy failed to start'

exit 1

fi

Then cleanup in a final step with condition: always():

pkill -f 'az connectedk8s proxy' || true

If u really need multiple proxies in the same job, give each one a different --port. But simpler is better here: one proxy per job, reuse the kubeconfig/context for all kubectl/helm calls.

MS docs

https://learn.microsoft.com/en-us/cli/azure/connectedk8s?view=azure-cli-latest#az-connectedk8s-proxy

https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/cluster-connect

Also add a hard guard if kubeconfig has no current-context, stop immediately. Don’t let helm fail 6 steps later like a murder mystery.

rgds,

Alex

&

If my answer was helpful pls mark it and additional thx if u follow me at Q&A portal

and at my blog https://ctrlaltdel.blog/

 

Was this answer helpful?

1 person found this answer helpful.

1 additional answer

Sort by: Oldest
  1. 승록 이 45 Reputation points
    2026-07-02T06:58:28.01+00:00

    Thank you so much for the detailed answer — I really appreciate you taking the time to explain this. 🙏

    I wanted to follow up and share my test results in case it helps others hitting the same issue: even after applying the suggested approach, reclaiming the port is still difficult because of a detached child process.

    When I kill the parent az connectedk8s proxy command:

    pkill -f 'az connectedk8s proxy' || true

    the underlying arcProxy_linux_ listener survives and keeps holding the ports:

    ss -ltnp 2>/dev/null | grep -E ':4701'

    LISTEN 0 4096 127.0.0.1:47010 0.0.0.0:* users:(("arcProxy_linux_",pid=117936,fd=4))

    LISTEN 0 4096 127.0.0.1:47011 0.0.0.0:* users:(("arcProxy_linux_",pid=117936,fd=8))

    So killing the az wrapper process alone doesn't release the ports — the spawned arcProxy_linux_ binary is what actually owns them, and it isn't matched by pkill -f 'az connectedk8s proxy' or pkill -f connectedk8s.

    What worked for me was targeting the child process directly, by name or by the PID owning the port:

    pkill -f arcProxy_linux_

    or, using the PID from ss output above:

    kill 117936

    Just wanted to document this so anyone else running into stuck ports knows to kill the arcProxy_linux_ child, not just the az command. Thanks again for the help!

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.