Cert Manager + Gateway API

Делаю:
2026.02.06


Не работает! Т.к. нет публичного адреса до хоста с kubernetes.


https://www.youtube.com/watch?v=XAcmHWZ02VI

https://github.com/marcel-dempers/docker-development-youtube-series/tree/master/kubernetes/cert-manager


$ kind create cluster --name certmanager --image kindest/node:v1.35.0


Deploy pods that require SSL\TLS


$ cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deploy
  labels:
    app: example-app
    test: test
  annotations:
    fluxcd.io/tag.example-app: semver:~1.0
    fluxcd.io/automated: 'true'
spec:
  selector:
    matchLabels:
      app: example-app
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: example-app
    spec:
      containers:
      - name: example-app
        image: aimvector/python:1.0.4
        imagePullPolicy: Always
        ports:
        - containerPort: 5000
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "256Mi"
            cpu: "500m"
      tolerations:
      - key: "cattle.io/os"
        value: "linux"
        effect: "NoSchedule"
EOF


$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: example-service
  labels:
    app: example-app
spec:
  type: ClusterIP
  selector:
    app: example-app
  ports:
    - protocol: TCP
      name: http
      port: 80
      targetPort: 5000
EOF


$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
example-deploy-6489756d87-4g5c5   1/1     Running   0          102s
example-deploy-6489756d87-d9tzr   1/1     Running   0          102s


Gateway API CRDs


$ kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml

This will install (Stable Channel):

  • Gateway Classes: kubectl get gatewayclass
  • Gateways: kubectl get gateway
  • HTTP Routes: kubectl get httproute

These APIs are part of the Experimental Channel:

  • TLS Routes: kubectl get tlsroute
  • TCP Routes: kubectl get tcproute
  • UDP Routes: kubectl get udproute

Note: Gateway API is very new, and all of the above is subject to change quite rapidly </br>


Install cert-manager

// install cert-manager
$ CHART_VERSION="v1.19.2"

// checkout the values
// $ helm show values oci://quay.io/jetstack/charts/cert-manager > kubernetes/cert-manager/default-values.yaml

$ helm install \
  cert-manager oci://quay.io/jetstack/charts/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version ${CHART_VERSION} \
  --set crds.enabled=true \
  --set config.enableGatewayAPI=true


$ kubectl -n cert-manager get pods
NAME                                      READY   STATUS    RESTARTS       AGE
cert-manager-7785549dcf-r8qtt             1/1     Running   5 (117s ago)   3m36s
cert-manager-cainjector-c898c8b47-2rhlh   1/1     Running   0              3m36s
cert-manager-webhook-758795746d-85lcp     1/1     Running   0              3m36s


Setup my DNS (У меня пока такого нет, точнее не хочется запарываться)

I can get the public IP address of my computer by running a simple command:

$ curl ifconfig.co

I can log into my DNS provider and point my DNS A record to my IP.
Also setup my router to allow 80 and 443 to come to my PC

Note: If you are running in the cloud, your Ingress controller or Gateway API and Cloud provider will give you a public IP and you can point your DNS to that accordingly.


Create a Gateway Class


$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: traefik
spec:
  controllerName: traefik.io/gateway-controller
EOF

Create a Gateway


$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway-api
  namespace: default
spec:
  gatewayClassName: traefik

  # Only Routes from the same namespace are allowed.
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: Same  #or All or Selector

    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: secret-tls
            namespace: default
      allowedRoutes:
        namespaces:
          from: Same
EOF


Create a Gateway API Let’s Encrypt Issuer

We create a ClusterIssuer for Ingress that allows us to issue certs in any namespace


$ cat << EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-issuer
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-issuer-key
    solvers:
    - http01:
        gatewayHTTPRoute:
          parentRefs:
            - name: gateway-api
              namespace: default
              kind: Gateway
EOF


// check the issuer
$ kubectl describe clusterissuer letsencrypt-issuer


Issue Certificate


$ cat << EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-app
  namespace: default
spec:
  dnsNames:
    - test.marceldempers.dev
  secretName: secret-tls
  issuerRef:
    name: letsencrypt-issuer
    kind: ClusterIssuer
EOF


// check the cert issue status
$ kubectl describe certificate example-app


// READY - FALSE!
$ kubectl get CertificateRequest
NAME            APPROVED   DENIED   READY   ISSUER               REQUESTER                                         AGE
example-app-1   True                False   letsencrypt-issuer   system:serviceaccount:cert-manager:cert-manager   14m


$ kubectl get Orders
NAME                       STATE     AGE
example-app-1-3040804028   pending   17m


$ kubectl describe Orders example-app-1-3040804028


// TLS created as a secret
$ kubectl get secrets

Не создался. А должен быть.

NAME                  TYPE                                  DATA   AGE
secret-tls       kubernetes.io/tls                     2      1m


$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-route
  namespace: default

spec:
  parentRefs:
  - name: gateway-api
    sectionName: http
    kind: Gateway
  - name: gateway-api
    sectionName: https
    kind: Gateway

  hostnames:
  - test.marceldempers.dev

  rules:
  - backendRefs:
    - name: example-service
      port: 80
      weight: 1
EOF


// test TLS
$ curl https://test.marceldempers.dev
Hello World!


// cleanup
$ kubectl delete certificate example-app
$ kubectl delete clusterissuer letsencrypt-issuer
$ kubectl delete secret secret-tls