I have a service (/deployment/pod) running in my Minikube (installed on my Mac) that needs to call an external http service that runs directly on my Mac (i.e. outside Minikube). The domain name of that external service is defined into my Mac /etc/hosts file. Yet, my service within Minikube cannot call that external service. Any idea what I need to configure where? Many thanks. C
Create Endpoints that will forward traffic to your desire external IP address (your local machine). You can directly connect using Endpoints but according to Goole Cloud best practice (doc) is to access it through a Service
Create your Endpoints
kind: Endpoints
apiVersion: v1
metadata:
name: local-ip
subsets:
- addresses:
- ip: 10.240.0.4 # IP of your desire end point
ports:
- port: 27017 # Port that you want to access
Then create you Service
kind: Service
apiVersion: v1
metadata:
name: local-ip
spec:
type: ClusterIP
ports:
- port: 27017
targetPort: 27017
Now you can call external http service using the Service name. In this case local-ip like any other internal service of minikube.
Because your minikube is running on a virtual machine on your laptop , you just need minikube ssh into that machine and enter the address of your external service into the /etc/hosts file of that virtual machine.
Related
I am trying out a possible kubernetes scenario in the local machine minikube cluster. It is to access an internal service that is exposed with ingress in one cluster from another cluster using an ExternalName service. I understand that using an ingress the service will already be accessible within the cluster. As I am trying this out locally using minikube, I am unable to use simultaneously running clusters. Since I just wanted to verify whether it is possible to access an ingress exposed service using ExternName service.
I started the minikube tunnel using minikube tunnel.
I can access the service using http://k8s-yaml-hello.info.
But when I tryout curl k8s-yaml-hello-internal within a running POD, the error that I that is curl: (7) Failed to connect to k8s-yaml-hello-internal port 80 after 1161 ms: Connection refused
Can anyone point me out the issue here? Thanks in advance.
service.yaml
apiVersion: v1
kind: Service
metadata:
name: k8s-yaml-hello
spec:
selector:
app: k8s-yaml-hello
ports:
- port: 3000
targetPort: 3000
ingress.yaml
kind: Ingress
metadata:
name: k8s-yaml-hello-ingress
labels:
name: k8s-yaml-hello-ingress
spec:
rules:
- host: k8s-yaml-hello.info
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: k8s-yaml-hello
port:
number: 3000
externalName.yaml
apiVersion: v1
kind: Service
metadata:
name: k8s-yaml-hello-internal
spec:
ports:
- name: ''
appProtocol: http
protocol: TCP
port: 3000
type: ExternalName
externalName: k8s-yaml-hello.info
etc/hosts
127.0.0.1 k8s-yaml-hello.info
As You are getting the error curl: (7) Failed to connect :
The above error message means that no web-server is running on the specified IP and Port and the specified (or implied) port.
Check using nano /etc/hosts whether the IP and port is pointing to the correct domain or not. If it's not pointing, provide the correct IP and Port.
Refer to this SO for more information.
In Ingress.Yaml use Port 80 and also in service.yaml port should be 80. The service port and Target port should be different As per your yaml it is the same. Change it to 80 and have a try , If you get any errors, post here.
The problem is that minikube tunnel by default binds to the localhost address 127.0.0.1. Every node, machine, vm, container etc. has its own and the same localhost address. It is to reach local services without having to know the ip address of the network interface (the service is running on "myself"). So when k8s-yaml-hello.info resolves to 127.0.0.1 then it points to different service depending on which container you are (just to myself).
To make it work like you want, you first have to find out the ip address of your hosts network interface e.g. with ifconfig. Its name is something like eth0 or en0, depending on your system.
Then you can use the bind-address option of minikube tunnel to bind to that address instead:
minikube tunnel --bind-address=192.168.1.10
With this your service should be reachable from within the container. Please check first with the ip address:
curl http://192.168.1.10
Then make sure name resolution with /etc/hosts works in your container with dig, nslookup, getent hosts or something similar that is available in your container.
I used Cloud Foundry a lot previously, when an app is bind with a service, all the service connection info will be injected into app's environment variables. In Kubernetes world, I think this is same for normal service.
For me, I try to use headless service to describe an external PostgreSQL using below service yaml.
---
kind: "Service"
apiVersion: "v1"
metadata:
name: "postgresql"
spec:
clusterIP: None
ports:
- protocol: "TCP"
port: 5432
targetPort: 5432
nodePort: 0
---
kind: "Endpoints"
apiVersion: "v1"
metadata:
name: "postgresql"
subsets:
-
addresses:
- ip: "10.29.0.123"
ports:
- port: 5432
After deploy the headless service to cluster, the container does not has any environment variables for that, I guess it is because the ClusterIP = None.
The apps can use postgresql:5432 to access by DNS, but I just wonder why Kubernetes does not inject the headless service and its endpoints into the app's environment variable, so the app can get both ip and port from it?
Is there any way to do so?
Thanks!
The Kube-proxy does not manage HeadLess Service, a request made to theses service is only forwarded to the it.
Kubernetes does not really aknowledge theses endpoints (cf https://kubernetes.io/docs/concepts/services-networking/service/#headless-services).
To pass the IP of your postgreSQL DB, you will have to add a environment variable in your deployment, like this:
env:
- name: POSTGRESQL_ADDR
value: "10.29.0.123:5432"
I found the answer to the question. For a headless service, the service info will not be shown in pod's environment variables. If service info is to be available in the environment var, you need to use the service without selectors, simply remove the "clusterIP: None".
The client pod can use both DNS and environment var for external service discovery.
I deployed k3s on a single Ubuntu machine.
Other services are installed on this machine directly (outside k8s), e.g. Redis, Mysql... They are listening loopback address 127.0.0.1 for the security reason.
But the service inside k3s cannot connect to my db. If I change the listening address to 0.0.0.0, the problem will be fixed.
Why? And what is the best practice in this use case?
PS: I use Endpoints to map host service to k8s:
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
ports:
- port: 6379
---
apiVersion: v1
kind: Endpoints
metadata:
name: redis
subsets:
- addresses:
- ip: xxxxx (host's ip)
ports:
- port: 6379
Thanks to #vincent pli, I realized that I confused lo with host itself.
A service listens to lo, does not mean that all services actually running on this machine can access it. If that's what you really want, you must make sure that these two services are in the same virtual network card (lo).
Otherwise, if you want to access through an ip address, the service must listen it. If this address is only inside the LAN, it's still safe. Or use the firewall to enforce more stringent inbounds restrictions.
I'm trying to access a MySQL database hosted inside a docker container on localhost from inside a minikube pod with little success. I tried the solution described Minikube expose MySQL running on localhost as service but to no effect. I have modelled my solution on the service we use on AWS but it does not appear to work with minikube. My service reads as follows
apiVersion: v1
kind: Service
metadata:
name: mysql-db-svc
namespace: external
spec:
type: ExternalName
ExternalName: 172.17.0.2
...where I try to connect to my database from inside a pod using "mysql-db-svc" on port 3306 but to no avail. If I try and CURL the address "mysql-db-svc" from inside a pod it cannot resolve the host name.
Can anybody please advise a frustrated novice?
I'm using ubuntu with Minikube and my database runs outside of minikube inside a docker container and can be accessed from localhost # 172.17.0.2. My Kubernetes service for my external mysql container reads as follows:
kind: Service
apiVersion: v1
metadata:
name: mysql-db-svc
namespace: external
spec:
type: ExternalName
externalName: 10.0.2.2
Then inside my .env for a project my DB_HOST is defined as
mysql-db-svc.external.svc
... the name of the service "mysql-db-svc" followed by its namespace "external" with "svc"
Hope that makes sense.
If I'm not mistaken, you should also create an Endpoint for this service as it's external.
In your case, the Endpoints definition should be as follows:
kind: "Endpoints"
apiVersion: "v1"
metadata:
name: mysql-db-svc
namespace: external
subsets:
- addresses:
- ip: "10.10.1.1"
ports:
port: 3306
You can read about the external sources on Kubernetes Defining a service docs.
This is because your service type is ExternalName which only fits in cloud environment such as AWS and GKE. To run your service locally change the service type to NodePort which will assign a static NodePort between 30000-32767. If you need to assign a static port on your own so that minikube won't pick a random port for you define that in your service definition under ports section like this nodePort: 32002.
And also I don't see any selector that points to your MySQL deployment in your service definition. So include the corresponding selector key pair (e.g. app: mysql-server) in your service definition under spec section. That selector should match with the selector you have defined in MySQL deployment definition.
So your service definition should be like this:
kind: Service
apiVersion: v1
metadata:
name: mysql-db-svc
namespace: external
spec:
selector:
app: mysql-server
ports:
- protocol: TCP
port: 3306
targetPort: 3306
nodePort: 32002
type: NodePort
After you deploy the service you can hit the MySQL service via http://{minikube ip}:32002 Replace {minikube ip} with actual minikube ip.
Or else you can get the access URL for the service with following command
minikube service <SERVICE_NAME> --url
Replace the with actual name of the service. In your case it is mysql-db-svc
I was also facing a similar problem where I needed to connect a POD inside minikube with a SQL Server container on the machine.
I noticed that minikube is itself a container in the local docker environment and during it's setup it creates a local docker network minikube. I connected my local SQL Server container to this minikube docker network using docker network connect minikube <SQL Server Container Name> --ip=<any valid IP on the minikube network subent>.
I was now able to access the local SQL Server container using the IP address on minikube network.
Above solution somehow doesn't work for me. Finally it works below in terraform
resource "kubernetes_service" "host" {
metadata {
name = "minikube-host"
labels = {
app = "minikube-host"
}
namespace = "default"
}
spec {
port {
name = "app"
port = 8082
}
cluster_ip = "None"
}
}
resource "kubernetes_endpoints" "host" {
metadata {
name = "minikube-host"
namespace = "default"
}
subset {
address {
// This ip comes from command: minikube ssh 'grep host.minikube.internal /etc/hosts | cut -f1'
ip = "192.168.65.2"
}
port {
name = "app"
port = 8082
}
}
}
Then I can access the local service (e.g, postgres, or mysql) in my mac with host minikube-host.default.svc.cluster.local from k8s pods.
The plain yaml file version and more details can be found at issue.
The minikube host access host.minikube.internal detail can be found here.
On the other hand, the raw ip address from command minikube ssh 'grep host.minikube.internal /etc/hosts | cut -f1'(e.,g "192.168.65.2"), can be used as the service host directly, instead of 127.0.0.1/localhost at code. And no more above configurations required.
As an addon to #Crou s answer from 2018, In 2022, kubernetes docs say ExternalName takes in a string and not an address. So, in case ExternalName doesn't work, you can also use the simpler option of services-without-selectors
You can also refer to this Google Cloud Tech video for how this services-without-selectors concept works
I've installed minikube to learn kubernetes a bit better.
I've deployed some apps and services which have ip's in a range of 10.x.x.x (private ip). I can expose my services on minikube and visit them in my browser. But I want to use the private IP's and not exposing it.
How can I visit (vpn/proxy wize) private ip's of services in minikube?
Minikube is Kubernetes with only one node and master server running on this node.
It provides the possibility to learn how it works with minimum hardware required.
It's ideal for testing purposes and seamless running on a laptop. Minikube is still software with mature
network stack from Kubernetes. This means that ports are exposed to services and virtually services are
communicating with pods.
To understand what is communicating, let me explain what ClusterIP does - it exposes the service on an internal IP in the cluster. This type makes service only reachable from within the cluster.
Cluster IP you can get by the command:
kubectl get services test_service
So, after you create a new service, you like to establish connections to ClusterAPI.
Basically, there are three ways to connect to backend resource:
1/ use kube-proxy - this proxy reflects services as defined in the Kubernetes API and simple stream TCP and UDP to backend or set of them in advanced configuration. Service cluster IPs and ports are currently found through Docker compatible environment variables specifying ports opened by the service proxy. There is an optional addon that provides cluster DNS for these cluster IPs. The user must create a service with the apiserver API to configure the proxy.
Example shows how can we use nodeselectors to define connection to port 5000 on ClusterIP - config.yaml may consist of:
kind: Service
apiVersion: v1
metadata:
name: jenkins-discovery
namespace: ci spec:
type: ClusterIP
selector:
app: master
ports:
- protocol: TCP
port: 50000
targetPort: 50000
name: slaves
2/ use port forwarding to access application - first check if kubectl command-line tool to communicate with your minikube cluster works, then if true find service port from ClusterIP configuration.
kubectl get svc | grep test_service
Let assume service test_service works on port 5555 so to do port forwarding run the command:
kubectl port-forward pods/test_service 5555:5555
After that, you service will be available on the localhost:5555
3/ If you are familiar with the concept of pods networking you cat declare public ports in the pod’s manifest file. A user can connect to pods network defining manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 8080
When the container is starting with manifest file like above host port TCP port 8080 will be forwarded to pod port 8080.
Please keep in the mind that ClusterIP is the use of a lot of services regarding to proper works of the cluster. I think it is not good practice to deal with ClusterIP as a regular network service - on worst scenario, it breaks a cluster soon, by invalid internal network state of connections.