I'm working locally (within Docker for Mac) on a Kubernetes cluster that will eventually be deployed to the cloud. We plan to use a database service in that environment. To simulate that, I'd like to have the services in the cluster connect to a database running outside the cluster on my laptop.
Can I do that? Here's what I thought I'd try.
Define a Service with type: ExternalName and externalName: somedb.local
Add 127.0.0.1 somedb.local to /etc/hosts on the laptop
Is that correct? Is there a better way?
After talking with some colleagues, I found a solution.
In Docker for Mac, host.docker.internal points to the host machine, and that lets me connect to the db running there, even from containers running in the K8s cluster.
You may have a Service pointing to an address out of your SDN, by creating an Endpoint object with matching name.
----
apiVersion: v1
kind: Service
metadata:
name: external-db
namespace: my-namespace
spec:
ports:
- name: exporter-3306
port: 3306
selector:
name: external-db
---
apiVersion: v1
kind: Endpoints
metadata:
name: external-db
namespace: my-namespace
subsets:
- addresses:
- ip: 10.42.253.110
ports:
- name: exporter-3306
port: 3306
You may add hosts overrides in your Deployment definition:
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
...
hostAliases:
- ip: 10.42.253.110
hostnames:
- external-db
It seems the Kubernetes docs provide an instruction on how to achieve this.
https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors
A note says endpoint IPs must not be: loopback (127.0.0.0/8 for IPv4, ::1/128 for IPv6), or link-local (169.254.0.0/16 and 224.0.0.0/24 for IPv4, fe80::/64 for IPv6).
Related
I have a Service that is deployed as a StatefulSet in one Kubernetes cluster, and with static IPs in another cluster.
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: statefulset-name
spec:
...
I want to use the same host to access the service in both clusters. I also need to have one hostname per endpoint (e.g the pod and the static IP).
Given that I get <pod>.<statefulset>.<namespace> in the Kubernetes-native case, how can I expose my static IPs with the same hosts?
A StatefulSet will eventually generate a Service for the Pod. Digging into the source code I found that the pod subdomain will map to the address hostname in the Endpoints resource.
Assuming that you have 2 replicas in the first case and 2 static IPs in the second one, you need to create the Service and Endpoints as such:
kind: Service
apiVersion: v1
metadata:
name: same-as-statefulset
spec:
clusterIP: None
ports:
- port: 80
targetPort: 80
---
kind: Endpoints
apiVersion: v1
metadata:
name: same-as-statefulset
subsets:
- addresses:
- ip: 10.192.255.0
hostname: same-as-pod-0
- ip: 10.192.255.1
hostname: same-as-pod-1
ports:
- port: 80
I have a kubernetes (v1.18.6) with 1 service (loadbalancer), 2 pods in a develoment:
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: app
ports:
- protocol: "TCP"
port: 6000
targetPort: 5000
type: LoadBalancer
A network policy to access Intenert (it is necesary for me):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: internet-access
spec:
podSelector:
matchLabels:
networking/allow-internet-access: "true"
policyTypes:
- Ingress
- Egress
ingress:
- {}
Deployment config file
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
spec:
progressDeadlineSeconds: 120
selector:
matchLabels:
app: app
replicas: 2
template:
metadata:
labels:
app: app
spec:
imagePullSecrets:
- name: myregistrykey
containers:
- name: app
image: app
imagePullPolicy: Always
ports:
- containerPort: 5000
It is working correctly. But now, I want to connect this imagen to an external database (in another network only access by internet). For this proposition I use this service:
apiVersion: v1
kind: Service
metadata:
name: postgresql
spec:
clusterIP: None
ports:
- port: 25060
---
apiVersion: v1
kind: Endpoints
metadata:
name: postgresql
subsets:
- addresses:
- ip: 206............
ports:
- port: 25060
name: postgresql
It is all the services:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app-service LoadBalancer 10.245.134.137 206........... 6000:31726/TCP 2d4h
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 3d7h
postgresql ClusterIP None <none> 25060/TCP 19h
But when I try to connect I receive a timeout error of the database, like can't connect to the database.
I have an internet connection in the image.
I find the solution, the problem was the rules of inbound of the database. I must add the IP of Kubernetes.
Thx.
Here is what worked for me:
Define a service , but set clusterIP: None , so no endpooint is created.
And then create an endpoint yourself with the SAME NAME as your service and set the IP and port of your db.
In your example , you have a type in your endpoint: the name of your endpoint is postgresql not postgresSql.
My example:
---
service.yaml
kind: Service
apiVersion: v1
metadata:
name: backend-mobile-db-service
spec:
clusterIP: None
ports:
- port: 5984
---
kind: Endpoints
apiVersion: v1
metadata:
name: backend-mobile-db-service
subsets:
- addresses:
- ip: 192.168.1.50
ports:
- port: 5984
name: backend-mobile-db-service
For better visibility I am placing the answer OP mentioned in question:
I find the solution, the problem was the rules of inbound of the database. I must add the IP of Kubernetes
The service definition should be corrected. Default service type is clusterIP which doesn't work for external database. You need to update the service type as given below
type: ExternalName
also ensure that service name and the endpoint name should match. it is different in your yaml. please check
If I understand correctly, you have your cluster with application on Digital Ocean cloud and your PostgreSQL is outside this cluster.
In your Application Deployment <> application service you have used services with selectors so you didn't need to create Endpoints manually.
In your external database service you have used services without selectors so you had to create Endpoint manually.
As database is external service, using clusterIP: None is pointless as it will try to match pods inside the cluster. I guess you added it as you read in this docs.
Last thing is that in Endpoint you set ip: 206... which is the same as application service LoadBalancer ip?
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app-service LoadBalancer 10.245.134.137 206........... 6000:31726/TCP 2d4h
subsets:
- addresses:
- ip: 206............
It is only a part of information so I am guessing. However in this part you should provide IP of desired database, not your application Loadbalancer IP.
Now based on scenario you can connect:
Database outside cluster with IP address
Remotely hosted database with URI
Remotely hosted database with URI and port remapping
Detailed information about above scenarios you can find in Kubernetes best practices: mapping external services
Based on your current config I assume you want to use scenario 1.
If this database and cluster are somewhere in cloud you could use internal Database IP. If not you should provide IP of machine where this Database is hosted.
You can also read Kubernetes Access External Services article.
Please let me know if you will still have issue after IP change
I can't access to public IP assigned by MetalLB load Balancer
I created a Kubernetes cluster in Contabo. Its 1 master and 2 workers. Each one has its own public IP.
I did it with kubeadm + flannel. Later I did install MetalLB to use Load Balancing.
I used this manifest for installing nginx:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
It works, pods are running. I see the external IP adress after:
kubectl get services
From each node/host I can curl to that ip and port and I can get nginx's:
<h1>Welcome to nginx!</h1>
So far, so good. BUT:
What I still miss is to access to that service (nginx) from my computer.
I can try to access to each node (master + 2 slaves) by their IP:PORT and nothing happens. The final goal is to have a domain that access to that service but I can't guess witch IP should I use.
What I'm missing?
Should MetalLB just expose my 3 possible IPs?
Should I add something else on each server as a reverse proxy?
I'm asking this here because all articles/tutorials on baremetal/VPS (non aws,GKE, etc...) do this on a kube on localhost and miss this basic issue.
Thanks.
I am having the very same hardware layout:
a 3-Nodes Kubernetes Cluster - here with the 3 IPs:
| 123.223.149.27
| 22.36.211.68
| 192.77.11.164 |
running on (different) VPS-Providers (connected to a running cluster(via JOIN), of course)
Target: "expose" the nginx via metalLB, so I can access my web-app from outside the cluster via browser via the IP of one of my VPS'
Problem: I do not have a "range of IPs" I could declare for the metallb
Steps done:
create one .yaml file for the Loadbalancer, the kindservicetypeloadbalancer.yaml
create one .yaml file for the ConfigMap, containing the IPs of the 3 nodes, the kindconfigmap.yaml
``
### start of the kindservicetypeloadbalancer.yaml
### for ensuring a unique name: loadbalancer name nginxloady
apiVersion: v1
kind: Service
metadata:
name: nginxloady
annotations:
metallb.universe.tf/address-pool: production-public-ips
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx
type: LoadBalancer
``
below, the second .yaml file to be added to the Cluster:
# start of the kindconfigmap.yaml
## info: the "production-public-ips" can be found
## within the annotations-sector of the kind: Service type: loadbalancer / the kindservicetypeloadbalancer.yaml
## as well... ...namespace: metallb-system & protocol: layer2
## note: as you can see, I added a /32 after every of my node-IPs
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: production-public-ips
protocol: layer2
addresses:
- 123.223.149.27/32
- 22.36.211.68/32
- 192.77.11.164/32
``
add the LoadBalancer:
kubectl apply -f kindservicetypeloadbalancer.yaml
add the ConfigMap:
kubectl apply -f kindconfigmap.yaml
Check the status of the namespace ( "n" ) metallb-system:
kubectl describe pods -n metallb-system
PS:
actually it is all there:
https://metallb.universe.tf/installation/
and here:
https://metallb.universe.tf/usage/#requesting-specific-ips
What you are missing is a routing policy
Your external IP addresses must belong to the same network as your nodes or instead of that you can add a route to your external address at your default gateway level and use a static NAT for each address
I have a cluster in aws and using kubernetes.
I have an app running on a machine (vm) in the same network as the cluster
in my browser i can type http://ipaddress:port/status and i get a response
In my pod i can ping the ip address and i get a response but if i do wget://ipaddress:port/status it doesn't connect.
I have tried some things but not able to succeed.
How do i get the pod in the cluster to be be able to open this url, what do I need to do?
You can integrate external services within kubernetes.
endpoint.yaml
kind: Endpoints
apiVersion: v1
metadata:
name: external-ip-database
subsets:
- addresses:
- ip: 192.168.0.1
ports:
- port: 3306
service.yaml
apiVersion: v1
kind: Service
metadata:
name: database
spec:
ports:
- port: 1433
targetPort: 1433
protocol: TCP
---
# Because this service has no selector, the corresponding Endpoints
# object will not be created. You can manually map the service to
# your own specific endpoints:
kind: Endpoints
apiVersion: v1
metadata:
name: database
subsets:
- addresses:
- ip: "192.168.1.103"
ports:
- port: 1433
I have minikube version v0.17.1 running on my machine. I want to simulate the environment I will have in AWS, where my MySQL instance will be outside of my Kubernetes cluster.
Basically, how can I expose my local MySQL instance running on my machine to the Kubernetes cluster running via minikube?
Kubernetes allows you to create a service without selector, and cluster will not create related endpoint for this service, this feature is usually used to proxy a legacy component or an outside component.
Create a service without selector
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 1443
targetPort: <YOUR_MYSQL_PORT>
Create a relative Endpoint object
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: <YOUR_MYSQL_ADDR>
ports:
- port: <YOUR_MYSQL_PORT>
Get service IP
$ kubectl get svc my-service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service <SERVICE_IP> <none> 1443/TCP 18m
Access your MYSQL from service <SERVICE_IP>:1443 or my-service:1443
As of minikube 1.10, there is a special hostname host.minikube.internal that resolves to the host running the minikube VM or container. You can then configure this hostname in your pod's environment variables or the ConfigMap that defines the relevant settings.
Option 1 - use a headless service without selectors
Because this service has no selector, the corresponding Endpoints object will not be created. You can manually map the service to your own specific endpoints (See doc).
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080
---
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.0.2.2
ports:
- port: 8080
Option 2 - use ExternalName service
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
type: ExternalName
externalName: minikube.host
The only caveat is that it needs to be able to resolve minikube.host. Simply add this line to the etc/hosts file should do it.
10.0.2.2 minikube.host
ExternalName doesn't support port mapping at the moment.
Another note: The IP 10.0.2.2 is known to work with Virtual Box only (see SO).
For xhyve, try replacing that with 192.168.99.1 (see GitHub issue and issue). A demo GitHub.
Just a reminder, if on Windows, open your firewall.