I am going through the second module of the Kubernetes tutorial and I'm confused about when kubectl proxy
is necessary.
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 kubectl run kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --port=8080
before we ever setup a proxy. Deploying an image seems like it would require access to the nodes.
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 kubectl proxy
before we attempt to curl
a pod directly (e.g. with curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
). Yet we were already able to deploy those pods without a proxy. It seems strange that we could deploy them but not query them.
Similarly, the tutorial also has us setup the proxy before we attempt to get the version using the Kubernetes API with curl http://localhost:8001/version
(I believe localhost:8001
is the proxy). And yet, earlier we were able to query the version without a proxy using kubectl version
, which returns the versions of both kubectl
and Kubernetes on the master node.
Can anybody shed some light on these apparent contradictions?
When the proxy server is running, you can explore the kubernetes API using curl, wget, or a browser.
Get the API versions:
curl http://localhost:8080/api/
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.2.15:8443"
}
]
}
Get a list of pods:
curl http://localhost:8080/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/default/pods",
"resourceVersion": "33074"
},
"items": [
{
"metadata": {
"name": "kubernetes-bootcamp-2321272333-ix8pt",
"generateName": "kubernetes-bootcamp-2321272333-",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/pods/kubernetes-bootcamp-2321272333-ix8pt",
"uid": "ba21457c-6b1d-11e6-85f7-1ef9f1dab92b",
"resourceVersion": "33003",
"creationTimestamp": "2016-08-25T23:43:30Z",
"labels": {
"pod-template-hash": "2321272333",
"run": "kubernetes-bootcamp"
},
...
}
Also, you can hit some k8s-service to check if service if actually connected to desired deployment/pods
http://localhost:8001/api/v1/namespaces/<namespace-name>/services/<service-name>:<service-port>/proxy/
I usually use kubectl proxy to query API Server. as given below
kubectl proxy --port=8001 &
curl 127.0.0.1:8001/version
curl 127.0.0.1:8001/metrics
curl 127.0.0.1:8001/api/v1/namespaces
curl 127.0.0.1:8001/api/v1/namespaces/kube-system
curl 127.0.0.1:8001/api/v1/namespaces/kube-system/services
curl 127.0.0.1:8001/api/v1/namespaces/kube-system/services/kube-dns
when is kubectl proxy necessary?
When applications need to communicate to the API Server without implementing the security logic and cluster configuration within the applications.
It prevents the client applications of:
Not to confuse the kubectl proxy
with other proxies listed on the docs
When running kubectl
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 ~/.kube/config
by default. You can cat
that file in the tutorial to see what's in it:
$ 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
You can do the equivalent of what is happening in the tutorial without the proxy, as follows:
$ 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
You can see that after running the proxy command, the resulting curl command you need to run is simpler and more convenient:
curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
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.
Now, most interactions with the Kubernetes API that you need to do can be done directly via kubectl
commands, it's rare that you need to curl
the API directly. You see this when you issued the kubectl run
or kubectl version
command. In fact, you observed that you later found the version information via a curl
, but you don't really need to do that since you can directly run kubectl version
.
So you would probably only use kubectl proxy
when you need to curl
the Kubernetes API directly because there is no native kubectl
command that lets you do what you want and when you prefer the convenience of not having that more complicated curl
command with all the cert flags, etc.
Okay, but when do you really need to curl
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 /api/v1/namespaces/default/pods/$POD_NAME/proxy/
.
The StackOverflow question 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.
So putting it all together: when you have deployed a web application to Kubernetes and you would like to send requests to it and 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 /api/v1/namespaces/default/pods/$POD_NAME/proxy/
of the Kubernetes API server. There is no kubectl
command that will hit that endpoint for you, so you have to curl it (or open it in a browser) directly. When you want to curl
any Kuberentes server API endpoint directly and you don't want to pass a bunch of flags to your curl
command, then running kubectl proxy
allows you to run simpler curl
commands directed at that local proxy that will proxy your requests to the Kubernetes API.
One final note, there are two completely different proxies going on here. One is the local proxy proxying your requests to any 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.