Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A quickstart guide to deploying cert-manager and nginx-ingress on GKE

This is a quick recipe for deploying cert-manager and nginx-ingress on GKE to obtain SSL certificates from Lets Encrypt. Whilst this recipe is designed for Google Cloud Platform, it can easily be adapted for other cloud platforms.

We'll begin with a Kubernetes cluster, and we'll obtain authentication credentials.

gcloud container clusters get-credentials my-test-app
kubectl config current-context
kubectl get nodes

Next we're going to initialize Helm, adding RBAC support. A working example is shown below.

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

Next we apply these resources and initalize Helm on the cluster.

kubectl apply -f helm-rbac.yaml
helm init --service-account tiller --upgrade 
kubectl -n kube-system get pods -l name=tiller

Once Tiller has been deployed, we're going to deploy the cert-manager package. Note we're going to disable ingress-shim as we are going to use Nginx class instead.

git clone https://github.com/jetstack/cert-manager
git checkout v0.2.3
helm install --name cert-manager contrib/charts/cert-manager --set ingressShim.extraArgs='{--default-issuer-name=letsencrypt-prod,--default-issuer-kind=ClusterIssuer}' --set ingressShim.enabled=false --namespace kube-system
kubectl -n kube-system get pods

Once the cert-manager pod is running we can go ahead and deploy the nginx-ingress helm package, providing a service with Load Balancer type and the controller.

helm install --name ingress-my-test-app stable/nginx-ingress --set rbac.create='true'

Wait for the LB service to deploy, and obtain the External IP for the load balancer

kubectl get svc -l app=nginx-ingress,component=controller -o=jsonpath='{$.items[*].status.loadBalancer.ingress[].ip}'

Now head over to your DNS provider and point test.example.com at the IP address returned above. Allow enough time for DNS propagation before proceeding to the next step.

We can now create our Issue (Lets Encrypt prod) and Certificate resources.

Issuer example:

apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
  name: letsencrypt-prod
  namespace: default
spec:
  acme:
    # The ACME server URL
    server: https://acme-v01.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: your.name@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod-key
    # Enable HTTP01 validations
    http01: {}

Deployed using

kubectl apply -f issuer.yaml 

An example Certificate resource

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: my-test-app
  namespace: default
spec:
  secretName: my-test-app-crt
  commonName: test.example.com
  dnsNames:
  - test.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: Issuer
  acme:
    config:
    - http01:
        ingressClass: nginx
      domains:
      - test.example.com

Deployed by:

kubectl apply -f certificate.yaml

The next step is to deploy our Ingress resource, using this example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: my-test-app
  namespace: default
spec:
  rules:
    - host: test.example.com
      http:
        paths:
          - backend:
              serviceName: echoserver
              servicePort: 8080
            path: /echo
  tls:
    - hosts:
        - test.example.com
      secretName: my-test-app-crt

Deploy this ingress

kubectl apply -f ingress.yaml

The penultimate step is to deploy your backend App. For this example we'll use echoserver, but you can substitute it with your own app/service.

This example:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: echoserver
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: echoserver
    spec:
      containers:
      - image: gcr.io/google_containers/echoserver:1.0
        imagePullPolicy: Always
        name: echoserver
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: echoserver
spec:
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP
  selector:
    app: echoserver

can be deployed with

kubectl apply -f echoserver.yaml

Now, assuming everything above has worked you can test it.

# This should return 404 Not Found (the default backend)
curl -s https://test.example.com/

and

# This should return your request parameters (echoserver)
curl -s https://test.example.com/echo

Hopefully profit! and congratulations, your app is now served via TLS support.

@rodriguez-facundo

This comment has been minimized.

Copy link

@rodriguez-facundo rodriguez-facundo commented Apr 11, 2019

🎉 🎉 🎉 🎉

@esodell

This comment has been minimized.

Copy link

@esodell esodell commented May 17, 2019

Awesome explanation, thanks for that!

@andreasvirkus

This comment has been minimized.

Copy link

@andreasvirkus andreasvirkus commented Jan 6, 2020

The acme spec should now point to the v2 API

spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory

Ref: jetstack/cert-manager#1310 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment