Following up on the ‘Rails from “zero” to kubernetes‘ series, we’ll see today how to expose your service to the internet, since I think we all agree that mapping directly the port of your rails app to the internet is not a really wise choice.
Kubernetes has a “simple but works” solution called ingress, ingress is an HTTP proxy, it will work as a reverse proxy for HTTP and HTTPS for any service that exposes one one port.
You can also use ingress to map multiple hosts, or multiple paths to different services.
The important restriction for ingress is that it will only proxy the ports 80 and 443.
To continue with the same example that are already working, we’ll change the service from the previous post to ClusterIP, this way it will not be directly accessible to the outside world, the YAML will be like this:
apiVersion: v1 kind: Service metadata: labels: run: rails-sample name: rails-sample spec: ports: - port: 3000 protocol: TCP targetPort: 3000 selector: run: rails-sample type: ClusterIP
Then we’ll create an ingress mapping to that service, we’ll add some path mapping just to use it as an example, the initial ingress sample will map the path “/app” to our rails service like the sample bellow.
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: / name: rails-sample spec: rules: - http: paths: - path: /app backend: serviceName: rails-sample servicePort: 3000
The annotation “nginx.ingress.kubernetes.io/rewrite-target: /” will rewrite the paths to prevent errors in our application routing.
To check the ingress status and configuration, we can run the command “kubectl get ingress”, this will show the current ingress configuration and hosts mappings.
Ingress also supports name based virtual services, for example, if the host name “my.sample.service” points to your machine, you can map only this host name to your rails application with the following ingress configuration:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: rails-sample spec: rules: - host: my.sample.service http: paths: - backend: serviceName: rails-sample servicePort: 3000
The rewrite annotation and the “path” were removed because in this sample, we are mapping the host name directly to our rails app.
It is possible to merge both samples, mapping many host names and many paths inside each host name to a different service.
Since ingress is also an HTTPS proxy, it will be wise to provide a certificate for it, so we’ll map correctly our “my.sample.service” domain.
You can create a self signed certificate with the following commands:
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout sample.key -out sample.crt -subj "/CN=my.sample.service/O=my.sample.service" $ kubectl create secret tls rails-sample-tls --key sample.key --cert sample.crt -o=yaml > secret.yaml
in the “req” part, remember that the common name must match your domain name, in my case “my.sample.service”
That last command creates the secret in kubernetes and saves it in the “secret.yaml” file for future reference, of course in a real application you’ll not use a self signed certificate, but you’ll buy one for you real domain.
Now lets configure out ingress to use this certificate, we’ll just update the yaml file with the following config:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: rails-sample spec: tls: - hosts: - my.sample.service secretName: rails-sample-tls rules: - host: my.sample.service http: paths: - backend: serviceName: rails-sample servicePort: 3000
You can either “kubectl edit ingress rails-sample” and change it as shown above, or change your file and “kubectl apply” it.
Now you can edit your /etc/hosts file and add “127.0.0.1 my.sample.service” to it, and access your app through https://my.sample.service.
You’ll need to tell your browser to thrust your self signed certificate.
And with this you can now deploy your HTTP/HTTPS applications using ingress, but sometimes this is not good enough, for example if you need for some reason expose another port through HTTPS, ingress will not allow that, and if you need that, stay tuned in this blog, and we’ll see another options that I’ve used in the next post.
As always, please leave comments with any questions or suggestions.