Skip to main content

Deploying a public service

This guide will walk you through deploying an instance of the nginx and expose it to the public.

Preparing your domain

In order to deploy a public service to the cluster, you will need a valid domain. Once you own a domain, you will need to point your domain to the cluster. There are two methods to achieve this.

CNAME record (preferred)

A CNAME record can be thought of as an "alias" for another domain. Head over to the DNS settings of your domain registrar and add a CNAME record to the canonical domain of the cluster:

kube01.kubinity.com

A and AAAA records

As an alternative to a CNAME record, you can create an A record for each of these IP addresses:

78.46.201.114
49.12.219.73
168.119.170.212

If you want to use IPv6 addresses, make sure to create three AAAA records pointing to these domains:

2a01:4f8:c2c:2d76::1
2a01:4f8:c17:44e2::1
2a01:4f8:1c1c:8523::1

Note: It's advised to create one record for each IP to ensure a higher availability.

Todo: These IP addresses are currently subject to change. There should be a load balancer in front of these addresses instead.

Deploying an application

With your domain set up, we're ready to get our hands dirty! The way you usually deploy an application to a Kubernetes cluster is by creating so called "resource definitions", also commonly called "manifests".

To make your life easier, it's advised that you keep a directory containing all your manifests. This makes it easier to re-deploy a resource later in case it is accidentally deleted. For inspiration about how this might look, you can take a look at the manifests of this cluster.

We already talked about creating a Deployment resource in our Getting started guide. Here's the manifest, in case you haven't yet deployed it:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
memory: 10Mi
cpu: 10m
limits:
memory: 20Mi
cpu: 20m

Notice that in the template section, we assigned the deployment the label app with a value of nginx. This will become relevant in just a bit.

Next up, you will need to create a Service that sits in front of that deployment. In a more complex application, services will handle load balancing and other fancy stuff. For us, a service just defines what ports we want to expose to other parts of the cluster.

# service.yml

apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
selector:
app: nginx
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80

Here, we create a Service called "hello-world" and tell Kubernetes to forward incoming traffic to every pod where the label app matches the name nginx. Since we have a Deployment with such a label, every pod deployed by that Deployment will be matched by our service. We also say that traffic hitting our service on port 80 should be forwarded to port 80 of the container.

The last piece of the puzzle is the Ingress. Ingresses make up the "outer layer" of a cluster. They match incoming traffic from outside the cluster to services running in the cluster.

# ingress.yml

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: hello-world
annotations:
kubernetes.io/ingress.class: nginx # Required

spec:
rules:
- host: foo.bar # Your domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-world
port:
number: 80

The Kubinity cluster runs NGINX as a public Ingress controller. Every request from and to the cluster goes through this controller. By creating an Ingress, we tell NGINX that we want to handle the traffic for a specific hostname, which is the domain we prepared earlier. Note that there can be many ingresses in a cluster at the same time.

After deploying all these manifests, you should be able to open your browser and navigate to your domain. If you have any questions, please let us know.

TODO: Link to contact information

Securing your site with TLS

To make securing your site via HTTPS as convenient as possible, you can make use of our instance of cert-manager, which is running in the cluster.

To issue certificates, you first need to deploy an Issuer to your namespace. As the name implies, an issuer is responsible to issue TLS certificates for your domain. Here's an example for an issuer that uses LetsEncrypt to fetch free certificates:

# issuer.yml

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: example@yourdomain.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource used to store the account's private key.
name: letsencrypt-staging-account-key
solvers:
- http01:
ingress:
class: nginx

Notice that this issuer uses the staging environment of LetsEncrypt. The certificates issued by this environment are not considered secure, but they are great for testing the waters before generating a "real" certificate. If you directly use the production environment without testing your setup first, your account might run into a rate limit! To start issuing real certificates, either create a new Issuer or override the existing one with the URL of the LetsEncrypt production environment:

https://acme-staging-v02.api.letsencrypt.org/directory

Once you deployed the issuer, you should be able to generate certificates. You can now configure TLS on your existing ingress by adding the tls section like this:

# ingress.yml

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: hello-world
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/issuer: letsencrypt-staging

spec:
rules:
- host: mydomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-world
port:
number: 80
tls:
- hosts:
- mydomain.com
secretName: mydomain.com-tls # The certificate will be stored in this secret

Wait for a minute while cert-manager fetches your certificate, and you should see a Secret resource in your namespace, containing the certificate:

> kubectl get secrets

NAME TYPE DATA AGE
hello-world-issuer-account-key Opaque 1 6m
mydomain.com-tls kubernetes.io/tls 2 1m

And if everything went well, you can now access your site via HTTPS!