Skip to content

Commit

Permalink
Elaborate the docs, add a faq section (#109)
Browse files Browse the repository at this point in the history
* docs: elaborate the docs, add a faq section

* docs: fix a messed up command

* docs: update docs to reference v0.1 release

* docs(faq): fix stray whitespace

* docs: restructure docs for a leaner README

* docs: move first run section back to main readme

* docs: fix references to packages

* docs: fix reference to gke tutorial

* docs: fix missing source flag in examples

* docs: fix missing provider flag in examples

* docs: mention ingress support in main readme
  • Loading branch information
linki authored and Yerken committed Mar 30, 2017
1 parent f3c1d0f commit 5ff8015
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 97 deletions.
145 changes: 109 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,132 @@
# External DNS
[![Build Status](https://travis-ci.org/kubernetes-incubator/external-dns.svg?branch=master)](https://travis-ci.org/kubernetes-incubator/external-dns)
[![Coverage Status](https://coveralls.io/repos/github/kubernetes-incubator/external-dns/badge.svg?branch=master)](https://coveralls.io/github/kubernetes-incubator/external-dns?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-incubator/external-dns)](https://goreportcard.com/report/github.com/kubernetes-incubator/external-dns)
[![GitHub release](https://img.shields.io/github/release/kubernetes-incubator/external-dns.svg)](https://github.com/kubernetes-incubator/external-dns/releases)

`external-dns` synchronizes external DNS servers (e.g. Google CloudDNS) with exposed Kubernetes Services and Ingresses.
ExternalDNS synchronizes exposed Services and Ingresses with cloud DNS providers.

This is a new Kubernetes Incubator project and will incorporate features from the following existing projects:
# Motivation

* [Kops DNS Controller](https://github.com/kubernetes/kops/tree/master/dns-controller)
* [Mate](https://github.com/zalando-incubator/mate)
* [wearemolecule/route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes)
Inspired by Kubernetes' cluster-internal [DNS server](https://github.com/kubernetes/dns) ExternalDNS intends to make Kubernetes resources discoverable via public DNS servers. Similarly to KubeDNS it retrieves a list of resources from the Kubernetes API, such as Services and Ingresses, to determine a desired list of DNS records. However, unlike KubeDNS it's not a DNS server itself but merely configures other DNS providers accordingly, e.g. AWS Route53 or Google CloudDNS.

## Current Status
In a broader sense, it allows you to control DNS records dynamically via Kubernetes resources in a DNS provider agnostic way.

The project just started and isn't in a usable state as of now. The current roadmap looks like the following.
# Getting started

* Create an MVP that allows managing DNS names for Service resources via Google CloudDNS with the official annotation set. (Done)
* Add support for Ingress and Node resources as well as AWS Route53.
* Add support for the annotation semantics of the three parent projects so that `external-dns` becomes a drop-in replacement for them.
* Switch from regular sync-only to watch and other advanced topics.
ExternalDNS' current release is `v0.1` which allows to keep a managed zone in Google's [CloudDNS](https://cloud.google.com/dns/docs/) service synchronized with Services of `type=LoadBalancer` in your cluster.

Please have a look at [the milestones](https://github.com/kubernetes-incubator/external-dns/milestones) to find corresponding issues.
In this release ExternalDNS is limited to a single managed zone and takes full ownership of it. That means if you have any existing records in that zone they will be removed. We encourage you to try out ExternalDNS in its own zone first to see if that model works for you. However, ExternalDNS, by default, runs in dryRun mode and won't make any changes to your infrastructure. So, as long as you don't change that flag, you're safe.

## Features
Make sure you meet the following prerequisites:
* You have a local Go 1.7+ development environment.
* You have access to a Google project with the DNS API enabled.
* You have access to a Kubernetes cluster that supports exposing Services, e.g. GKE.
* You have a properly setup, **unused** and **empty** hosted zone in Google CloudDNS.

* External DNS should be able to create/update/delete records on multiple cloud providers
* The used cloud provider should be configurable at runtime
* External DNS should take the ownership of the records created by it
* It should support Kubernetes Services with `type=Loadbalancer` and `type=NodePort`, Ingresses and Nodes
* Allow to customize external name via annotations
* It should be fault tolerance to individual pod failures
* Support weighted records annotations - allow different resources share same hostname, and respective weighted records should be created.
* Support multiple hosted zones - therefore External DNS should be able to create records as long as there exist a hosted zone matching the desired hostname
First, get ExternalDNS.

## Nice to have
```console
$ go get -u github.com/kubernetes-incubator/external-dns
```

* Should do smart cloud provider updates, i.e. Cloud Provider API should be called only when necessary
* High Availability - should be possible to run multiple instances of External DNS
* Should be able to monitor resource changes via K8S API for quick updates
* New DNS record sources (e.g. TPRs) and targets (e.g. Azure DNS) should be pluggable and easy to add
Run an application and expose it via a Kubernetes Service.

## Example
```console
$ kubectl run nginx --image=nginx --replicas=1 --port=80
$ kubectl expose deployment nginx --port=80 --target-port=80 --type=LoadBalancer
```

The [tutorials](docs/tutorials/gke.md) section contains a detailed example of how to setup `external-dns` on Google Container Engine.
Annotate the Service with your desired external DNS name. Make sure to change `example.org` to your domain and that it includes the trailing dot.

## Building
```console
$ kubectl annotate service nginx "external-dns.alpha.kubernetes.io/hostname=nginx.example.org."
```

You need a working Go 1.7+ development environment. Then run `make build` to build `external-dns` for your platform. The binary will land at `build/external-dns`.
Run a single sync loop of ExternalDNS locally. Make sure to change the Google project to one you control and the zone identifier to an **unused** and **empty** hosted zone in that project's Google CloudDNS.

## Getting involved!
```console
$ external-dns --zone example-org --provider google --google-project example-project --source service --once
```

Want to contribute to External DNS? We would love the extra help from the community.
This should output the DNS records it's going to modify to match the managed zone with the DNS records you desire.

Reach out to us on [Kubernetes slack](https://github.com/kubernetes/community#slack-chat).
Once you're satisfied with the result you can run ExternalDNS like you would run it in your cluster: as a control loop and not in dryRun mode.

```console
$ external-dns --zone example-org --provider google --google-project example-project --source service --dry-run=false
```

Check that ExternalDNS created the desired DNS record for your service and that it points to its load balancer's IP. Then try to resolve it.

```console
$ dig +short nginx.example.org.
104.155.60.49
```

Now you can experiment and watch how ExternalDNS makes sure that your DNS records are configured as desired. Here are a couple of things you can try out:
* Change the desired hostname by modifying the Service's annotation.
* Recreate the Service and see that the DNS record will be updated to point to the new load balancer IP.
* Add another Service to create more DNS records.
* Remove Services to clean up your managed zone.

The [tutorials](docs/tutorials) section contains examples including Ingress resources and show how to setup ExternalDNS in different environments, such as other cloud providers and alternative ingress controllers.

# Roadmap

ExternalDNS was built with extensibility in mind. Adding and experimenting with new DNS providers and sources of desired DNS records should be as easy as possible. In addition, it should also be possible to modify how ExternalDNS behaves, e.g. whether it should add but must never delete records.

Furthermore, we're working on an ownership system that allows ExternalDNS to keep track of the records it created and will allow it to never modify records it doesn't have control over.

Here's a rough outline on what is to come:

### v0.1

* Support for Google CloudDNS
* Support for Kubernetes Services

### v0.2

* Support for AWS Route53
* Support for Kubernetes Ingresses

### v0.3

* Support for AWS Route53 via ALIAS
* Support for multiple zones
* Ownership System

### v1.0

* Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/master/dns-controller)
* Ability to replace Zalando's [Mate](https://github.com/zalando-incubator/mate)
* Ability to replace Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes)

The [FAQ](docs/faq.md) contains additional information and addresses several questions about key concepts of ExternalDNS.

Also have a look at [the milestones](https://github.com/kubernetes-incubator/external-dns/milestones) to get an idea of where we currently stand.

### Yet to be defined

* Support for CoreDNS and Azure DNS
* Support for record weights
* Support for different behavioral policies
* Support for Services with `type=NodePort`
* Support for TPRs
* Support for more advanced DNS record configurations

# Contributing

We encourage you to get involved with ExternalDNS, as users as well as contributors. Read the [contributing guidelines](CONTRIBUTING.md) and have a look at [the contributing docs](docs/contributing/getting-started.md) to learn about building the project, the project structure and the purpose of each package.

Feel free to reach out to us on the [Kubernetes slack](http://slack.k8s.io) in the #sig-network channel.

# Heritage

ExternalDNS is an effort to unify the following similar projects in order to bring the Kubernetes community an easy and predictable way of managing DNS records across cloud providers based on their Kubernetes resources.

* Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/master/dns-controller)
* Zalando's [Mate](https://github.com/zalando-incubator/mate)
* Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes)

## Kubernetes Incubator

Expand All @@ -64,5 +138,4 @@ The incubator team for the project is:
* Champion: Tim Hockin (@thockin)
* SIG: sig-network


For more information about sig-network such as meeting times and agenda, check out the community site.
For more information about sig-network such as meeting times and agenda, check out the [community site](https://github.com/kubernetes/community/tree/master/sig-network).
25 changes: 25 additions & 0 deletions docs/contributing/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Project structure

### Building

You can build ExternalDNS for your platform with `make build`. The binary will land at `build/external-dns`.

### Design

ExternalDNS's sources of DNS records live in package [source](../../source). They implement the `Source` interface that has a single method `Endpoints` which returns the represented source's objects converted to `Endpoints`. Endpoints are just a tuple of DNS name and target where target can be an IP or another hostname.

For example, the `ServiceSource` returns all Services converted to `Endpoints` where the hostname is the value of the `external-dns.alpha.kubernetes.io/hostname` annotation and the target is the IP of the load balancer.

This list of endpoints is passed to the [Plan](../../plan) which determines the difference between the current DNS records and the desired list of `Endpoints`.

Once the difference has been figured out the list of intended changes is passed to a `Provider` which live in the [provider](../../provider) package. The provider is the adapter to the DNS provider, e.g. Google CloudDNS. It implements two methods: `ApplyChanges` to apply a set of changes and `Records` to retrieve the current list of records from the DNS provider.

The orchestration between the different components is controlled by the [controller](../../controller).

You can pick which `Source` and `Provider` to use at runtime via the `--source` and `--provider` flags, respectively.

### Adding a DNS provider

A typical way to start on, e.g. a CoreDNS provider, would be to add a `coredns.go` to the providers package and implement the interface methods. Then you would have to register your provider under a name in `main.go`, e.g. `coredns`, and would be able to trigger it's functions via setting `--provider=coredns`.

Note, how your provider doesn't need to know anything about where the DNS records come from, nor does it have to figure out the difference between the current and the desired state, it merely executes the actions calculated by the plan.
78 changes: 78 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Frequently asked questions

### When is this useful to me?

You probably have created many Deployments in the past. Often you would expose your Deployment to the Internet by creating a Service with a type of LoadBalancer. Depending on your environment this usually assigns a random publicly available endpoint to your service at which you can access it from anywhere in the world. On Google Container Engine this is a public IP address.

```console
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx 10.3.249.226 35.187.104.85 80:32281/TCP 1m
```

However, dealing with IPs for service discovery isn't nice so you would probably register this IP with your DNS provider under a better name, probably corresponding to your service name. If that IP were to change you would update the DNS record accordingly.

Those times are over, ExternalDNS takes care of that last part for you and keeps your DNS records synchronized with your external entry points.

It starts to become more clear when you use Ingresses to allow external traffic into your cluster. Via Ingress you can tell Kubernetes to route traffic to different services based on certain HTTP request attributes, e.g. the Host header.

```console
$ kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
entrypoint frontend.example.org,backend.example.org 35.186.250.78 80 1m
```

But there's nothing that actually makes clients to resolve those hostnames to the Ingress' IP address. Again, you would register each entry with your DNS provider and only if you're lucky you could use a wildcard like in this example.

However, EnternalDNS can solve that for you as well.

### What DNS providers are supported?

There will be support for Google CloudDNS and AWS Route53 with ALIAS records. There's a desire to support CoreDNS as well as Azure DNS. We're open to review and add other providers if the community believes them valuable.

Initial support for Google CloudDNS is targeted for the `v0.1` release. You can already test it with version `v0.1.0-beta.1` onwards.
Initial support for AWS Route53 is targeted for the `v0.2` release. However, you can already test it with CNAME instead of ALIAS using version `v0.1.0`.
There are no plans regarding other providers at the moment.

### What Kubernetes objects are supported?

There will be support for Services exposed via type LoadBalancer and for the hostnames defined in Ingress objects. It also seems useful to expose Services with type NodePort to point to your cluster's nodes directly, but there's no commitment, yet.

### Which Service and Ingress controllers are supported?

Regarding Services we'll support the OSI Layer 4 load balancers that are created by Kubernetes on AWS as well as on Google Container Engine and possibly other clusters running on Google Compute Engine.

Regarding Ingress we'll support:
* Google's Ingress Controller on GKE that integrates with their Layer 7 load balancers (GLBC)
* nginx-ingress-controller v0.9.x with a fronting Service
* Zalando's [AWS Ingress controller](https://github.com/zalando-incubator/kube-ingress-aws-controller) based on AWS ALBs and [Skipper](https://github.com/zalando/skipper)

### What about those other implementations?

ExternalDNS is a joint effort to unify different projects accomplishing the same goals in the past, namely:

* Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/master/dns-controller)
* Zalando's [Mate](https://github.com/zalando-incubator/mate)
* Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes)

We strive to make the migration from these implementations a smooth experience. This means for some time we'll support their annotation semantics in ExternalDNS as well as allow both implementations to run side-by-side. This allows you to migrate incrementally and slowly face out the other implementation.

### How does it work with other implementations and legacy records?

ExternalDNS will allow you to opt-in any Services and Ingresses you want it to consider by an annotation. This way it can co-exist with other implementations running in the same cluster if they support this pattern as well. However, we'll most likely declare ExternalDNS to be the default implementation in the future. This means ExternalDNS will consider Services and Ingresses that don't specifically declare which controller they want to be processed by, similar to the `ingress.class` annotation on GKE.

### I'm afraid you mess up my DNS records!

ExternalDNS will implement the concept of owning DNS records. It means that ExternalDNS keeps track of which records it has control over and will never modify any records of which it doesn't. This is a fundamental requirement to operate ExternalDNS safely when there might be other actors creating DNS records in the same target space.

However, this is a delicate topic and hasn't found its way into ExternalDNS, yet.

### Does anyone use ExternalDNS in production?

No, but ExternalDNS is heavily influenced by Zalando's [Mate](https://github.com/zalando-incubator/mate) which is used in production on AWS. If you want to adopt this approach and need a solution now then try Mate. Otherwise we encourage you to stick with ExternalDNS and help us make it work for you.

### How can we start using ExternalDNS?

ExternalDNS is in an early state and not recommended for production use, yet. However, you can start trying it out on a non-production GKE cluster following [the GKE tutorial](tutorials/gke.md).

Cluster's on AWS that want to make use of Route53 work very similar but a tutorial is still on our TODO list.
59 changes: 0 additions & 59 deletions docs/project-structure.md

This file was deleted.

4 changes: 2 additions & 2 deletions docs/tutorials/gke.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Setting up external-dns on Google Container Engine
# Setting up ExternalDNS on Google Container Engine

This tutorial describes how to setup `external-dns` for usage within a GKE cluster.

Expand Down Expand Up @@ -73,7 +73,7 @@ spec:
spec:
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:v0.1.0-beta.0
image: registry.opensource.zalan.do/teapot/external-dns:v0.1.0
args:
- --in-cluster
- --zone=external-dns-test-gcp-zalan-do
Expand Down

0 comments on commit 5ff8015

Please sign in to comment.