Skip to content

Commit

Permalink
Implement Azure DNS provider (#210) (#214)
Browse files Browse the repository at this point in the history
* vendor Azure Go SDK (#210)

* vendor the Azure Go SDK and dependencies

* add initial Azure DNS provider implementation (#210)

* add 'azure' value to 'provider' command line option
* add 'azure-config-file' command line option
* add 'azure-resource-group' command line option
* implement initial Azure DNS provider

note: azure provider is not yet fully implemented (does not query for existing
records).

tests and documentation are forthcoming.

* add a tutorial for the Azure provider (#210)

* add tutorial for using ExternalDNS with Azure DNS

* finish implementation of Azure DNS provider (#210)

* implement the Records method for the Azure DNS provider

* refactor Azure API interface for future tests (#210)

* make Azure provider use an interface for future unit tests

* add unit tests for the Azure provider (#210)

* test retrieving Azure DNS records.
* test updating and deleting Azure DNS records.
* test dry run for the Azure provider (i.e. noop).
  • Loading branch information
peterhuene authored and linki committed Jun 2, 2017
1 parent f837b65 commit 3355528
Show file tree
Hide file tree
Showing 946 changed files with 302,387 additions and 1,805 deletions.
168 changes: 168 additions & 0 deletions docs/tutorials/azure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Setting up ExternalDNS for Services on Azure

This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster on Azure.

Make sure to use **>=0.4.0-alpha.0** version of ExternalDNS for this tutorial.

This tutorial uses [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) for all
Azure commands and assumes that the Kubernetes cluster was created via Azure Container Services and `kubectl` commands
are being run on an orchestration master.

## Creating a Azure DNS zone

The Azure provider for ExternalDNS will find suitable zones for domains it manages; it will
not automatically create zones.

For this tutorial, we will create a Azure resource group named 'externaldns' that can easily be deleted later:

```
$ az group create -n externaldns -l eastus
```

Substitute a more suitable location for the resource group if desired.

Next, create a Azure DNS zone for "example.com":

```
$ az network dns zone create -g externaldns -n example.com
```

Substitute a domain you own for "example.com" if desired.

If using your own domain that was registered with a third-party domain registrar, you should point your domain's
name servers to the values in the `nameServers` field from the JSON data returned by the `az network dns zone create` command.
Please consult your registrar's documentation on how to do that.

## Creating Azure Credentials Secret

When your Kubernetes cluster is created by Azure Container Services, a file named `/etc/kubernetes/azure.json` is created to store
the Azure credentials for API access. Kubernetes uses this file for the Azure cloud provider.

For ExternalDNS to access the Azure API, it also needs access to this file. However, we will be deploying ExternalDNS inside of
the Kubernetes cluster so we will need to use a Kubernetes secret.

The Azure DNS provider expects, by default, that the configuration file is at `/etc/kubernetes/azure.json`. This can be overridden with
the `--azure-config-file` option when starting ExternalDNS.

To create the secret:

```
$ kubectl create secret generic azure-config-file --from-file=/etc/kubernetes/azure.json
```

## Deploy ExternalDNS

Create a deployment file called `externaldns.yaml` with the following contents:

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:v0.4.0-alpha.0
args:
- --source=service
- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above.
- --provider=azure
- --azure-resource-group=externaldns # (optional) use the DNS zones from the tutorial's resource group
volumeMounts:
- name: azure-config-file
mountPath: /etc/kubernetes
readOnly: true
volumes:
- name: azure-config-file
secret:
secretName: azure-config-file
```
Create the deployment for ExternalDNS:
```
$ kubectl create -f externaldns.yaml
```

## Deploying an Nginx Service

Create a service file called 'nginx.yaml' with the following contents:

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
external-dns.alpha.kubernetes.io/hostname: example.com
spec:
selector:
app: nginx
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
```
Note the annotation on the service; use the same hostname as the Azure DNS zone created above. The annotation may also be a subdomain
of the DNS zone (e.g. 'www.example.com').
ExternalDNS uses this annotation to determine what services should be registered with DNS. Removing the annotation
will cause ExternalDNS to remove the corresponding DNS records.
Create the deployment and service:
```
$ kubectl create -f nginx.yaml
```

It takes a little while for the Azure cloud provider to create an external IP for the service. Check the status by running
`kubectl get services nginx`. If the `EXTERNAL-IP` field shows an address, the service is ready to be accessed externally.

Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and synchronize
the Azure DNS records.

## Verifying Azure DNS records

Run the following command to view the A records for your Azure DNS zone:

```
$ az network dns record-set a list -g externaldns -z example.com
```

Substitute the zone for the one created above if a different domain was used.

This should show the external IP address of the service as the A record for your domain ('@' indicates the record is for the zone itself).

## Delete Azure Resource Group

Now that we have verified that ExternalDNS will automatically manage Azure DNS records, we can delete the tutorial's
resource group:

```
$ az group delete -n externaldns
```
14 changes: 10 additions & 4 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ import:
- package: github.com/kubernetes/repo-infra
- package: github.com/linki/instrumented_http
version: ~0.1.0
- package: github.com/Azure/azure-sdk-for-go
version: ~10.0.4-beta
- package: github.com/Azure/go-autorest
version: ~8.0.0
- package: github.com/dgrijalva/jwt-go
version: ~3.0.0
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ func main() {
p, err = provider.NewAWSProvider(cfg.DomainFilter, cfg.DryRun)
case "inmemory":
p, err = provider.NewInMemoryProviderWithDomainAndLogging("example.com"), nil
case "azure":
p, err = provider.NewAzureProvider(cfg.AzureConfigFile, cfg.DomainFilter, cfg.AzureResourceGroup, cfg.DryRun)
default:
log.Fatalf("unknown dns provider: %s", cfg.Provider)
}
Expand Down
84 changes: 45 additions & 39 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,51 @@ var (

// Config is a project-wide configuration
type Config struct {
Master string
KubeConfig string
Sources []string
Namespace string
FqdnTemplate string
Compatibility string
Provider string
GoogleProject string
DomainFilter string
Policy string
Registry string
TXTOwnerID string
TXTPrefix string
Interval time.Duration
Once bool
DryRun bool
LogFormat string
MetricsAddress string
Debug bool
Master string
KubeConfig string
Sources []string
Namespace string
FqdnTemplate string
Compatibility string
Provider string
GoogleProject string
DomainFilter string
AzureConfigFile string
AzureResourceGroup string
Policy string
Registry string
TXTOwnerID string
TXTPrefix string
Interval time.Duration
Once bool
DryRun bool
LogFormat string
MetricsAddress string
Debug bool
}

var defaultConfig = &Config{
Master: "",
KubeConfig: "",
Sources: nil,
Namespace: "",
FqdnTemplate: "",
Compatibility: "",
Provider: "",
GoogleProject: "",
DomainFilter: "",
Policy: "sync",
Registry: "txt",
TXTOwnerID: "default",
TXTPrefix: "",
Interval: time.Minute,
Once: false,
DryRun: false,
LogFormat: "text",
MetricsAddress: ":7979",
Debug: false,
Master: "",
KubeConfig: "",
Sources: nil,
Namespace: "",
FqdnTemplate: "",
Compatibility: "",
Provider: "",
GoogleProject: "",
DomainFilter: "",
AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "",
Policy: "sync",
Registry: "txt",
TXTOwnerID: "default",
TXTPrefix: "",
Interval: time.Minute,
Once: false,
DryRun: false,
LogFormat: "text",
MetricsAddress: ":7979",
Debug: false,
}

// NewConfig returns new Config object
Expand All @@ -93,9 +97,11 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule")

// Flags related to providers
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, google, inmemory)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google", "inmemory")
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, google, inmemory, azure)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google", "inmemory", "azure")
app.Flag("google-project", "When using the Google provider, specify the Google project (required when --provider=google)").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject)
app.Flag("domain-filter", "Limit possible target zones by a domain suffix (optional)").Default(defaultConfig.DomainFilter).StringVar(&cfg.DomainFilter)
app.Flag("azure-config-file", "When using the Azure provider, specify the Azure configuration file (required when --provider=azure").Default(defaultConfig.AzureConfigFile).StringVar(&cfg.AzureConfigFile)
app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (optional)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup)

// Flags related to policies
app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only")
Expand Down
Loading

0 comments on commit 3355528

Please sign in to comment.