<p>I am going through the second module of the <a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/deploy-app/deploy-interactive/" rel="noreferrer">Kubernetes tutorial</a> and I'm confused about when <code>kubectl proxy</code> is necessary. </p>

<p>The reason I'm confused is, in the tutorial it was possible to create a Deployment (i.e. deploy a Docker image as a container in a pod) with the command <code>kubectl run kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --port=8080</code> before we ever setup a proxy. Deploying an image seems like it would require access to the nodes. </p>

<p>The tutorial says that "By default [pods, i.e. groups of containers] are visible from other pods and services within the same kubernetes cluster, but not outside that network." For this reason it instructs us to setup a proxy with <code>kubectl proxy</code> before we attempt to <code>curl</code> a pod directly (e.g. with <code>curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/</code>). Yet we were already able to deploy those pods without a proxy. It seems strange that we could deploy them but not query them.</p>

<p>Similarly, the tutorial also has us setup the proxy before we attempt to get the version using the Kubernetes API with <code>curl http://localhost:8001/version</code> (I believe <code>localhost:8001</code> is the proxy). And yet, earlier we were able to query the version without a proxy using <code>kubectl version</code>, which returns the versions of both <code>kubectl</code> <strong>and</strong> Kubernetes on the master node.</p>

<p>Can anybody shed some light on these apparent contradictions?</p>

<p>When running <code>kubectl</code> commands, the CLI is determining the address of the Kubernetes API server, the CA to verify the server's certificate against (to ensure you're talking to a trusted server and not some man-in-the-middle, say) and your client credentials from the kubeconfig file (to establish an encrypted, authenticated connection to the server with mTLS), which is in <code>~/.kube/config</code> by default.  You can <code>cat</code> that file in the tutorial to see what's in it:</p>

<pre><code>$ cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /root/.minikube/ca.crt
    server: https://172.17.0.26:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /root/.minikube/client.crt
    client-key: /root/.minikube/client.key
</code></pre>

<p>You can do the equivalent of what is happening in the tutorial without the proxy, as follows:</p>

<pre><code>$ curl \
    --cacert /root/.minikube/ca.crt \
    --cert /root/.minikube/client.crt \
    --key /root/.minikube/client.key \
    https://172.17.0.26:8443/api/v1/namespaces/default/pods/$POD_NAME/proxy/
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-6bf84cb898-5gzp5 | v=1
</code></pre>

<p>You can see that after running the proxy command, the resulting curl command you need to run is simpler and more convenient:</p>

<pre><code>curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
</code></pre>

<p>You don't need to bother figuring out the address of the API server or dealing with all these certificates and keys, you just connect to localhost and the local proxy running there handles making the secure, authenticated connection to the API and proxies the response from the API server back to you.</p>

<hr>

<p>Now, most interactions with the Kubernetes API that you need to do can be done directly via <code>kubectl</code> commands, it's rare that you need to <code>curl</code> the API directly.  You see this when you issued the <code>kubectl run</code> or <code>kubectl version</code> command.  In fact, you observed that you later found the version information via a <code>curl</code>, but you don't really need to do that since you can directly run <code>kubectl version</code>.</p>

<p>So you would probably only use <code>kubectl proxy</code> when you need to <code>curl</code> the Kubernetes API directly because there is no native <code>kubectl</code> command that lets you do what you want <em>and</em> when you prefer the convenience of not having that more complicated <code>curl</code> command with all the cert flags, etc.</p>

<hr>

<p>Okay, but when do you really need to <code>curl</code> the API directly?  Again, usually never.  However, one thing the API does in addition to being a RESTful API for creating and deleting Kubernetes resources (pods, deployments, services, pvcs, etc.) is it serves as a proxy into the internal container network.  Out-of-the-box, there's no way to send traffic to the container you ran in the tutorial, except for via the proxy endpoints provided by the Kubernetes API located at <code>/api/v1/namespaces/default/pods/$POD_NAME/proxy/</code>.</p>

<p>The <a href="https://stackoverflow.com/questions/54332972/what-is-the-purpose-of-kubectl-proxy">StackOverflow question</a> that you link to in the comment to your question has an accepted answer that explains several other ways to send traffic to the running containers.  For a real-world application, you're likely to want to use something other than the proxy endpoints on the Kubernetes API server itself, but the proxy endpoints are a quick and easy way to interact over the network with a deployed container, so it might be something you want to do early on in your development lifecycle before setting up more robust and complex infrastructure to handle ingress traffic to your containers.</p>

<hr>

<p>So putting it all together: <strong>when</strong> you have deployed a web application to Kubernetes <strong>and</strong> you would like to send requests to it <strong>and</strong> you don't (yet) want to set up some of the more complex but robust ways to get ingress traffic to your containers, you can use the container network proxy API located at <code>/api/v1/namespaces/default/pods/$POD_NAME/proxy/</code> of the Kubernetes API server.  There is no <code>kubectl</code> command that will hit that endpoint for you, so you have to curl it (or open it in a browser) directly.  <strong>When</strong> you want to <code>curl</code> any Kuberentes server API endpoint directly <strong>and</strong> you don't want to pass a bunch of flags to your <code>curl</code> command, then running <code>kubectl proxy</code> allows you to run simpler <code>curl</code> commands directed at that local proxy that will proxy your requests to the Kubernetes API.</p>

<hr>

<p>One final note, there are two completely different proxies going on here.  One is the local proxy proxying your requests to <em>any</em> endpoint of the Kuberentes API server.  One such (type of) endpoint that the Kubernetes API server has is itself a proxy into the internal network where containers are deployed.  (Further still, there are proxies internal to the container network that make things work under the hood but to keep it simple, there's no need to discuss them in this answer).  Don't get those two proxies confused.</p>
