How to make application visible to Traefik?

Hi I have a fresh cluster via Digital Ocean.
I created the namespace routing, where I installed the Traefik helm chart v2.2
The dashboard works via localhost by binding the port so I can see that there is 4 services visible.

In the dashboard in the services area it says:

api@internal
dashbaord@internal
noop@internal
ping@internal

The status for all them is a green tick.

When I do the following after deploying the application I can do:

kubectl get svc -A

I can see:

NAMESPACE     NAME          TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
default       kubernetes    ClusterIP      10.245.0.1       <none>          443/TCP                      9d
example       example-app   ClusterIP      10.245.179.188   <none>          80/TCP                       2d1h
kube-system   kube-dns      ClusterIP      10.245.0.10      <none>          53/UDP,53/TCP,9153/TCP       9d
routing       traefik       LoadBalancer   10.245.80.28     external-ip   80:30140/TCP,443:31185/TCP   2d4h

When I do:

kubectl get pods -A

I get:

NAMESPACE     NAME                                           READY   STATUS    RESTARTS   AGE
example       example-app-2zlzd                              1/1     Running   0          19m
kube-system   cilium-bzpsx                                   1/1     Running   0          9d
kube-system   cilium-operator-7c59b5d8d-p26n8                1/1     Running   1          9d
kube-system   coredns-6b6854dcbf-trdsz                       1/1     Running   0          9d
kube-system   coredns-6b6854dcbf-vdng4                       1/1     Running   0          9d
kube-system   csi-do-node-mgqvv                              2/2     Running   0          9d
kube-system   do-node-agent-7nhx2                            1/1     Running   0          9d
kube-system   kube-proxy-t249t                               1/1     Running   0          9d
routing       traefik-86cb4f657c-wns84                       1/1     Running   0          2d5h

on on domain name provider I set the @ and * field to the external IP. When I ping the domain it shows the external-ip. After deploying the application I get a 404 when visiting the webpage.

So now for my application:

example-app.yml


apiVersion: apps/v1
kind: ReplicaSet
metadata:
  namespace: example
  name: 'example-app'
  labels:
    app: 'example-app'
    tier: 'frontend'
    traefik.http.routers.example-app.rule: 'mydomain.com'
    traefik.http.routers.example-app.entrypoints: 'web'
    traefik.enable: 'true'
spec:
  replicas: 1
  selector:
      matchLabels:
        tier: 'frontend'
  template:
    metadata:
      labels:
        tier: 'frontend'
        traefik.http.routers.example-app.rule: 'mydomain.com'
        traefik.http.routers.example-app.entrypoints: 'web'
        traefik.enable: 'true'
    spec:
      containers:
      - name: example-app
        image: richarvey/nginx-php-fpm:latest
        imagePullPolicy: Always
        env: passwords-for-repo
        ports:
        - containerPort: 80

example-namespace.yml

apiVersion: v1
kind: Namespace
metadata:
  name: example

example-service.yml

apiVersion: v1
kind: Service
metadata:
  namespace: example
  name: 'example-app'
spec:
  type: ClusterIP
  ports:
    - protocol: TCP
      name: http
      port: 80
      targetPort: 80
  selector:
    app: 'example-app'

The image in the deployment is richarvey/nginx-php-fpm The page is here and all it does it deploy an nginx/php-fpm webserver that pulls in files from a git repo. In the git repo I just have an index.php that says hello.

The guide I used is here:

Any help from you would be amazing as I am finding it quite difficult to know where to look! Thanks

So labels are for the docker provider. You are not using that. You are using kubernetes. You need to create either IngressRoute or Ingress, I personally recommend the former.

https://docs.traefik.io/providers/kubernetes-crd/
https://docs.traefik.io/providers/kubernetes-ingress/

I have already installed Traefik via the helm chart, is this something that needs to be a part of the values.yml file for the chart or is this a separate ingress controller just for the application? Or is the traefik ingress controller just for incoming requests to the cluster and then each application needs another ingress that I must setup? Do you know of any links to github repos with an example application of deploy files? Also does `scope: Namespaced mean they must all be in the same namespace?Or even a youtube video that goes through the process as I find the documentation a little bit confusing, thanks!

This is the guide I followed from the start:

No, I mean configuration for example-app. The helm chart and traefik installation is fine. What you are trying to do is to expose your example app. This is not done via labels since it's not docker it's done via a Kubernetes object as you would expect.

My apologies, I might have linked not the pages I intended above, here are some more links:

https://docs.traefik.io/routing/providers/kubernetes-crd/
https://docs.traefik.io/routing/providers/kubernetes-ingress/

1 Like

Awesome I will give them a read and post a reply on how I get on. Thanks again.

Hey i'm back.
So I added example-ingress.yml which consists of:


kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
  namespace: example
  name: example-ingress
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web, websecure
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - path: /
        backend:
          serviceName: example-app
          servicePort: 80

I can then run:

kubectl get ing -n example

which gives me:

NAMESPACE   NAME              CLASS    HOSTS                       ADDRESS   PORTS   AGE
example     example-ingress   <none>   mydomain.com             80      75m

But when I check the logs of the traefik pod I get the following errors:

level=error msg="Cannot create service: subset not found" namespace=example ingress=example-ingress serviceName=example-app providerName=kubernetes servicePort=80

Any ideas? Then still getting 404 when visiting the domain on browser

Check that your kubernetes service has active endpoints.

Thanks for sticking with me :slight_smile:

So when I do: kubectl get svc -A

I get:

NAMESPACE     NAME          TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                      AGE
default       kubernetes    ClusterIP      10.245.0.1       <none>           443/TCP                      11d
example       example-app   ClusterIP      10.245.224.160   <none>           80/TCP                       30h
kube-system   kube-dns      ClusterIP      10.245.0.10      <none>           53/UDP,53/TCP,9153/TCP       11d
routing       traefik       LoadBalancer   10.245.105.182   external-ip   80:30402/TCP,443:30022/TCP   29h

Might the issue like my my example-app services port and targetPort? Since the port in LoadBalancer service is 80:30402?


apiVersion: v1
kind: Service
metadata:
  namespace: example
  name: 'example-app'
spec:
  type: ClusterIP
  ports:
    - protocol: TCP
      name: http
      port: 80
      targetPort: 80
  selector:
    app: 'example-app'

Hey, could you please check that your kubernetes service has active endpoints? Endpoint is a kubernetes object attached to a kubernetes service , you might want to google it if you do not know what it is / how it works.

When I do the following:

kubectl get endpoints -A

I get:


NAMESPACE     NAME          ENDPOINTS                                                   AGE
default       kubernetes    ip-address:443                                          14d
example       example-app   <none>                                                      4d2h
kube-system   kube-dns      10.244.0.74:53,10.244.0.8:53,10.244.0.74:9153 + 3 more...   14d
routing       traefik       10.244.0.26:8000,10.244.0.26:8443                           4d

My values file when I installed the traefik helm chart was:

# Default values for Traefik
image:
  name: traefik
  tag: 2.2.8
  pullPolicy: IfNotPresent

#
# Configure the deployment
#
deployment:
  enabled: true
  # Number of pods of the deployment
  replicas: 1
  # Additional deployment annotations (e.g. for jaeger-operator sidecar injection)
  annotations: {}
  # Additional pod annotations (e.g. for mesh injection or prometheus scraping)
  podAnnotations: {}
  # Additional containers (e.g. for metric offloading sidecars)
  additionalContainers: []
  # Additional initContainers (e.g. for setting file permission as shown below)
  initContainers: []
    # The "volume-permissions" init container is required if you run into permission issues.
    # Related issue: https://github.com/containous/traefik/issues/6972
    # - name: volume-permissions
    #   image: busybox:1.31.1
    #   command: ["sh", "-c", "chmod -Rv 600 /data/*"]
    #   volumeMounts:
    #     - name: data
    #       mountPath: /data
  # Custom pod DNS policy. Apply if `hostNetwork: true`
  # dnsPolicy: ClusterFirstWithHostNet

# Pod disruption budget
podDisruptionBudget:
  enabled: false
  # maxUnavailable: 1
  # minAvailable: 0

# Create an IngressRoute for the dashboard
ingressRoute:
  dashboard:
    enabled: true
    # Additional ingressRoute annotations (e.g. for kubernetes.io/ingress.class)
    annotations: {}
    # Additional ingressRoute labels (e.g. for filtering IngressRoute by custom labels)
    labels: {}

rollingUpdate:
  maxUnavailable: 1
  maxSurge: 1


#
# Configure providers
#
providers:
  kubernetesCRD:
    enabled: true
  kubernetesIngress:
    enabled: true
    # IP used for Kubernetes Ingress endpoints
    publishedService:
      enabled: false
      # Published Kubernetes Service to copy status from. Format: namespace/servicename
      # By default this Traefik service
      # pathOverride: ""

#
# Add volumes to the traefik pod.
# This can be used to mount a cert pair or a configmap that holds a config.toml file.
# After the volume has been mounted, add the configs into traefik by using the `additionalArguments` list below, eg:
# additionalArguments:
# - "--providers.file.filename=/config/dynamic.toml"
volumes: []
# - name: public-cert
#   mountPath: "/certs"
#   type: secret
# - name: configs
#   mountPath: "/config"
#   type: configMap

# Logs
# https://docs.traefik.io/observability/logs/
logs:
  # Traefik logs concern everything that happens to Traefik itself (startup, configuration, events, shutdown, and so on).
  general:
    # By default, the logs use a text format (common), but you can
    # also ask for the json format in the format option
    # format: json
    # By default, the level is set to ERROR. Alternative logging levels are DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.
    level: ERROR
  access:
    # To enable access logs
    enabled: true
    # By default, logs are written using the Common Log Format (CLF).
    # To write logs in JSON, use json in the format option.
    # If the given format is unsupported, the default (CLF) is used instead.
    # format: json
    # To write the logs in an asynchronous fashion, specify a bufferingSize option.
    # This option represents the number of log lines Traefik will keep in memory before writing
    # them to the selected output. In some cases, this option can greatly help performances.
    # bufferingSize: 100
    # Filtering https://docs.traefik.io/observability/access-logs/#filtering
    filters: {}
      # statuscodes: "200,300-302"
      # retryattempts: true
      # minduration: 10ms
    # Fields
    # https://docs.traefik.io/observability/access-logs/#limiting-the-fieldsincluding-headers
    fields:
      general:
        defaultmode: keep
        names: {}
          # Examples:
          # ClientUsername: drop
      headers:
        defaultmode: drop
        names: {}
          # Examples:
          # User-Agent: redact
          # Authorization: drop
          # Content-Type: keep

globalArguments:
  - "--global.checknewversion"
  - "--global.sendanonymoususage"

#
# Configure Traefik static configuration
# Additional arguments to be passed at Traefik's binary
# All available options available on https://docs.traefik.io/reference/static-configuration/cli/
## Use curly braces to pass values: `helm install --set="additionalArguments={--providers.kubernetesingress.ingressclass=traefik-internal,--log.level=DEBUG}"`
additionalArguments: []
#  - "--providers.kubernetesingress.ingressclass=traefik-internal"
#  - "--log.level=DEBUG"

# Environment variables to be passed to Traefik's binary
env: []
# - name: SOME_VAR
#   value: some-var-value
# - name: SOME_VAR_FROM_CONFIG_MAP
#   valueFrom:
#     configMapRef:
#       name: configmap-name
#       key: config-key
# - name: SOME_SECRET
#   valueFrom:
#     secretKeyRef:
#       name: secret-name
#       key: secret-key

envFrom: []
# - configMapRef:
#     name: config-map-name
# - secretRef:
#     name: secret-name

# Configure ports
ports:
  # The name of this one can't be changed as it is used for the readiness and
  # liveness probes, but you can adjust its config to your liking
  traefik:
    port: 9000
    # Use hostPort if set.
    # hostPort: 9000
    #
    # Use hostIP if set. If not set, Kubernetes will default to 0.0.0.0, which
    # means it's listening on all your interfaces and all your IPs. You may want
    # to set this value if you need traefik to listen on specific interface
    # only.
    # hostIP: 192.168.100.10

    # Defines whether the port is exposed if service.type is LoadBalancer or
    # NodePort.
    #
    # You SHOULD NOT expose the traefik port on production deployments.
    # If you want to access it from outside of your cluster,
    # use `kubectl proxy` or create a secure ingress
    expose: false
    # The exposed port for this service
    exposedPort: 9000
    # The port protocol (TCP/UDP)
    protocol: TCP
  web:
    port: 8000
    # hostPort: 8000
    expose: true
    exposedPort: 80
    # The port protocol (TCP/UDP)
    protocol: TCP
    # Use nodeport if set. This is useful if you have configured Traefik in a
    # LoadBalancer
    # nodePort: 32080
    # Port Redirections
    # Added in 2.2, you can make permanent redirects via entrypoints.
    # https://docs.traefik.io/routing/entrypoints/#redirection
    # redirectTo: websecure
  websecure:
    port: 8443
    # hostPort: 8443
    expose: true
    exposedPort: 443
    # The port protocol (TCP/UDP)
    protocol: TCP
    # nodePort: 32443

# Options for the main traefik service, where the entrypoints traffic comes
# from.
service:
  enabled: true
  type: LoadBalancer
  # Additional annotations (e.g. for cloud provider specific config)
  annotations: {}
  # Additional entries here will be added to the service spec. Cannot contains
  # type, selector or ports entries.
  spec: {}
    # externalTrafficPolicy: Cluster
    # loadBalancerIP: "1.2.3.4"
    # clusterIP: "2.3.4.5"
  loadBalancerSourceRanges: []
    # - 192.168.0.1/32
    # - 172.16.0.0/16
  externalIPs: []
    # - 1.2.3.4

## Create HorizontalPodAutoscaler object.
##
autoscaling:
  enabled: false
#   minReplicas: 1
#   maxReplicas: 10
#   metrics:
#   - type: Resource
#     resource:
#       name: cpu
#       targetAverageUtilization: 60
#   - type: Resource
#     resource:
#       name: memory
#       targetAverageUtilization: 60

# Enable persistence using Persistent Volume Claims
# ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
# After the pvc has been mounted, add the configs into traefik by using the `additionalArguments` list below, eg:
# additionalArguments:
# - "--certificatesresolvers.le.acme.storage=/data/acme.json"
# It will persist TLS certificates.
persistence:
  enabled: false
#  existingClaim: ""
  accessMode: ReadWriteOnce
  size: 128Mi
  # storageClass: ""
  path: /data
  annotations: {}
  # subPath: "" # only mount a subpath of the Volume into the pod

# If hostNetwork is true, runs traefik in the host network namespace
# To prevent unschedulabel pods due to port collisions, if hostNetwork=true
# and replicas>1, a pod anti-affinity is recommended and will be set if the
# affinity is left as default.
hostNetwork: false

# Whether Role Based Access Control objects like roles and rolebindings should be created
rbac:
  enabled: true

  # If set to false, installs ClusterRole and ClusterRoleBinding so Traefik can be used across namespaces.
  # If set to true, installs namespace-specific Role and RoleBinding and requires provider configuration be set to that same namespace
  namespaced: false

# The service account the pods will use to interact with the Kubernetes API
serviceAccount:
  # If set, an existing service account is used
  # If not set, a service account is created automatically using the fullname template
  name: ""

# Additional serviceAccount annotations (e.g. for oidc authentication)
serviceAccountAnnotations: {}

resources: {}
  # requests:
  #   cpu: "100m"
  #   memory: "50Mi"
  # limits:
  #   cpu: "300m"
  #   memory: "150Mi"
affinity: {}
# # This example pod anti-affinity forces the scheduler to put traefik pods
# # on nodes where no other traefik pods are scheduled.
# # It should be used when hostNetwork: true to prevent port conflicts
#   podAntiAffinity:
#     requiredDuringSchedulingIgnoredDuringExecution:
#     - labelSelector:
#         matchExpressions:
#         - key: app
#           operator: In
#           values:
#           - {{ template "traefik.name" . }}
#       topologyKey: failure-domain.beta.kubernetes.io/zone
nodeSelector: {}
tolerations: []

# Pods can have priority.
# Priority indicates the importance of a Pod relative to other Pods.
priorityClassName: ""

# Set the container security context
# To run the container with ports below 1024 this will need to be adjust to run as root
securityContext:
  capabilities:
    drop: [ALL]
  readOnlyRootFilesystem: true
  runAsGroup: 65532
  runAsNonRoot: true
  runAsUser: 65532

podSecurityContext:
  fsGroup: 65532

Hello,

so your application do not have any service endpoints as per your output, this is your problem. No one can reach it via the service you told traefik to reach it via, so traefik cannot either. Could you please configure the app correctly and try again? If you not sure how to do that you might want to get some help from kubernetes communities, since this is not traefik specific. Here is a starting point: https://kubernetes.io/docs/concepts/services-networking/service/

Good luck!

The answer was to change the example-service.yml files selector:

selector:
tier: 'frontend'

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.