Access to Mongodb in Kubernetes - mongodb

I created a Mongodb service according to the Kubernetes tutorial.
Now my question is how do I gain access to the database itself, with a client like Robomongo or similar clients? Just for making backups or exploring what data have been entered.
The mongo-pod and service only have an internal endpoint, and a single mount.
Is there any way to safely access this instance with no public endpoint?
Internally URI is mongo:27***

You can use kubectl port-forward mypod 27017:27017 and then just connect your mongodb client to localhost:27017.
If you want to stop, just hit Ctrl+C on the same cmd window to stop the process.

The kubernetes cmd-line tool provides this functionality as #ainlolcat stated
kubectl get pods
Retrieves the pod names currently running and with:
kubectl exec -i mongo-controller-* bash
you get a basic bash, which lets you execute
mongo
to get into the database to create dumps, and so on. The bash is very basic and has no features like completion and so on. I have not found a solution for better shell but it does the job

when you create a service in kubernetes you give it a name, say for example "mymongo". After the service is created then
The DNS service of kubernetes (by default is on) will ensure that any pod can discover this servixe simply by its name. so you can set your uri like
uri: mongodb://**mymongo**:27017/mong
In addition the service IP and port will be set as environment variables at the running pod.
MYMONGO_SERVICE_HOST
MYMONGO_SERVICE_PORT
I have in fact wrote a blog that show a step by step example of an app with nodejs web server and mongo that can explain further
http://codefresh.io/blog/kubernetes-snowboarding-everything-intro-kubernetes/
feedback welcome!

Answer from #grchallenge is correct but it is deprecated as of in 2021
All new comers please use
kubectl exec mongo-pod-name -i -- bash

Related

How to connect to MongoDB replicaset on Kubernetes

I have deployed bitnami's Mongodb helm chart in the replicaset mode on a K8s cluster, using this minimal config (for now):
architecture: replicaset
auth:
enabled: false
Now I have two replicas (one primary and one secondary, allegedly) and an arbiter (no data, just voting rights). Additionally, I got two services: appname-mongodb-headless, appname-mongodb-arbiter-headless. However, the MongoDB docs specify the connection string in case of replicaset installations as mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017,mongodb2.example.com:27017/?replicaSet=myRepl.
I can use mongodb://appname-mongodb-headless:27017 to connect to the db, but is it the "real experience" (i.e. highly available, etc)?
Do I need to specify the replicaset name (as in the example) and how do I find out what it is?
If the current services are enough, do I need to include the arbiter in the connection string?
Or should I create separate services for each replica and build the recommended connection string?
externalAccess:
enabled: true
autoDiscovery:
enabled: true
I will eventually enable authentication after sorting out this part of the connection. What is this replicaSetKey ("Key used for authentication in the replicaset"), and where do I use it?
I found this similar question. It is for another chart, but it suggests me that some combination of the headless services should be enough. Nonetheless, it doesn't answer all aspects of my question.
The headless service serves as an entrypoint for you to connect to MongoDB, without the need to specify a pod address. Kubernetes will balance the load and serve it to a specific pod.
If you wish to connect to MongoDB, using externalAccess.enabled, you should take a look at the Helm deployment notes that are shown when you deploy the chart. You can read them post-deployment by executing the helm get notes MY-RELEASE command.
For instance, in my case, it shows this, though depending on the deployment options it would show something else:
To connect to your database, create a MongoDB® client container:
kubectl run --namespace default mbmongo-mongodb-client --rm --tty -i --restart='Never' --env="MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD" --image docker.io/bitnami/mongodb:4.4.8-debian-10-r24 --command -- bash
Then, run the following command:
mongo admin --host "mbmongo-mongodb-0.mbmongo-mongodb-headless.default.svc.cluster.local:27017,mbmongo-mongodb-1.mbmongo-mongodb-headless.default.svc.cluster.local:27017,mbmongo-mongodb-2.mbmongo-mongodb-headless.default.svc.cluster.local:27017" --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD
To connect to your database nodes from outside, you need to add both primary and secondary nodes hostnames/IPs to your Mongo client. To obtain them, follow the instructions below:
MongoDB® nodes domain: you can reach MongoDB® nodes on any of the K8s nodes external IPs.
kubectl get nodes -o wide
MongoDB® nodes port: You will have a different node port for each MongoDB® node. You can get the list of configured node ports using the command below:
echo "$(kubectl get svc --namespace default -l "app.kubernetes.io/name=mongodb,app.kubernetes.io/instance=mbmongo,app.kubernetes.io/component=mongodb,pod" -o jsonpath='{.items[*].spec.ports[0].nodePort}' | tr ' ' '\n')"
From the notes you can see this line:
To connect to your database nodes from outside, you need to add both primary and secondary nodes hostnames/IPs to your Mongo client
That means that you do need to specify all primary/secondary node names, but not arbiters.
As for replicaSetKey, it refers to the contents of the MongoDB keyFile to use for internal cluster replication, so it can happen in a secure manner. You can read more about it here.
If you continue finding issues, I suggest you create an issue in the bitnami/charts repository.
Adding to Marcos' answer, there is another URI format called DNS Seed List Connection Format from 3.6+ which you can use with a single host name of your headless service and still take advantage of the replicaset.
mongodb+srv://server.example.com/
It is described here: https://docs.mongodb.com/manual/reference/connection-string/#dns-seed-list-connection-format

How to use proxy with Kubernetes

I'm new with Kubernetes and I'm just starting out. My Kubernetes server is running at: 127.0.0.1:3000 and I want it to run at 0.0.0.0:3000. I tried to use
kube proxy --bind-address"0.0.0.0"
but I'm getting a
kube: command not found
error.
I've also tried to use
kubectl proxy --address="0.0.0.0"
although it says:
Starting to serve on [::]:8001
but I'm unable to write any commands after that. Is there any way that enables me to use "0.0.0.0" as my IP address and I'm also able to write commands after binding it to the said IP address? Can i change something in my yaml file or kubeconfig file or add a new file for this purpose that enables me to do so?
Use --port argument to change the port
kubectl proxy --address=0.0.0.0 --port=8001
Starting to serve on [::]:8001
Open another terminal to run commands against ip:8001
Another mistake would be to issue "kube" Command, as you maybe wanted to use "kubectl".
As #confused genius said above, you have to use.
kubectl proxy --address=0.0.0.0 --port=3000
Starting to serve on [::]:3000

How to get Kubernetes cluster name from K8s API using client-go

How to get Kubernetes cluster name from K8s API mentions that
curl http://metadata/computeMetadata/v1/instance/attributes/cluster-name -H "Metadata-Flavor: Google"
(from within the cluster), or
kubectl run curl --rm --restart=Never -it --image=appropriate/curl -- -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name
(from outside the cluster), can be used to retrieve the cluster name. That works.
Is there a way to perform the same programmatically using the k8s client-go library? Maybe using the RESTClient()? I've tried but kept getting the server could not find the requested resource.
UPDATE
What I'm trying to do is to get the cluster-name from an app that runs either in a local computer or within a k8s cluster. the k8s client-go allows to initialise the clientset via in cluster or out of cluster authentication.
With the two commands mentioned at the top that is achievable. I was wondering if there was a way from the client-go library to achieve the same, instead of having to do kubectl or curl depending on where the service is run from.
The data that you're looking for (name of the cluster) is available at GCP level. The name itself is a resource within GKE, not Kubernetes. This means that this specific information is not available using the client-go.
So in order to get this data, you can use the Google Cloud Client Libraries for Go, designed to interact with GCP.
As a starting point, you can consult this document.
First you have to download the container package:
➜ go get google.golang.org/api/container/v1
Before you will launch you code you will have authenticate to fetch the data:
Google has a very good document how to achieve that.
Basically you have generate a ServiceAccount key and pass it in GOOGLE_APPLICATION_CREDENTIALS environment:
➜ export GOOGLE_APPLICATION_CREDENTIALS=sakey.json
Regarding the information that you want, you can fetch the cluster information (including name) following this example.
Once you do do this you can launch your application like this:
➜ go run main.go -project <google_project_name> -zone us-central1-a
And the result would be information about your cluster:
Cluster "tom" (RUNNING) master_version: v1.14.10-gke.17 -> Pool "default-pool" (RUNNING) machineType=n1-standard-2 node_version=v1.14.10-gke.17 autoscaling=false%
Also it is worth mentioning that if you run this command:
curl http://metadata/computeMetadata/v1/instance/attributes/cluster-name -H "Metadata-Flavor: Google"
You are also interacting with the GCP APIs and can go unauthenticated as long as it's run within a GCE machine/GKE cluster. This provided automatic authentication.
You can read more about it under google`s Storing and retrieving instance metadata document.
Finally, one great advantage of doing this with the Cloud Client Libraries, is that it can be launched externally (as long as it's authenticated) or internally within pods in a deployment.
Let me know if it helps.
If you're running inside GKE, you can get the cluster name through the instance attributes: https://pkg.go.dev/cloud.google.com/go/compute/metadata#InstanceAttributeValue
More specifically, the following should give you the cluster name:
metadata.InstanceAttributeValue("cluster-name")
The example shared by Thomas lists all the clusters in your project, which may not be very helpful if you just want to query the name of the GKE cluster hosting your pod.

k8s API server is down due to misconfiguration, how to bring it up again?

I was trying to add a command line flag to the API server. In my setup, it was running as a daemon set inside the k8s cluster so I got the daemon set manifest using kubectl, updated it, and executed kubectl apply -f apiserver.yaml (I know, this was not a good idea).
Of course, the new yaml file I wrote had an error so the API server is not starting anymore and I can't use kubectl to update it. I have an ssh connection to the node where it was running and I can see how the kubelet is trying to run the apiserver pod every few seconds with the ill-formed command. I am trying to configure the kubelet service to use the correct api-server command but am not being able to do so.
Any ideas?
The API server definition usually lives in /etc/kubernetes/manifests - Edit the configuration there rather than at the API level

Get the nodes/pods information using cluster name or context name when we have multiple configs

I'm trying to fetch nodes list via ansible playbook using a context name. but its not working
my playbook:
getnodes.yaml
- name: "get nodes"
hosts: kubernetes
tasks:
- name: "nodes"
command: "kubectl get nodes --context='contextname'"
I do have multiple clusters in config file. I need to either specify cluster name or context name and get the nodes list or to perform any activity on a particular cluster
As far as I understand you when you run the command kubectl get nodes --context='contextname' directly on your master node, everything works fine, right ? And it fails only when you run it as a part of your ansible playbook against the master node ? What errors do you get ?
Yes that's correct. i'm able to execute from command line
"The connection to the server localhost:8080 was refused - did you
specify the right host or port?"
Are you sure it is available on the same host as you run your ansible playbook ? I mean your Kubernetes master node, on which you have kubectl binary installed ? My guess is that it is not and even if it is on the same host you'll not be able to connect to it using localhost:8080.
Look. You're not using here any particular Ansible module specific to manage Kubernetes cluster like this one, which you run directly against the API server and you need to provide its valid URL. Instead here you are just using simple command module which doesn't care what command you want to run as long as you provide a valid hostname with ssh access and Python installed.
In this case your Ansible simply tries to ssh to your Kubernetes master node and execute the shell command you passed to it:
kubectl get nodes --context='contextname'
I really doubt that your ssh server listens on port 8080.
If you run your ansible playbook on same host you can run your kubectl commands there are much easier solutions in Ansible for such cases like:
local_action or delegate_to: localhost statements in your task or more globally connection: local
More details on usage of all above mentioned statements in your Ansible plays you can find in Ansible docs and in this article.
I hope it will help you.