cclloyd
cclloyd

Reputation: 9225

Kubernetes Ingress to External Service?

Say I have a service that isn't hosted on Kubernetes. I also have an ingress controller and cert-manager set up on my kubernetes cluster.

Because it's so much simpler and easy to use kubernetes ingress to control access to services, I wanted to have a kubernetes ingress that points to a non-kubernetes service.

For example, I have a service that's hosted at https://10.0.40.1:5678 (ssl required, but self signed certificate) and want to access at service.example.com.

Upvotes: 59

Views: 62029

Answers (6)

Niokolay Dimitrov
Niokolay Dimitrov

Reputation: 1

Maybe also add "nsm.nginx.com/internal-route: "true" as mentioned in https://docs.nginx.com/mesh/tutorials/kic/egress-walkthrough/ or https://www.f5.com/company/blog/nginx/how-to-simplify-kubernetes-ingress-egress-traffic-management as to expose the route only internally.

Upvotes: 0

Anton Kostenko
Anton Kostenko

Reputation: 9033

You can do it by manual creation of Service and Endpoint objects for your external server.

Objects will looks like that:

apiVersion: v1
kind: Service
metadata:
  name: external-ip
spec:
  ports:
  - name: app
    port: 80
    protocol: TCP
    targetPort: 5678
  clusterIP: None
  type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-ip
subsets:
- addresses:
  - ip: 10.0.40.1
  ports:
  - name: app
    port: 5678
    protocol: TCP

Also, it is possible to use an EndpointSlice object instead of Endpoints.

Then, you can create an Ingress object which will point to Service external-ip with port 80:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: external-service
spec:
  rules:
  - host: service.example.com
    http:
      paths:
      - backend:
          serviceName: external-ip
          servicePort: 80
        path: /

Upvotes: 64

secavfr
secavfr

Reputation: 963

Here's a working copy of my configuration for Kubernetes 1.26 with the EndpointSlice approach and NGINX Ingress 1.7 :

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
  - name: https
    port: 5678
    targetPort: 5678
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: external-service-1
  labels:
    kubernetes.io/service-name: external-service
addressType: IPv4
ports:
  - name: ''
    appProtocol: http
    protocol: TCP
    port: 5678
endpoints:
  - addresses:
      - "10.0.40.1"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: external-service
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  rules:
  - host: service.example.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: external-service
            port:
              number: 5678

Upvotes: 4

Moulick
Moulick

Reputation: 4812

So I got this working using ingress-nginx to proxy an managed external service over a non-standard port

apiVersion: v1
kind: Service
metadata:
  name: external-service-expose
  namespace: default
spec:
  type: ExternalName
  externalName: <external-service> # eg example.example.com
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: external-service-expose
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" #important
spec:
  rules:
  - host: <some-host-on-your-side> # eg external-service.yourdomain.com
    http:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: external-service
            port:
              number: <port of external service> # eg 4589
  tls:
  - hosts:
    - external-service.yourdomain.com
    secretName: <tls secret for your domain>

of-course you need to make sure that the managed url is reachable from inside the cluster, a simple check can be done by launching a debug pod and doing

curl -v https://example.example.com:4589

Upvotes: 20

Ralph
Ralph

Reputation: 4868

I just want to update @Moulick answer here according to Kubernetes version v1.21.1, as for ingress the configuration has changed a little bit. In my example I am using Let's Encrypt for my nginx controller:

apiVersion: v1
kind: Service
metadata:
  name: external-service
  namespace: default
spec:
  type: ExternalName
  externalName: <some-host-on-your-side> eg managed.yourdomain.com
  ports:
  - port: <port of external service> eg 4589

---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: external-service
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" #important
spec:
  tls:
  - hosts:
    - <some-host-on-your-side> eg managed.yourdomain.com
    secretName: tls-external-service
  rules:
  - host: <some-host-on-your-side> eg managed.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: external-service
            port:
              number: <port of external service> eg 4589

Upvotes: 9

c4f4t0r
c4f4t0r

Reputation: 1641

If your external service has a dns entry configured on it, you can use kubernetes externalName service.

---
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: myexternal.http.service.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: externalNameservice
  namespace: prod
spec:
  rules:
  - host: service.example.com
    http:
      paths:
      - backend:
          serviceName: my-service
          servicePort: 80
        path: /

In this way, kubernetes create cname record my-service pointing to myexternal.http.service.com

Upvotes: 11

Related Questions