feat: add support for Digital Ocean

This adds a Digital Ocean platform implementation.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
Andrew Rynhard 2019-10-28 15:43:59 +00:00
parent c6e1e6f28f
commit 0d1c5ac305
6 changed files with 268 additions and 0 deletions

View File

@ -190,6 +190,19 @@ image-azure:
@tar -C $(PWD)/build -czf $(PWD)/build/azure.tar.gz azure.vhd
@rm -rf $(PWD)/build/azure.raw $(PWD)/build/azure.vhd
.PHONY: image-digital-ocean
image-digital-ocean:
@docker run --rm -v /dev:/dev -v $(PWD)/build:/out \
--privileged $(DOCKER_ARGS) \
autonomy/installer:$(TAG) \
install \
-n digital-ocean \
-r \
-p digital-ocean \
-u none \
-e console=ttyS0
@gzip $(PWD)/build/digital-ocean.raw
.PHONY: image-gcp
image-gcp:
@docker run --rm -v /dev:/dev -v $(PWD)/build:/out \

View File

@ -19,6 +19,10 @@
"title": "Azure",
"path": "v0.3/en/guides/cloud/azure"
},
{
"title": "Digital Ocean",
"path": "v0.3/en/guides/cloud/digitalocean"
},
{
"title": "GCP",
"path": "v0.3/en/guides/cloud/gcp"

View File

@ -0,0 +1,143 @@
---
title: 'Digital Ocean'
---
## Creating a Cluster via the CLI
In this guide we will create an HA Kubernetes cluster with 1 worker node.
We assume an existing [Space](https://www.digitalocean.com/docs/spaces/), and some familiarity with Digital Ocean.
If you need more information on Digital Ocean specifics, please see the [official Digital Ocean documentation](https://www.digitalocean.com/docs/).
### Create the Image
First, download the Digital Ocean image from a Talos release.
Using an upload method of your choice (`doctl` does not have Spaces support), upload the image to a space.
Now, create an image using the URL of the uploaded image:
```bash
doctl compute image create \
--region $REGION \
--image-name talos-digital-ocean-tutorial \
--image-url https://talos-tutorial.$REGION.digitaloceanspaces.com/digital-ocean.raw.gz \
Talos
```
### Create a Load Balancer
```bash
doctl compute load-balancer create \
--region $REGION \
--name talos-digital-ocean-tutorial-lb \
--tag-name talos-digital-ocean-tutorial-control-plane \
--health-check protocol:tcp,port:443,check_interval_seconds:10,response_timeout_seconds:5,healthy_threshold:5,unhealthy_threshold:3
--forwarding-rules entry_protocol:tcp,entry_port:443,target_protocol:tcp,target_port:6443
```
We will need the IP of the load balancer.
To retrieve it, run:
```bash
doctl compute load-balancer get --format IP
```
Save it, as we will need it in the next step.
### Create the Machine Configuration Files
#### Generating Base Configurations
Using the DNS name of the loadbalancer created earlier, generate the base configuration files for the Talos machines:
```bash
$ osctl config generate talos-k8s-digital-ocean-tutorial https://$LB_IP
created init.yaml
created controlplane.yaml
created join.yaml
created talosconfig
```
At this point, you can modify the generated configs to your liking.
#### Validate the Configuration Files
```bash
$ osctl validate --config init.yaml --mode cloud
init.yaml is valid for cloud mode
$ osctl validate --config controlplane.yaml --mode cloud
controlplane.yaml is valid for cloud mode
$ osctl validate --config join.yaml --mode cloud
join.yaml is valid for cloud mode
```
### Create the Droplets
#### Create the Bootstrap Node
```bash
doctl compute droplet create \
--region $REGION \
--image 54190082 \
--size s-2vcpu-4gb \
--enable-private-networking \
--tag-names talos-digital-ocean-tutorial-control-plane \
--user-data-file init.yaml \
--ssh-keys '<ssh key fingerprint>' \
talos-control-plane-1
```
#### Create the Remaining Control Plane Nodes
Run the following twice, to give ourselves three total control plane nodes:
```bash
doctl compute droplet create \
--region $REGION \
--image 54190082 \
--size s-2vcpu-4gb \
--enable-private-networking \
--tag-names talos-digital-ocean-tutorial-control-plane \
--user-data-file controlplane.yaml \
--ssh-keys '<ssh key fingerprint>' \
talos-control-plane-2
doctl compute droplet create \
--region $REGION \
--image 54190082 \
--size s-2vcpu-4gb \
--enable-private-networking \
--tag-names talos-digital-ocean-tutorial-control-plane \
--user-data-file controlplane.yaml \
--ssh-keys '<ssh key fingerprint>' \
talos-control-plane-3
```
#### Create the Worker Nodes
Run the following to create a worker node:
```bash
doctl compute droplet create \
--region $REGION \
--image 54190082 \
--size s-2vcpu-4gb \
--enable-private-networking \
--tag-names talos-digital-ocean-tutorial-control-plane \
--user-data-file join.yaml \
--ssh-keys '<ssh key fingerprint>' \
talos-worker-1
```
### Retrieve the `kubeconfig`
To configure `osctl` we will need the first controla plane node's IP:
```bash
doctl compute droplet get --format PublicIPv4 <droplet ID>
```
At this point we can retrieve the admin `kubeconfig` by running:
```bash
osctl --talosconfig talosconfig config target <control plane 1 IP>
osctl --talosconfig talosconfig kubeconfig > kubeconfig
```

View File

@ -0,0 +1,91 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package digitalocean
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"github.com/talos-systems/talos/internal/pkg/runtime"
"github.com/talos-systems/talos/pkg/download"
)
const (
// DigitalOceanExternalIPEndpoint displays all external addresses associated with the instance
DigitalOceanExternalIPEndpoint = "http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address"
// DigitalOceanHostnameEndpoint is the local endpoint for the hostname.
DigitalOceanHostnameEndpoint = "http://169.254.169.254/metadata/v1/hostname"
// DigitalOceanUserDataEndpoint is the local endpoint for the config.
DigitalOceanUserDataEndpoint = "http://169.254.169.254/metadata/v1/user-data"
)
// DigitalOcean is the concrete type that implements the platform.Platform interface.
type DigitalOcean struct{}
// Name implements the platform.Platform interface.
func (a *DigitalOcean) Name() string {
return "Digital Ocean"
}
// Configuration implements the platform.Platform interface.
func (a *DigitalOcean) Configuration() ([]byte, error) {
return download.Download(DigitalOceanUserDataEndpoint)
}
// Mode implements the platform.Platform interface.
func (a *DigitalOcean) Mode() runtime.Mode {
return runtime.Cloud
}
// Hostname gets the hostname from the DigitalOcean metadata endpoint.
func (a *DigitalOcean) Hostname() (hostname []byte, err error) {
resp, err := http.Get(DigitalOceanHostnameEndpoint)
if err != nil {
return
}
// nolint: errcheck
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return hostname, fmt.Errorf("failed to fetch hostname from metadata service: %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
// ExternalIPs provides any external addresses assigned to the instance
func (a *DigitalOcean) ExternalIPs() (addrs []net.IP, err error) {
var (
body []byte
req *http.Request
resp *http.Response
)
if req, err = http.NewRequest("GET", DigitalOceanExternalIPEndpoint, nil); err != nil {
return
}
client := &http.Client{}
if resp, err = client.Do(req); err != nil {
return
}
// nolint: errcheck
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return addrs, fmt.Errorf("failed to retrieve external addresses for instance")
}
if body, err = ioutil.ReadAll(resp.Body); err != nil {
return
}
addrs = append(addrs, net.ParseIP(string(body)))
return addrs, err
}

View File

@ -0,0 +1,14 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package digitalocean_test
import "testing"
func TestEmpty(t *testing.T) {
// added for accurate coverage estimation
//
// please remove it once any unit-test is added
// for this package
}

View File

@ -14,6 +14,7 @@ import (
"github.com/talos-systems/talos/internal/pkg/runtime/platform/aws"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/azure"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/container"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/digitalocean"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/gcp"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/iso"
"github.com/talos-systems/talos/internal/pkg/runtime/platform/metal"
@ -44,6 +45,8 @@ func NewPlatform() (p runtime.Platform, err error) {
p = &aws.AWS{}
case "azure":
p = &azure.Azure{}
case "digital-ocean":
p = &digitalocean.DigitalOcean{}
case "metal":
p = &metal.Metal{}
case "container":