Understand the use of Traefik2.1

Traefik is an open source edge router that makes publishing services easy and fun. It is responsible for receiving requests from your system and then using the appropriate components to process those requests.

In addition to its many features, Traefik sets itself apart by automatically discovering the right configuration for your service. When Traefik checks your service, it finds information about the service and finds the right service to fulfill the request.

Traefik is compatible with all major clustering technologies such as Kubernetes, Docker, Docker Swarm, AWS, Mesos, Marathon, and more; And you can do multiple things at once. (It can even be used with older software that runs bare-metal.)

With Traefik, there is no need to maintain or synchronize a separate configuration file: everything is configured automatically, in real time (no reboots, no broken connections). With Traefik, you can spend more time on system development and new features than on configuration and maintaining working state.

The core concept

Traefik is an edge router, the gateway to your entire platform, intercepting and routing every incoming request: it knows all the logic and rules that determine which services handle which requests; Whereas a traditional reverse proxy requires a configuration file that contains all possible routes to your service, Traefik detects the service in real time and automatically updates the routing rules for automatic service discovery.

First, when Traefik is started, entrypoints need to be defined. Then, incoming requests are analyzed based on the routes connected to these entrypoints to see if they match a set of rules, and if so, The routing may route the request through a series of middleware and forward it to your service. There are a few core concepts that we need to understand before getting to know Traefik:

  • ProvidersFor automatic discovery of services on the platform, this can be a orchestration tool, container engine, or key-value store, such as Docker, Kubernetes, or File
  • EntrypointsListen for incoming traffic (ports, etc…) Are network entry points that define the port (HTTP or TCP) to receive requests.
  • RoutersAnalyze requests (host, PATH, headers, SSL,…) Is responsible for connecting incoming requests to a service that can handle them.
  • ServicesForward requests to your app (Load balancing,…) Is responsible for configuring how to get the actual service that will ultimately process the incoming request.
  • MiddlewaresMiddleware, used to modify requests or make some judgments based on the request (authentication, rate Limiting, headers…) The middleware is attached to the routing, which is one of the ways in which the request is sent to youserviceA way to tweak a request before (or before the service’s response is sent to the client).

The installation

Since Traefik 2.x is not compatible with the previous 1.x version, we chose the more powerful 2.x version for this presentation. The image we use here is Traefik :2.1.1.

Configuration in Traefik can be done in two different ways:

  • Dynamic configuration: Fully dynamic route configuration
  • Static configuration: Start configuration

The elements in the static configuration, which do not change often, connect to providers and define the entrypoints that Treafik will listen on.

There are three ways to define static configuration in Traefik: in configuration files, in command-line arguments, and through environment variables

Dynamic configuration contains all the configuration that defines how the system handles requests, which can be changed and hot-updated seamlessly without any request interrupts or connection losses.

Install Traefik into Kubernetes cluster resource manifest file, which I have prepared in advance.

$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/crd.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/rbac.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/deployment.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/dashboard.yaml
Copy the code

Yaml is fixed to the master node. If you need to modify it, you can download it and make corresponding modifications. Here we do static configuration with command line arguments:

args:
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --api=true
- --api.dashboard=true
- --ping=true
- --providers.kubernetesingress
- --providers.kubernetescrd
- --log.level=INFO
- --accesslog
Copy the code

— API =true if enabled,=, a special service named api@internal will be created, which can be accessed directly in Dashboard. The other important thing is to start kubernetesingress and Kubernetescrd providers.

Dashboard. yaml defines the resource list file for accessing dashboards, which can be modified according to your own requirements.

$ kubectl get pods -n kube-system                       
NAME                                  READY   STATUS    RESTARTS   AGE
traefik-867bd6b9c-lbrlx               1/1     Running   0          6m17s
......
$ kubectl get ingressroute
NAME                 AGE
traefik-dashboard    30m
Copy the code

After the deployment is complete, you can add a mapping to the traefik.domain.com domain name in /etc/hosts to access the Dashboard page of Traefik:

ACME

Traefik extends Ingress’s capabilities by extending CRD to automatically generate HTTPS certificates in addition to the default Secret support for HTTPS for applications.

For example, we now have a WHOami application like this:

apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: containous/whoami
          ports:
            - name: web
              containerPort: 80
Copy the code

Then define an IngressRoute object:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: simpleingressroute
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/notls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
Copy the code

The entryPoints specify that the entry point for our application is the Web, that is, through port 80, and the rules for access are to match who.qikqiak.com. Requests with the path prefix /notls will be matched by the whoami Service. We can directly create the above several resource objects, and then do the corresponding domain name resolution, you can access the application:

In the IngressRoute object we define some matching rules. These rules are defined in Traefik as follows:

If you want to use HTTPS to access the application, you need to listen for the webSecure entry point, that is, through port 443 to access the application. If you want to use HTTPS to access the application, you also need a certificate.

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=who.qikqiak.com"
Copy the code

Then reference the certificate file via the Secret object:

#Note that the certificate file name must be tls. CRT and tls.key
$ kubectl create secret tls who-tls --cert=tls.crt --key=tls.key
secret/who-tls created
Copy the code

At this point we can create an IngressRoute object for HTTPS access to the application:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
  tls:
    secretName: who-tls
Copy the code

Once created, the application can be accessed via HTTPS. Since we are a self-signed certificate, the certificate is not trusted:

In addition to manually providing certificates, Traefik supports automatic certificate generation using Let’s Encrypt. To use Let’s Encrypt for automatic HTTPS, you need to enable ACME, which requires static configuration. The Traefik deployment file contains the following command line parameters:

args:
.
DNS authentication is enabled
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
# email configuration
- [email protected]
# Where to save the ACME certificate
- --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json
Copy the code

ACME has a variety of authentication modes tlsChallenge, httpChallenge, and dnsChallenge. HTTP authentication was more commonly used in the past. For details about the use of these authentication modes, see the documentation: www.qikqiak.com/traefik-boo… Know the difference. To use TLS authentication, ensure that Traefik port 443 is reachable. DNS authentication can generate wildcard certificates. You only need to configure the API access key of the DNS resolution service provider for authentication. Here we use DNS verification to show you how to configure ACME.

Above us by setting — certificatesResolvers. Ali. Acme. DnsChallenge. The provider = alidns parameter to specify the specified DNS check of ali cloud, cloud to use ali DNS check we also need to configure the three environment variables: ALICLOUD_ACCESS_KEY, ALICLOUD_SECRET_KEY and ALICLOUD_REGION_ID respectively correspond to the keys of ali Cloud application development at ordinary times, which can be obtained by logging in ali Cloud background. Since these are relatively private information, So we use the Secret object to create:

$ kubectl create secret generic traefik-alidns-secret --from-literal=ALICLOUD_ACCESS_KEY=<aliyun ak> --from-literal=ALICLOUD_SECRET_KEY=<aliyun sk>--from-literal=ALICLOUD_REGION_ID=cn-beijing -n kube-system
Copy the code

Once created, this Secret is configured to Traefik’s application using the environment variable. Json file, or you will need to re-authenticate after Traefik reconstruction. Let’s Encrypt has a limit on the number of times the certificate can be authenticated. Finally, our complete list of Traefik configuration resources is as follows:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
  namespace: kube-system
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik
      terminationGracePeriodSeconds: 60
      tolerations:
      - operator: "Exists"
      nodeSelector:
        kubernetes.io/hostname: ydzs-master
      volumes:
      - name: acme
        hostPath:
          path: /data/k8s/traefik/acme
      containers:
      - image: Traefik: 2.1.1
        name: traefik
        ports:
        - name: web
          containerPort: 80
          hostPort: 80
        - name: websecure
          containerPort: 443
          hostPort: 443
        args:
        - --entryPoints.web.address=:80
        - --entryPoints.websecure.address=:443
        - --api=true
        - --api.dashboard=true
        - --ping=true
        - --providers.kubernetesingress
        - --providers.kubernetescrd
        - --log.level=INFO
        - --accesslog
        DNS authentication is enabled
        - --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
        # email configuration
        - [email protected]
        # Where to save the ACME certificate
        - --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json
        # Below is the CA service for testing. If HTTPS certificate generation is successful, remove the following parameters
        # - --certificatesresolvers.ali.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
        envFrom:
        - secretRef:
            name: traefik-alidns-secret
            # ALICLOUD_ACCESS_KEY
            # ALICLOUD_SECRET_KEY
            # ALICLOUD_REGION_ID
        volumeMounts:
        - name: acme
          mountPath: /etc/acme
        resources:
          requests:
            cpu: "50m"
            memory: "50Mi"
          limits:
            cpu: "200m"
            memory: "100Mi"
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        readinessProbe:
          httpGet:
            path: /ping
            port: 8080
          failureThreshold: 1
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        livenessProbe:
          httpGet:
            path: /ping
            port: 8080
          failureThreshold: 3
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
Copy the code

Just update the Traefik app. Now that the update is complete, let’s modify our whoami application above:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
  tls:
    certResolver: ali
    domains:
    - main: "*.qikqiak.com"
Copy the code

All else is the same, just change the TLS part to the ali certificate parser we defined. If we want to generate a wildcard certificate we can define the Domains parameter to specify it, then update the IngressRoute object, At this time, we will use HTTPS to access our application (of course, the domain name needs to be resolved on Aliyun DNS) :

We can see that the application is already a browser-trusted certificate, and when we look at the certificate we can also see that the certificate is a wildcard certificate.

The middleware

Middleware is a feature of Traefik2.0. We can choose different middleware to meet our needs. Traefik has built a lot of middleware with different functions, some of which can modify requests, headers, redirects, add authentication, etc. And middleware can also be used in a chain combination of ways to adapt to various situations.

Also the whoami this application we defined above, for example, we can visit https://who.qikqiak.com/tls asked applications, but if we use HTTP to access? Not line, will be 404, because we have no simple port 80 the entry point, So to access an application over HTTP, we naturally need to listen to the web entry point:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls-http
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
Copy the code

Note that the entryPoints for IngressRoute are web, and the object is created so that we can access the application via HTTP.

But what if we only want users to access the application over HTTPS? In Traefik, it is also possible to configure force-jump from HTTP to HTTPS, but this function is now provided through middleware. As shown below, we use redirectScheme middleware to create a service that provides forced jumps:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
spec:
  redirectScheme:
    scheme: https
Copy the code

This middleware is then attached to the HTTP service because HTTPS does not need to redirect:

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls-http
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
    middlewares: 
    - name: redirect-https
Copy the code

If you want to access the HTTP service, it will automatically redirect to HTTPS. For more information on the use of middleware, see the documentation Traefik Docs.

Gray released

One of the more powerful features of Traefik2.0 is grayscale publishing, which is sometimes called Canary publishing. Grayscale publishing allows some of the tested services to participate in the online testing to see if they are required to go online.

For example, now we have two services named Appv1 and Appv2, and we want to use Traefik to control our traffic, routing 3⁄4 traffic to Appv1 and 1/4 traffic to Appv2, At this point you can leverage the ** weighted polling (WRR) ** provided in Traefik2.0 to implement this functionality, first deploying the above two services in a Kubernetes cluster. In order to compare the results, we provide two services here: whoAMI and Nginx, which are convenient for testing.

The list of resources for the appv1 service is as follows :(appv1.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv1
spec:
  selector:
    matchLabels:
      app: appv1
  template:
    metadata:
      labels:
        use: test
        app: appv1
    spec:
      containers:
      - name: whoami
        image: containous/whoami
        ports:
        - containerPort: 80
          name: portv1
---
apiVersion: v1
kind: Service
metadata:
  name: appv1
spec:
  selector:
    app: appv1
  ports:
  - name: http
    port: 80
    targetPort: portv1
Copy the code

The resource list of the appv2 service is as follows :(appv2.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv2
spec:
  selector:
    matchLabels:
      app: appv2
  template:
    metadata:
      labels:
        use: test
        app: appv2
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: portv2
---
apiVersion: v1
kind: Service
metadata:
  name: appv2
spec:
  selector:
    app: appv2
  ports:
  - name: http
    port: 80
    targetPort: portv2
Copy the code

Create the two services directly:

$ kubectl apply -f appv1.yaml
$ kubectl apply -f appv2.yaml
#Run the following command to check whether the service is running successfully
$ kubectl get pods -l use=test
NAME                     READY   STATUS    RESTARTS   AGE
appv1-58f856c665-shm9j   1/1     Running   0          12s
appv2-ff5db55cf-qjtrf    1/1     Running   0          12s
Copy the code

In Traefik2.1, a CRD resource for TraefikService is added. We can directly use this object to configure WRR. In previous versions, we need to use File Provider, which is troublesome.

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: app-wrr
spec:
  weighted:
    services:
      - name: appv1
        weight: 3  # define weight
        port: 80
        kind: Service  # Optional, default is Service
      - name: appv2
        weight: 1
        port: 80
Copy the code

Then create an IngressRoute resource object for our grayscale published service :(ingressroute.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: wrringressroute
  namespace: default
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`wrr.qikqiak.com`)
    kind: Rule
    services:
    - name: app-wrr
      kind: TraefikService
Copy the code

The Kubernetes domain name wrr.qikqiak.com is used as the TraefikService object. The Kubernetes domain name wrr.qikqiak.com is used as the TraefikService object. Go to the browser 4 times in a row, and we can observe that appv1 receives 3 requests, while appv2 receives only 1 request, which matches our 3:1 weighting above.

Traffic copy

In addition to grayscale publishing, Traefik 2.0 also introduces traffic mirroring, which is a way to copy incoming traffic and simultaneously send it to other services, receiving a given percentage of requests while ignoring the response to those requests.

In version 2.1, we can already configure the TraefikService resource object. Now we deploy two whoAMI services. The resource manifest file is as follows:

apiVersion: v1
kind: Service
metadata:
  name: v1
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: v1
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: v1
  labels:
    app: v1
spec:
  selector:
    matchLabels:
      app: v1
  template:
    metadata:
      labels:
        app: v1
    spec:
      containers:
        - name: v1
          image: nginx
          ports:
            - name: web
              containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: v2
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: v2
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: v2
  labels:
    app: v2
spec:
  selector:
    matchLabels:
      app: v2
  template:
    metadata:
      labels:
        app: v2
    spec:
      containers:
        - name: v2
          image: nginx
          ports:
            - name: web
              containerPort: 80
Copy the code

Create the above resource object directly:

$ kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
v1-77cfb86999-wfbl2                       1/1     Running   0          94s
v2-6f45d498b7-g6qjt                       1/1     Running   0          91s
$ kubectl get svc NAME TYPE cluster-ip external-ip PORT(S) AGE V1 ClusterIP 10.96.218.173 < None > 80/TCP 99S V2 ClusterIP 10.99.98.48 <none> 80/TCP 96sCopy the code

Now we create an IngressRoute object that copies 50% of service v1’s traffic to service v2, as shown in the following resource object :(mirror-ingress-route.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: app-mirror
spec:
  mirroring:
    name: v1 # send 100% requests to K8S Service "v1"
    port: 80
    mirrors:
    - name: v2 Then copy 50% of the requests to v2
      percent: 50
      port: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: mirror-ingress-route
  namespace: default
spec:
  entryPoints:
  - web
  routes:   
  - match: Host(`mirror.qikqiak.com`)
    kind: Rule
    services:
    - name: app-mirror
      kind: TraefikService Use the declared TraefikService instead of the K8S Service
Copy the code

Then create the resource object directly:

$ kubectl apply -f mirror-ingress-route.yaml 
ingressroute.traefik.containo.us/mirror-ingress-route created
traefikservice.traefik.containo.us/mirroring-example created
Copy the code

At this time, we visited mirror.qikqiak.com four times in a row in the browser and found that half of the requests also appeared in the v2 service:

TCP

In addition, Traefik2.0 already supports TCP services. Let’s use Mongo as an example to understand how Traefik supports TCP services.

Simple TCP service

Start by deploying a normal mongo service with the following resource manifest file :(mongo.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-traefik
  labels:
    app: mongo-traefik
spec:
  selector:
    matchLabels:
      app: mongo-traefik
  template:
    metadata:
      labels:
        app: mongo-traefik
    spec:
      containers:
      - name: mongo
        image: Mongo: 4.0
        ports:
        - containerPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-traefik
spec:
  selector:
    app: mongo-traefik
  ports:
  - port: 27017
Copy the code

Create mongo app directly:

$ kubectl apply -f mongo.yaml
deployment.apps/mongo-traefik created
service/mongo-traefik created
Copy the code

Once created, you can configure a route for the Mongo service. Traefik requires SNI to use TCP route configuration, and SNI relies on TLS, so we need to configure the certificate. If there is no certificate, we can use wildcard * to configure. Create a CRD object of type IngressRouteTCP (mongo-ingressroute-tcp.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`*`)
    services:
    - name: mongo-traefik
      port: 27017
Copy the code

Note that entryPoints are defined by entryPoints in the static configuration of Traefik. We can use 80 and 443. However, you can also add a special entry point for the Mongo service:

.
- image: Traefik: 2.1.1
  name: traefik
  ports:
  - name: web
    containerPort: 80
    hostPort: 80
  - name: websecure
    containerPort: 443
    hostPort: 443
  - name: mongo
    hostPort: 27017
    containerPort: 27017
  args:
  - --entryPoints.web.address=:80
  - --entryPoints.websecure.address=:443
  - --entryPoints.mongo.address=:27017
  .
Copy the code

Hostports are added to entryPoints so that services can be accessed through node ports. For more information about entryPoints entryPoints, see the documentation entryPoints.

After updating Traefik, we can create the above resource object directly:

$ mongo-ingressroute-tcp.yaml
ingressroutetcp.traefik.containo.us/mongo-traefik-tcp created
Copy the code

Once created, we can also go to Traefik’s Dashboard page to see if it works:

Then we configure a domain name mongo.local to resolve to the node where Traefik is located, and then connect to the Mongo service via port 27017:

$ mongo --host mongo.local --port 27017Mongo (75240,0 x1075295C0) malloc: *** malloc_zone_unregister() failed for 0x7fffa56f4000 MongoDB shell version: 2.6.1 connecting to: mongo. Local: 27017 / test> show dbsAdmin 0.000GB config 0.000GB local 0.000GBCopy the code

At this point we are done exposing the Mongo (TCP) service to external users.

TCP with TLS certificate

The mongo service deployed above is a normal service, which is brokered by Traefik, but sometimes the Mongo service itself is provided in the form of TLS certificates for security purposes. Here is a script file used to generate mongo TLS certificates: (the generate – certificates. Sh)

#! /bin/bash
#
# From https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89set -eu -o pipefail DOMAINS="${1}" CERTS_DIR="${2}" [ -d "${CERTS_DIR}" ] CURRENT_DIR="$(cd "$(dirname "${0}")" && pwd -P)" GENERATION_DIRNAME="$(echo "${DOMAINS}" | cut -d, -f1)" rm -rf "${CERTS_DIR}/${GENERATION_DIRNAME:? }" "${CERTS_DIR}/certs" echo "== Checking Requirements..." command -v go >/dev/null 2>&1 || echo "Golang is required" command -v minica >/dev/null 2>&1 || go get github.com/jsha/minica >/dev/null echo "== Generating Certificates for the following domains: ${DOMAINS}..." cd "${CERTS_DIR}" minica --ca-cert "${CURRENT_DIR}/minica.pem" --ca-key="${CURRENT_DIR}/minica-key.pem" --domains="${DOMAINS}" mv "${GENERATION_DIRNAME}" "certs" cat certs/key.pem certs/cert.pem > certs/mongo.pem echo "== Certificates Generated in the directory ${CERTS_DIR}/certs"Copy the code

Place the above certificate under the certs directory, then we create a directory called 02-TLS-mongo and run the following command under this directory to generate the certificate:

$bash .. /certs/generate-certificates.sh mongo.local .
== Checking Requirements...
== Generating Certificates for the following domains: mongo.local...
Copy the code

The last directory is as follows, and the certs directory containing the certificate is generated under the 02-TLS-mongo directory:

$ tree .. ├ ─ ─ 01 - mongo │ ├ ─ ─ mongo - ingressroute - TCP. Yaml │ └ ─ ─ mongo. Yaml ├ ─ ─ 02 - TLS - mongo │ └ ─ ─ certs │ ├ ─ ─ cert. Pem │ ├ ─ ─ Key. Pem │ └ ─ ─ mongo. Pem └ ─ ─ certs ├ ─ ─ the generate - certificates. Sh ├ ─ ─ minica - key. Pem └ ─ ─ minica. PemCopy the code

To include the certificate contents, run the following command in the directory 02-TLS-mongo /certs:

$ kubectl create secret tls traefik-mongo-certs --cert=cert.pem --key=key.pem
secret/traefik-mongo-certs created
Copy the code

Then update the IngressRouteTCP object to add TLS configuration:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`mongo.local`)
    services:
    - name: mongo-traefik
      port: 27017
  tls: 
    secretName: traefik-mongo-certs
Copy the code

Also updated, now when we directly access the app, we will be hung because we did not provide a certificate:

$ mongo --host mongo.local --port 27017MongoDB shell version: 2.6.1 connecting to: mongo1. Local :27017/testCopy the code

At this time we can bring the certificate to connect:

$mongo --host mongo.local --port 27017 --ssl --sslCAFile=.. /certs/minica.pem --sslPEMKeyFile=./certs/mongo.pemMongo shell version v4.0.3 connecting to: mongo: / / mongo. Local: 27017 / Implicit session: session {" id ": UUID(" e7409EF6-8ebe-4C57A-9642-42059bdb477b ")} MongoDB server version: 4.0.14......> show dbs;Admin 0.000GB config 0.000GB local 0.000GBCopy the code

If you use a different domain name to connect to the TCP server, you will get an error, because now you specify a specific HostSNI:

$mongo --host mongo.k8s.local --port 27017 --ssl --sslCAFile=.. /certs/minica.pem --sslPEMKeyFile=./certs/mongo.pemMongoDB Shell Version V4.0.3 Connecting to: Mongo: / / mongo. K8s. Local: 27017 / T15:2019-12-29 03:52. 424 + 0800 E NETWORK [js] the SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; Connection Rejected 2019-12-29T15:03:52.429+0800 E QUERY [js] Error: couldn't connect to server mongo.qikqiak.com:27017, connection attempt failed: SSLHandshakeFailed: SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; connection rejected : connect@src/mongo/shell/mongo.js:257:13 @(connect):1:6 exception: connect failedCopy the code

We can also use ACME to provide us with a valid certificate, so that we do not need to specify a certificate for connection use, as shown below:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`mongo.qikqiak.com`)
    services:
    - name: mongo-traefik
      port: 27017
  tls:
    certResolver: ali
    domains:
    - main: "*.qikqiak.com"
Copy the code

So when we connect, all we need is the following command:

$ mongo --host mongo.qikqiak.com --port 27017 --ssl
Copy the code

Scan the following QR code (or search k8S technology circle on wechat) to follow our wechat public account, reply to our wechat public account and join our Kubernetes discussion group to learn together.