Expose service on local kubernetes

2020-05-27 04:18发布

问题:

I'm running a local kubernetes bundled with docker on Mac OS.

How can I expose a service, so that I can access the service via a browser on my Mac?

I've created:

a) deployment including apache httpd.

b) service via yaml:

apiVersion: v1
kind: Service
metadata:
  name: apaches
spec:
  selector:
    app: web
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
  externalIPs:
  - 192.168.1.10 # Network IP of my Mac

My service looks like:

$ kubectl get service apaches
NAME      TYPE       CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
apaches   NodePort   10.102.106.158   192.168.1.10   80:31137/TCP   14m

I can locally access the service in my kubernetes cluster by wget $CLUSTER-IP

I tried to call http://192.168.1.10/ on my Mac, but it doesn't work.

This question deals to a similar issue. But the solution does not help, because I do not know which IP I can use.

Update

Thanks to Michael Hausenblas I worked out a solution using Ingress. Nevertheless there are still some open questions:

  • What is the meaning of a service's externalIP? Why do I need an externalIP when I do not directly access a service from external?
  • What is the meaning of the service port 31137?
    • The kubernetes docs describe a method to [publish a service in minikube via NodePort][4]. Is this also possible with kubernetes bundled on docker?

回答1:

There are several solutions to expose services in kubernetes: http://alesnosek.com/blog/2017/02/14/accessing-kubernetes-pods-from-outside-of-the-cluster/

Here are my solutions according to alesnosek for a local kubernetes bundled with docker:

1. hostNetwork

hostNetwork: true

Dirty (the host network should not be shared for security reasons) => I did not check this solution.

2. hostPort

hostPort: 8086

Does not apply to services => I did not check this solution.

3. NodePort

Expose the service by defining a nodePort:

apiVersion: v1
kind: Service
metadata:
  name: apaches
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30000
  selector:
    app: apache

4. LoadBalancer

EDIT @MathObsessed posted the solution in his anwer.

5. Ingress

a. Install Ingress Controller

git clone https://github.com/jnewland/local-dev-with-docker-for-mac-kubernetes.git

kubectl apply -f nginx-ingress/namespaces/nginx-ingress.yaml -Rf nginx-ingress

b. Configure Ingress

kubectl apply -f apache-ing.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: apache-ingress
spec:
  rules:
  - host: localhost
    http:
      paths:
      - path: /
        backend:
          serviceName: apaches
          servicePort: 80

Now I can access my apache deployed with kubernetes by calling http://localhost/

Remarks for using local-dev-with-docker-for-mac-kubernetes

  • The repo simplifies the deployment of the offical ingress-nginx controller
  • For production use I would follow the official guide.
  • The repos ships with a tiny full featured ingress example. Very useful for getting quickly a working example application.

Further documentation

  • https://kubernetes.io/docs/concepts/services-networking/ingress


回答2:

The proper way to do it is to use Ingress as explained for example in this post



回答3:

For those still looking for an answer. I've managed to achieve this by adding another Kube service just to expose my app to localhost calls (via browser or Postman):

kind: Service
apiVersion: v1
metadata:
  name: apaches-published
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 80
      protocol: TCP
  selector:
    app: web
  type: LoadBalancer

Try it now on: http://localhost:8080



回答4:

As already mentioned in Matthias Ms answer there are several ways.

As the offical Kubernetes documentation specifically describes using a Service with a type NodePort I wanted to describe the workflow.

NodePort: Exposes the Service on each Node’s IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You’ll be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>:<NodePort>.

If you set the type field to NodePort, the Kubernetes control plane allocates a port from a range specified by --service-node-port-range flag (default: 30000-32767). Each node proxies that port (the same port number on every Node) into your Service. Your Service reports the allocated port in its .spec.ports[*].nodePort field.

Setup a Service with a type of NodePort

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: NodePort

Then you can check on which port the Service is exposed to via

kubectl get svc

NAME                           TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
my-service                     NodePort       10.103.218.215   <none>        9376:31040/TCP               52s

and access it via localhost using the exposed port. E.g.

curl http://localhost:31040


标签: kubernetes