Kubernetes Ingress nicht erreichbar

#1
Hallo Gemeinde, ich habe hier ein kleines Problem.
Bin mir sicher das ich nur ein Detail übersehen habe aber ich komme nicht drauf.

Ich habe mir einen Kubernetes-Cluster aufgesetzt(Single Node(Master only, untainted scheduling auf dem Master))
Deployments, Pods und Services laufen.
Aber wenn ich versuche einen Ingress-Controller zu benutzen dann scheitere ich und ich hab einiges ausprobiert und weiss gerade nicht wiso Ingress nicht will.
Services mit NodePort oder LoadBalancer sind übrigens von aussen erreichbar.

PHP:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextcloud
  labels:
    run: nextcloud
  name: nextcloud
spec:
  replicas: 1
  selector:
    matchLabels:
      run: nextcloud
  template:
    metadata:
      labels:
        run: nextcloud
    spec:
      containers:
        - name: nextcloud
          image: library/nextcloud
          imagePullPolicy: Always
          ports:
            - containerPort: 80

PHP:
apiVersion: v1
kind: Service
metadata:
  name: myservice
  labels:
    name: myservice
spec:
  selector:
    run: nextcloud 
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80 
    #type: LoadBalancer
  
    #type: NodePort 
  type: ClusterIP

PHP:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  backend:
    serviceName: myservice
    servicePort: 8080
Die Ingress-Versionen sind nicht zeitgleich aktiv.
PHP:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  backend:
    serviceName: myservice
    servicePort: 8080

PHP:
{
  "name": "cbr0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

Das Kubeadm-Kommando was ich zum initialisieren des Clusters aufgeführt habe

PHP:
kubeadm init --pod-network-cidr=10.244.0.0/16
Auch noch anzumerken ist das kubectl get ing -o wide

die Adresse nicht ausgibt.

kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
test minikube.k8s 80 12m

Ingress-Controller ist auch installiert.

-------------------------------------------------------------------------------
NGINX Ingress controller
Release: 0.16.2
Build: git-26eacf4
Repository: GitHub - kubernetes/ingress-nginx: NGINX Ingress Controller for Kubernetes https://kubernetes.github.io/ingress-nginx/
-------------------------------------------------------------------------------


Dockerversion: 17.12.1-ce (Ist nur bis 17.3 von kubeadm ohne Warnung unterstützt aber ich denke nicht das es daran liegt weil services ja erreichbar sind).

Kubernetesversion: 1.11

Als CNI nehme ich flannel.

OS ist Ubuntu Bionic Beaver.

Als Hardware kommt eine KVM bei meinem Anbieter zum Einsatz.

Beste Grüße

Fluffy


//edit

Für mich sieht es zZ so aus als ob kublet keine IP bezieht.

Nach einigen Recherchen bin ich zu dem Schluss gekommen das es ggf daran liegt das Ingress keine IP zugewiesen bekommt weil es nicht in einer Cloud-Umgebung aufgerufen wird.
Hoffe jemand anderes kann mir da noch etwas mehr Einsicht verschaffen, denn sonst werde ich mir früher als später meine eigene Registry aufsetzen müssen und meinen eigenen reverse-proxy-deployment schreiben müssen.
 
Zuletzt bearbeitet:
#2
Wenn du wissen willst, was das Problem eines Ingress-Controllers ist, solltest du erstmal folgende Dinge überprüfen:

1. Läuft der zum Deployment gehörende Pod korrekt und hat der eine IP bekommen? (Auf Anzahl der Restarts achten und mal die Logs vom Pod anschauen.)
2. Hat das Deployment ein passendes ReplicaSet zugeordnet?
3. Hat der Service einen Endpoint, der zum Pod passt (IP und Port)?
4. Hat der Ingress zu den Nodes passende Adressen?

Das alles kannst du mittels 'get' und 'describe' via kubectl herausbekommen. Mit 'kubectl get <what>' bekommst du die Liste der jeweilig verfügbaren Deployments, Services, Pods etc.. Mit 'kubectl describe <what> <name>' bekommst du dann die zugehörigen Detail-Infos. Also:

Code:
1. kubectl describe `kubectl describe pod |grep nextcloud |awk '{print $1}'` # Unterschied zwischen Backtick und Apostrophs beachten!
2. kubectl describe deploy nextcloud
3. kubectl describe svc myservice
4. kubectl describe ingress test
Damit solltest du die notwendigen Infos bekommen.

Edit: Wenn du das Cluster selbst aufgesetzt hast, solltest du natürlich auch mal den Cluster-Status überprüfen und schauen, ob z.B. der kube-dns korrekt läuft etc..
 
#3
Hi Bit,
das habe ich alles schon gecheckt ;) .
Ich kann auch mittels NodePort auf den service zugreifen, aber halt nicht auf Ingress(hab den Pod mal an 2 Services gleichzeitig angebunden).
So wie ich die Dokumentation und Posts in anderen Foren und auf S.O. halt lese ist Ingress dafür da einen externen LoadBalancer zu kreieren.
Problem ist halt beim BareMetal-Install das es keinen gibt.
Das würde sich auch mit meiner Beobachtung decken das Ingress keine IP zugewiesen bekommt.
PHP:
kubectl describe ing -o wide
liefert mir für "Address" halt einen leeren Wert zurück.
Wenn du nun aber weisst das es definitiv in dem angegebenen Szenario möglich ist, dann können wir hier gerne meine Server-Konfiguration, Clustersetup etc. auseinandern nehmen,
denn dann mache ich hier definitiv was falsch und ich werde nicht der einzige sein.

Würde darüber dann sogar hier einen Artikel in Eng und Deu verfassen.

LG

Fluffy
 
Zuletzt bearbeitet:
#4
Ich habe mir einen Kubernetes-Cluster aufgesetzt(Single Node(Master only, untainted scheduling auf dem Master))
Hast du echt nur einen Master und keine Minions? Wenn ja, wohin soll der Ingress denn dann gebunden werden? Der wird ja an die IPs der Minions gebunden.

Btw: Wenn du nur ein Single-Node-Cluster brauchst, dann nutze Minikube. Da kannst du auch mit Ingress-Controllern rumspielen.
 
#5
Ich dachte das wäre egal.

Wenn ich den Master-Node Untainte und da da auch Pods drauf schedule dann sollte das doch gehen,
denn dann ist der Master ja auch sein eigener Minion.Darüber hinaus dachte ich das, sobald es an den Ingress-Controller geht ich das ganze im Overlay-Netzwerk des Clusters selbst routen kann.
d.h. verwundert mich das das ich für den Ingress-Controller minions brauche, geht in Minikube ja auch.


LG

Fluffy

//edit: AFAIK funktioniert ingress in Minikube nicht(war zumindest damals so als ich das ausprobiert hatte, und wenn ich das ganze in Minikube mache und es funktioniert hab ich offensichtlich keine garantie das es im Cluster auch so ist)
Denn wie gesagt das was ich gelesen habe(ist es ein Cloud-First GCE feature), es funktioniert dort ja, aber wiso nicht auf der lokalen Cloud?
 
Zuletzt bearbeitet:
#6
Eine der Eigenschaften von Default-Ingress-Controllern ist, dass sie an das Netzwerk aller Minions gebunden werden. Beispiel:

Wenn ich einen Ingress für ein K8S-Dashboard wie diesen erstellen:

Code:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ro-dashboard-ing
  namespace: default
spec:
  rules:
  - host: ro-dashboard.meinedomain.tld
    http:
      paths:
        - path: /
          backend:
            serviceName: ro-dashboard
            servicePort: 80
Dann erhalte ich einen Ingress, der an den Port 80 aller Minions gebunden ist und die Anfragen für die Domain `ro-dashboard.meinedomain.tld` an den Service `ro-dashboard` weiterreicht. Ich hab zugegebenermaßen noch nie versucht das an den Master zu binden, kann mir aber vorstellen, dass es dort zu Konflikten kommen wird, wenn Master-Services (K8S-API o.ä.) den Port bereits belegen. Hab ich ihn jedoch an den Minions, kann ich einfach im DNS die entsprechenden Minions als A-Record eintragen oder einen entsprechenden Loadbalancer vorschalten, der die Minions als Backends nutzt.
 
#7
Schon verstanden, aber dann dürfte nach der Logik kein Node-port auf dem Master funktionieren.
Tun sie aber. Dafür ist ja der Kubelet-Service zuständig.
Ein Ingress-Kontroller ist ja auch eine art spezieller Service.
Rein theoritisch könnte ich einen Nginx-Pod mit ReverseProxy-Konfiguration benutzen und dort die anderen Service und Node-Ports der PODs eintragen.
Deshalb kommt mir das alles ja ein bischen komisch vor.

Deine oben gezeigte Konfiguration:
Hast du die auf einer privaten K8s Instanz laufen oder in GCE oder dergleichen?
 
#9
Dann geh ich erstmal davon aus das mein Setup der Grund ist.
Was IMHO auch schon komisch ist denn Ingress läuft ja auch über NodePorts.

Werde Euch auf dem Laufenden halten.
Thx bit.
 
#12
Kubespray hab ich noch nie benutzt. Werde ich mir bei Gelegenheit mal anschauen.
Ich meine Konfiguration rund um die Load-Balancer und Ingress-Controller.

Wenn ich meinen Cluster(wie oben beschrieben ohne jegliche Hilfsmittel(e.g. Kubespray)) aufsetze dann habe ich keine Loadbalancer konfiguriert und Ingress verhält sich wie beschrieben.
Im Grunde geht es um genau die Konfiguration welche dafür sorgt das dein Ingress-Kontroller funktioniert und meiner nicht.

LG

Fluffy
 
#13
Sorry für die späte Antwort. Hab dich nicht vergessen. Aber wir haben keine besonderen Settings, die den LB betreffen. Wir haben allerdings auch einen LB vorgeschaltet und die Ingress sind lediglich an alle Node-Adressen gebunden. Auf diese Weise stellen sie auf den gewünschten Ports auf allen Minions ihre Dienste bereit, wo unser LB sie abgreifen kann. Dabei kommt HAproxy als Ingress zum Einsatz, der mit einem Custom-Image deployed wird. Für den haben wir eine ConfigMap implementiert, mit der die haproxy.cfg aus einem Jinja-Template dynamisch generiert wird. In meinem Test-Cluster nutze ich auf ähnliche Weise das Image von quay.io/jcmoraisjr/haproxy-ingress:latest, dem man mittels Parameter Dinge wie ConfigMap oder auch Default-Backend einstellen kann. Beispiel: Du definierst z.B. einen Service als Backend in der Art (selector nach deinem Bedarf anpassen):

Code:
apiVersion: v1
kind: Service
metadata:
  name: ingress-default-backend
spec:
  ports:
  - name: http
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    app: web
  sessionAffinity: None
  type: ClusterIP
Dann erstellst du dir ein Deployment für den Haproxy-Ingress in der Art:

Code:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: haproxy-ingress
  name: haproxy-ingress
spec:
  replicas: 2
  selector:
    matchLabels:
      run: haproxy-ingress
  template:
    metadata:
      labels:
        run: haproxy-ingress
    spec:
      dnsPolicy: ClusterFirstWithHostNet
      hostNetwork: true
      serviceAccountName: ingress-controller
      serviceAccount: ingress-controller
      containers:
      - name: haproxy-ingress
        image: quay.io/jcmoraisjr/haproxy-ingress:latest
        args:
        - --default-backend-service=default/ingress-default-backend
        - --default-ssl-certificate=default/tls-secret
        - --configmap=default/haproxy-ingress
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        - name: stat
          containerPort: 1936
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
Die zugehörige ConfigMap könnte so aussehen:

Code:
apiVersion: v1
kind: ConfigMap
metadata:
  name: haproxy-configmap
data:
  timeout-server: 600s
  timeout-client: 600s
  timeout-http-request: 600s
  backend-check-interval: 1s
  haproxy.tmpl: |
    {{ $ing := . }}
    {{ $cfg := .Cfg }}
    global
        daemon
        stats socket {{ $cfg.StatsSocket }} level admin
        #server-state-file global
        #server-state-base /var/state/haproxy/
    {{ if ne $cfg.Syslog "" }}
        log {{ $cfg.Syslog }} format rfc5424 local0
        log-tag ingress
    {{ end }}
    {{ if ne $cfg.SSLDHParam.Filename "" }}
        # DH PEM checksum: {{ $cfg.SSLDHParam.PemSHA }}
        ssl-dh-param-file {{ $cfg.SSLDHParam.Filename }}
    {{ else }}
        tune.ssl.default-dh-param {{ $cfg.SSLDHParam.DefaultMaxSize }}
    {{ end }}
        ssl-default-bind-ciphers {{ $cfg.SSLCiphers }}
        ssl-default-bind-options {{ $cfg.SSLOptions }}

    defaults
        log global
        #load-server-state-from-file global
        option redispatch
        option dontlognull
        option http-server-close
        option http-keep-alive
        # One retry per server
        retries 4
        maxconn {{ $cfg.MaxConn }}
        timeout http-request    600s
        timeout connect         {{ $cfg.TimeoutConnect }}
        timeout client          600s
        timeout client-fin      {{ $cfg.TimeoutClientFin }}
        timeout server          600s
        timeout server-fin      {{ $cfg.TimeoutServerFin }}
        timeout tunnel          {{ $cfg.TimeoutTunnel }}
        timeout http-keep-alive 1s

    {{ if ne (len $ing.Userlists) 0 }}
    ######
    ###### Userlists
    ######
    {{ range $userlist := $ing.Userlists }}
    userlist {{ $userlist.ListName }}
    {{ range $user := $userlist.Users }}
        user {{ $user.Username }} {{ if not $user.Encrypted }}insecure-{{ end }}password {{ $user.Password }}
    {{ end }}
    {{ end }}
    {{ end }}

    ######
    ###### Backends
    ######
    {{ range $backend := $ing.Backends }}
    backend {{ $backend.Name }}
        mode {{ if $backend.SSLPassthrough }}tcp{{ else }}http{{ end }}
        balance {{ $cfg.BalanceAlgorithm }}
    {{ $sticky := $backend.SessionAffinity }}
    {{ if eq $sticky.AffinityType "cookie" }}
        cookie {{ $sticky.CookieSessionAffinity.Name }} insert indirect nocache
    {{ end }}
    {{ $cacert := $backend.SecureCACert }}
    {{ if ne $cacert.PemSHA "" }}
        # CA PEM checksum: {{ $cacert.PemSHA }}
    {{ end }}
    {{ $BackendSlots := index $ing.BackendSlots $backend.Name }}
    {{ range $target, $slot := $BackendSlots.FullSlots }}
        server {{ $slot.BackendServerName }} {{ $target }} {{ if $backend.Secure }}ssl {{ if ne $cacert.CAFileName "" }}verify required ca-file {{ $cacert.CAFileName }} {{ else }}verify none {{ end }}{{ end }}check port {{ $slot.BackendEndpoint.Port }} inter {{ $cfg.BackendCheckInterval }}{{ if eq $sticky.AffinityType "cookie" }} cookie {{ backendHash $slot.BackendServerName }}{{ end }}
    {{ end }}
    {{ range $empty := $BackendSlots.EmptySlots }}
        server {{ $empty }} 127.0.0.1:81 {{ if $backend.Secure }}ssl {{ if ne $cacert.CAFileName "" }}verify required ca-file {{ $cacert.CAFileName }} {{ else }}verify none {{ end }}{{ end }}check disabled inter {{ $cfg.BackendCheckInterval }}{{ if eq $sticky.AffinityType "cookie" }} cookie {{ backendHash $empty }}{{ end }}
    {{ end }}
    {{ end }}

    ######
    ###### HTTP frontend
    ######
    {{ $hasHTTPStoHTTP := gt $cfg.HTTPStoHTTPPort 0 }}
    frontend httpfront
        bind *:80{{ if $cfg.UseProxyProtocol }} accept-proxy{{ end }}
    {{ if $hasHTTPStoHTTP }}
        bind *:{{ $cfg.HTTPStoHTTPPort }}{{ if $cfg.UseProxyProtocol }} accept-proxy{{ end }}
    {{ end }}
        mode http
    {{ if ne $cfg.Syslog "" }}
        option httplog
    {{ if ne $cfg.HTTPLogFormat "" }}
        log-format {{ $cfg.HTTPLogFormat }}
    {{ end }}
    {{ end }}
    {{ if $hasHTTPStoHTTP }}
        http-request set-var(txn.hdr_proto) hdr(x-forwarded-proto)
        acl is-https-to-http dst_port eq {{ $cfg.HTTPStoHTTPPort }}
        acl is-https-to-http var(txn.hdr_proto) eq https
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if isWildcardHostname $server.Hostname }}
        acl ishost-{{ $server.HostnameLabel }} hdr_reg(host) {{ hostnameRegex $server.Hostname }}
    {{ else }}
        acl ishost-{{ $server.HostnameLabel }} hdr(host) {{ $server.Hostname }} {{ $server.Hostname }}:80
    {{ end }}
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if $server.UseHTTP }}
    {{ range $location := $server.Locations }}
    {{ if ne $location.HAWhitelist "" }}
        http-request deny if ishost-{{ $server.HostnameLabel }}{{ $location.HAMatchPath }} !{ src{{ $location.HAWhitelist }} }
    {{ end }}
    {{ $listName := $location.Userlist.ListName }}
    {{ if ne $listName "" }}
        {{ $realm := $location.Userlist.Realm }}
        http-request auth {{ if ne $realm "" }}realm "{{ $realm }}" {{ end }}if ishost-{{ $server.HostnameLabel }}{{ $location.HAMatchPath }} !{ http_auth({{ $listName }}) }
    {{ end }}
    {{ end }}
    {{ end }}
    {{ end }}
    {{ if eq $cfg.Forwardfor "add" }}
        reqidel ^X-Forwarded-For:.*
        option forwardfor
    {{ else if eq $cfg.Forwardfor "ifmissing" }}
        option forwardfor if-none
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if $server.UseHTTP }}
    {{ $appRoot := $server.RootLocation.Rewrite.AppRoot }}
    {{ if ne $appRoot "" }}
        redirect location {{ $appRoot }} if ishost-{{ $server.HostnameLabel }} { path / }
    {{ end }}
    {{ end }}
    {{ end }}
    {{ if and $hasHTTPStoHTTP $cfg.HSTS }}
        rspadd "Strict-Transport-Security: max-age={{ $cfg.HSTSMaxAge }}{{ if $cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }}{{ if $cfg.HSTSPreload }}; preload{{ end }}" if is-https-to-http
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if $server.UseHTTPS }}
    {{ if $server.SSLRedirect }}
        redirect scheme https if ishost-{{ $server.HostnameLabel }}{{ if $hasHTTPStoHTTP }} !is-https-to-http{{ end }}
    {{ else }}
    {{ range $location := $server.Locations }}
    {{ if $location.Rewrite.SSLRedirect }}
        redirect scheme https if ishost-{{ $server.HostnameLabel }}{{ $location.HAMatchPath }}{{ if $hasHTTPStoHTTP }} !is-https-to-http{{ end }}
    {{ end }}
    {{ end }}
    {{ end }}
    {{ end }}
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if or $server.UseHTTP $hasHTTPStoHTTP }}
    {{ range $location := $server.Locations }}
    {{ if ne $location.Proxy.BodySize "" }}
        use_backend error413 if ishost-{{ $server.HostnameLabel }} { path_beg {{ $location.Path }} } { req.body_size gt {{ sizeSuffix $location.Proxy.BodySize }} }
    {{ end }}
    {{ end }}
    {{ range $location := $server.Locations }}
        use_backend {{ $location.Backend }} if ishost-{{ $server.HostnameLabel }} { path_beg {{ $location.Path }} }
    {{ end }}
    {{ end }}
    {{ end }}
        default_backend {{ $ing.DefaultServer.RootLocation.Backend }}

    ######
    ###### HTTPS frontend (tcp mode)
    ######
    frontend httpsfront
        bind *:443{{ if $cfg.UseProxyProtocol }} accept-proxy{{ end }}
        mode tcp
        tcp-request inspect-delay 5s
        tcp-request content accept if { req.ssl_hello_type 1 }
    {{ range $server := $ing.PassthroughBackends }}
    {{ if isWildcardHostname $server.Hostname }}
        use_backend {{ $server.Backend }} if { req.ssl_sni -m reg -i {{ hostnameRegex $server.Hostname }} }
    {{ else }}
        use_backend {{ $server.Backend }} if { req.ssl_sni -i {{ $server.Hostname }} }
    {{ end }}
    {{ end }}
    {{ range $server := $ing.HAServers }}
    {{ if $server.UseHTTPS }}
    {{ if isWildcardHostname $server.Hostname }}
        use_backend httpsback-{{ $server.HostnameLabel }} if { req.ssl_sni -m reg -i {{ hostnameRegex $server.Hostname }} }
    {{ else }}
        use_backend httpsback-{{ $server.HostnameLabel }} if { req.ssl_sni -i {{ $server.Hostname }} }
    {{ end }}
    {{ end }}
    {{ end }}
        default_backend httpsback-default-backend
    {{ if ne $cfg.TCPLogFormat "" }}
        log-format {{ $cfg.TCPLogFormat }}
    {{ end }}

    {{ range $server := $ing.HAServers }}
    {{ if $server.UseHTTPS }}
    {{ $host := $server.HostnameLabel }}
    ##
    ## {{ $server.Hostname }}
    backend httpsback-{{ $host }}
        mode tcp
        server {{ $host }} unix@/var/run/haproxy-host-{{ $host }}.sock send-proxy-v2
    frontend httpsfront-{{ $host }}
    {{ $authSSLCert := $server.CertificateAuth.AuthSSLCert }}
        # CRT PEM checksum: {{ $server.SSLPemChecksum }}
    {{ if ne $authSSLCert.PemSHA "" }}
        # CA PEM checksum: {{ $authSSLCert.PemSHA }}
    {{ end }}
        bind unix@/var/run/haproxy-host-{{ $host }}.sock ssl crt {{ $server.SSLCertificate }}{{ if ne $authSSLCert.CAFileName "" }} ca-file {{ $authSSLCert.CAFileName }} verify optional ca-ignore-err all crt-ignore-err all{{ end }} accept-proxy
        mode http
    {{ if ne $cfg.Syslog "" }}
        option httplog
    {{ if ne $cfg.HTTPLogFormat "" }}
        log-format {{ $cfg.HTTPLogFormat }}
    {{ end }}
    {{ end }}
    {{ range $location := $server.Locations }}
    {{ if ne $location.HAWhitelist "" }}
        http-request deny if{{ $location.HAMatchPath }} !{ src{{ $location.HAWhitelist }} }
    {{ end }}
    {{ $listName := $location.Userlist.ListName }}
    {{ if ne $listName "" }}
        {{ $realm := $location.Userlist.Realm }}
        http-request auth {{ if ne $realm "" }}realm "{{ $realm }}" {{ end }}if{{ $location.HAMatchPath }} !{ http_auth({{ $listName }}) }
    {{ end }}
    {{ end }}
    {{ if eq $cfg.Forwardfor "add" }}
        reqidel ^X-Forwarded-For:.*
        option forwardfor
    {{ else if eq $cfg.Forwardfor "ifmissing" }}
        option forwardfor if-none
    {{ end }}
    {{ if ne $authSSLCert.CAFileName "" }}
    {{ if eq $server.CertificateAuth.ErrorPage "" }}
        use_backend error495 if { ssl_c_ca_err gt 0 } || { ssl_c_err gt 0 }
        use_backend error496 if !{ ssl_fc_has_crt }
    {{ else }}
        redirect location {{ $server.CertificateAuth.ErrorPage }} if !{ ssl_fc_has_crt } || { ssl_c_ca_err gt 0 } || { ssl_c_err gt 0 }
    {{ end }}
    {{ end }}
    {{ if $cfg.HSTS }}
        rspadd "Strict-Transport-Security: max-age={{ $cfg.HSTSMaxAge }}{{ if $cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }}{{ if $cfg.HSTSPreload }}; preload{{ end }}"
    {{ end }}
    {{ $appRoot := $server.RootLocation.Rewrite.AppRoot }}
    {{ if ne $appRoot "" }}
        redirect location {{ $appRoot }} if { path / }
    {{ end }}
    {{ range $location := $server.Locations }}
    {{ if ne $location.Proxy.BodySize "" }}
        use_backend error413 if { path_beg {{ $location.Path }} } { req.body_size gt {{ sizeSuffix $location.Proxy.BodySize }} }
    {{ end }}
    {{ end }}
    {{ range $location := $server.Locations }}
    {{ if not $location.IsRootLocation }}
        use_backend {{ $location.Backend }} if { path_beg {{ $location.Path }} }
    {{ else }}
        default_backend {{ $location.Backend }}
    {{ end }}
    {{ end }}
    {{ end }}
    {{ end }}

    ##
    ## Default backend (tcp mode)
    {{ $server := $ing.DefaultServer }}
    {{ $location := $server.RootLocation }}
    {{ $host := "default_backend" }}
    backend httpsback-default-backend
        mode tcp
        server {{ $host }} unix@/var/run/haproxy-{{ $host }}.sock send-proxy-v2

    frontend httpsfront-default-backend
        # CRT PEM checksum: {{ $server.SSLPemChecksum }}
        bind unix@/var/run/haproxy-{{ $host }}.sock ssl crt {{ $server.SSLCertificate }} accept-proxy
        mode http
    {{ if ne $cfg.Syslog "" }}
        option httplog
        {{ if ne $cfg.HTTPLogFormat "" }}
        log-format {{ $cfg.HTTPLogFormat }}
        {{ end }}
    {{ end }}
    {{ if eq $cfg.Forwardfor "add" }}
        reqidel ^X-Forwarded-For:.*
        option forwardfor
    {{ else if eq $cfg.Forwardfor "ifmissing" }}
        option forwardfor if-none
    {{ end }}
    {{ if $cfg.HSTS }}
        rspadd "Strict-Transport-Security: max-age={{ $cfg.HSTSMaxAge }}{{ if $cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }}{{ if $cfg.HSTSPreload }}; preload{{ end }}"
    {{ end }}
        default_backend {{ $location.Backend }}

    ######
    ###### Error pages
    ######
    backend error413
        mode http
        errorfile 400 /usr/local/etc/haproxy/errors/413.http
        http-request deny deny_status 400
    backend error495
        mode http
        errorfile 400 /usr/local/etc/haproxy/errors/495.http
        http-request deny deny_status 400
    backend error496
        mode http
        errorfile 400 /usr/local/etc/haproxy/errors/496.http
        http-request deny deny_status 400
    listen error503noendpoints
        bind *:8181
        mode http
        errorfile 503 /usr/local/etc/haproxy/errors/503noendpoints.http

    ######
    ###### Stats page
    ######
    listen stats
        bind *:{{ $cfg.StatsPort }}{{ if $cfg.StatsProxyProtocol }} accept-proxy{{ end }}
        mode http
        stats enable
        stats realm HAProxy\ Statistics
    {{ if ne $cfg.StatsAuth "" }}
        stats auth {{ $cfg.StatsAuth }}
    {{ end }}
        stats uri /
        no log

    ######
    ###### Monitor URI
    ######
    frontend healthz
        bind *:{{ $cfg.HealthzPort }}
        mode http
        monitor-uri /healthz
Wichtig ist im Endeffekt, dass dein Deployment den richtigen ServiceAccount verwendet und hostNetwork auf true gesetzt wird. Das Secret 'tls-secret' im default-Namespace sollte natürlich in diesem Beispiel das SSL-Zertifikat enthalten und kann einfach weggelassen werden, wenn du kein SSL brauchst. Dann musst du allerdings auch die ConfigMap entsprechend anpassen.
 
#14
Hi Bit,

Post ist abhanden gekommen... Fehlender Security-Token -.- .
Also nochmal kompakt:
Deine Konfiguration ausprobiert, vllt. Fehler gemacht, läuft zumindest bei mir so nicht.

Metallb ganz schlicht mit Layer2-Konfig installiert
MetalLB, bare metal load-balancer for Kubernetes

Service und Ingress bekommen nun eine IP zugewiesen
die explizit zugewiesen IP (siehe Service-config) wird auch nach deren löschen und neuanlegen des services ohne IP im Ingress-Kontroller weiter verwendet.
Service und Ingress haben unterschiedliche IPs.


Code:
apiVersion: v1
kind: Service
metadata:
  name: nextcloudstateful-service
  labels:
    name: nextcloudstateful-service
spec:
  selector:
    run: nextcloudstateful
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer
  externalIPs:
  - 192.168.1.50

kubectl get ing && kubectl get svc
NAME HOSTS ADDRESS PORTS AGE
test minikube.k8s 192.168.1.50 80 1h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h
nextcloudstateful-service LoadBalancer 10.106.53.79 192.168.1.240 80:31804/TCP 1h
nginx LoadBalancer 10.101.89.129 192.168.1.241 80:30746/TCP 2h


wget -O- mit IP 192.168.1.50 kehrt nie zurück.
Mit IP 192.168.1.240 bekomme ich genau das was ich will.
Ist auch nicht viel besser als ein Reverse Proxy mit verschiedenen Ports zum ansprechen, aber schonmal besser.

Irgend eine Komponente fehlt noch.

Code:
tcpdump "host 192.168.1.50" -i any
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
22:51:42.913126 IP cccc.happysrv.de.46690 > 192.168.1.50.http: Flags [S], seq 2421488084, win 29200, options [mss 1460,sackOK,TS val 285863368 ecr 0,nop,wscale 7], length 0
So wie es aussieht wird das Packet für die IP nicht weitergeleitet.
Werde morgen meinen Cluster nochmal komplett neu aufsetzten und schauen ob es an dem Internen Zustand von metallb lag(lease etc.) .
Wenn jemand noch eine andere Idee hat, bitte hier schreiben ;) .

LG

Fluffy

P.s.: Kubespray ist nicht wirklich für mich geeignet.
 
#15
Ich hab es hinbekommen.
Lag an meiner Installation vom Ingress-Controller.
Traefik als Daemonset installieren hat geholfen.
Nun hab ich Ingress.
IP wird immer noch nicht angezeigt, aber das macht auch nur bei Externem LB Sinn und wenn man Metallb einsetzen muss was hier definitiv nicht der Fall ist.
Traefik

LG

Fluffy

P.s.: Für alle die kubespray nicht verwenden wollen und es so minimalistisch wie möglich haben möchten:
Schritte aus meinem eröffnungspost durchführen und dann den Docs von Traefik entsprechend Traefik als Daemonset installieren.
Fertig ist der Cluster :D .
 
Oben