Endpoints

Using a Standard Endpoint

The standard way to expose your services to the internet is to use the following configuration:

tasks:
    deployment:
        deploy:
            # ...
            services:
                web:
                    specification:
                        accessibility:
                            from_external: true

This is fine for most purposes, but has it has three main limitations:

1) It presents difficulties when trying to whitelist IP addresses for authentication as the client IP address is not passed through to the service. This can be resolved by using an annotation, which ensures that the client IP address is passed through to the service:

tasks:
    deployment:
        deploy:
            # ...
            services:
                web:
                    endpoints:
                      - name: www
                        annotations:
                          service.beta.kubernetes.io/external-traffic: OnlyLocal
                    specification:
                        accessibility:
                            from_external: true

2) The IP addresses are chosen from a random pool and by default are not static, which means they cannot be reliably associated with a DNS record.

3) It uses a public IP address per service, which can be expensive.

Using a Load Balancer

Most cloud services offer the option of using a load balancer, which mitigates two of the above limitations - with a load balancer public IP addresses are passed through to the service, and the IP address of the load balancer is static so can be set up in a DNS record. However, using load balancers can also be expensive as you still use a public IP address for each service.

Using the Nginx Ingress Controller

Using the Nginx Ingress controller presents an option that mitigates all three of the above limitations, as it only requires one public IP address - a series of rules can be used to determine how inbound connections are directed to your services. The Nginx Ingress controller also allows SSL to be configured in one place so removes the need to configure SSL for each service independently.

Installation

ContinuousPipe currently provides no way to create the Nginx Ingress controller - this needs to be done as a manual step when setting up your Kubernetes cluster. Once the Ingress is deployed, it will be assigned an IP address from a random pool, which will then be static for the lifetime of the Ingress. The IP address of the manually deployed Ingress then needs to be set up in a DNS rule so that it is associated with your domain, unless you are using Cloudflare integration.

You need an Ingress controller to be deployed on your cluster first. You can use the ContinuousPipe Ingress controller or any of the official Kubernetes Ingress controllers.

ContinuousPipe Modifications

The Nginx Ingress controller used by ContinuousPipe is slightly modified from the default Kubernetes behaviour. The default Nginx Ingress controller only exposes port 443 if a SSL certificate with matching hostname is also configured. The ContinuousPipe Nginx Ingress controller extends that behaviour to allow port 443 to be exposed, using a wildcard SSL certificate if no matching hostname certificate is configured. Additionally, it allows Cloudflare SSL to be configured.

Nginx Ingress With No SSL

If you wish to use the Nginx Ingress without SSL, this can be done as follows:

tasks:
    # ...
    deployment:
        deploy:
            cluster: ${CLUSTER}
            services:
                web:
                    endpoints:
                        - name: webnossl
                          ingress:
                              class: nginx
                              host_suffix: '-example-with-no-ssl.yourdomain.com'
                    specification:
                        ports:
                          - 80

As you can see, the setup is quite straight forward. Within endpoints, the Ingress is defined as nginx. A host_suffix is supplied, which will be combined with the branch name to create the full URL e.g. a deployment of “master” branch would create an environment with URL “http://master-example-with-no-ssl.yourdomain.com”.

Additionally, port 80 is exposed, so traffic will just use HTTP.

Note

You will need to set up a wildcard DNS rule associating the Ingress IP address with your domain name for this example to work.

e.g. 123.123.123.123 *example-with-no-ssl.yourdomain.com

Nginx Ingress With Own SSL

If you wish to use the Nginx Ingress with SSL, this can be done as follows:

tasks:
    # ...
    deployment:
        deploy:
            cluster: ${CLUSTER}
            services:
                web:
                    endpoints:
                        - name: webwithssl
                          ingress:
                              class: nginx
                              host:
                                  expression: '"example-with-ssl.yourdomain.com"'
                          ssl_certificates:
                            - name: webwithssl
                              key: ${SSL_KEY}
                              cert: ${SSL_CERT}
                    specification:
                        ports:
                          - 80
                          - 443

This is similar to the previous configuration, but with important differences. Instead of using a host_suffix, a host expression is defined instead. This will create an environment using exactly “https://example-with-ssl.yourdomain.com".

The ssl_certificates section is used to define the certificate, which can be either an officially supplied certificate or a self signed certificate. As this isn’t something you want to store in version control, the key and cert properties instead reference variables ${SSL_KEY} and ${SSL_CERT} respectively. The values need to be entered into the ContinuousPipe console as explained when configuring a flow. The values entered should be base64 encoded.

In addition to port 80, port 443 is also exposed. This is needed to let ContinuousPipe know that you want to use HTTPS traffic.

Note

You will need to set up a DNS rule associating the Ingress IP address with your domain name for this example to work.

e.g. 123.123.123.123 example-with-ssl.yourdomain.com

Nginx Ingress With Wildcard SSL

If you wish to use the Nginx Ingress with wildcard SSL, this can be done as follows:

tasks:
    # ...
    deployment:
        deploy:
            cluster: ${CLUSTER}
            services:
                web:
                    endpoints:
                        - name: webwithwildcardssl
                          ingress:
                              class: nginx
                              host:
                                  expression: '"example-with-wildcard-ssl.yourdomain.com"'
                    specification:
                        ports:
                          - 80
                          - 443

This is similar to the previous configuration, but omits the ssl_certificates. However, as port 443 is still exposed ContinuousPipe will still set up SSL using wildcard certificates. This behaviour is distinct to the ContinuousPipe adaptation of the Nginx Ingress controller - the default Nginx Ingress controller would not set up SSL in this scenario.

Note

You will need to set up a wildcard DNS rule associating the Ingress IP address with your domain name for this example to work.

e.g. 123.123.123.123 *example-with-wildcard-ssl.yourdomain.com

Nginx Ingress With Cloudflare SSL

ContinuousPipe already has integration with Cloudflare when configuring endpoints directly. This integration can also be applied to the Nginx Ingress. The major advantage of this is that it does not need a DNS rule setting up in advance, as Cloudflare will create this automatically.

tasks:
    # ...
    deployment:
        deploy:
            cluster: ${CLUSTER}
            services:
                web:
                    endpoints:
                        - name: webwithcloudflaressl
                          cloud_flare_zone:
                              zone_identifier: ${CLOUD_FLARE_ZONE}
                              authentication:
                                  email: ${CLOUD_FLARE_EMAIL}
                                  api_key: ${CLOUD_FLARE_API_KEY}
                              proxied: true
                              record_suffix: '-example-with-cloudflare-ssl.continuouspipe.net'
                          ingress:
                              class: nginx
                              host_suffix: '-example-with-cloudflare-ssl.continuouspipe.net'
                    specification:
                        ports:
                          - 80
                          - 443

As you can see, the main difference is the addition of a cloud_flare_zone section, which defines how traffic should interact with Cloudflare. The values defined in cloud_flare_zone are explained in the integration with Cloudflare page.

Further down, the Ingress defines a host_suffix that matches the Cloudflare record_suffix, so that the environment URL and the Cloudflare DNS entry are matched.