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:
parent
c6e1e6f28f
commit
0d1c5ac305
13
Makefile
13
Makefile
@ -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 \
|
||||
|
@ -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"
|
||||
|
143
docs/website/content/v0.3/en/guides/cloud/digitalocean.md
Normal file
143
docs/website/content/v0.3/en/guides/cloud/digitalocean.md
Normal 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
|
||||
```
|
91
internal/pkg/runtime/platform/digitalocean/digitalocean.go
Normal file
91
internal/pkg/runtime/platform/digitalocean/digitalocean.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
@ -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":
|
||||
|
Loading…
x
Reference in New Issue
Block a user