Skip to content

Commit

Permalink
Merge pull request #4 from supernetes/ddns
Browse files Browse the repository at this point in the history
feat: add support for dynamic DNS
  • Loading branch information
twelho authored Aug 22, 2024
2 parents 9f8c427 + 7786102 commit 25f0b9f
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/work/**
!/work/**/
!/work/cpouta
!/work/ddclient.template.conf
!/work/supernetes-cluster.yaml
!/work/manifests/flux.yaml
!/work/manifests/kustomization.yaml
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Start by logging into cPouta and selecting the right project from the top left.

Then, click on your username from the top right and select `OpenStack RC File`. This will give you a file named `project_1234567-openrc.sh` which will be used by the scripts for API access. Save it into the `work` directory, which is used as the working directory of the container.

Next, since cPouta only hands out ephemeral IPv4 addresses, we need to set up [Dynamic DNS (DDNS)](https://en.wikipedia.org/wiki/Dynamic_DNS) for the cluster. This can be done using external services, such as [dy.fi](https://www.dy.fi/) (Finland-only), or any other service supported by [ddclient](https://ddclient.net/). A configuration template is provided in [`ddclient.template.conf`](work/ddclient.template.conf). Copying this file to `ddclient.conf` and filling it out will set up automatic dynamic DNS reconciliation in the cluster during bringup.

Finally, inside the [container](#usage), run

```shell
Expand Down
92 changes: 82 additions & 10 deletions work/cpouta
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
# - https://www.clouditlab.com/deploying-a-single-node-kubernetes-cluster-in-aws-using-talos/

_p() { (set -x; "$@"); }
alias kubectl="_p kubectl"
alias openstack="_p openstack"
alias talosctl="_p talosctl"
shopt -s expand_aliases
set -o pipefail

Expand Down Expand Up @@ -56,6 +58,19 @@ set -o pipefail
_usage 1
fi

# Extract DDNS FQDN if configuration is present
if [ -f ddclient.conf ]; then
_fqdn=$(tail -1 ddclient.conf)
if [ -z "$_fqdn" ] || [[ "$_fqdn" == *=* ]]; then
cat <<- EOF
Error: invalid DDNS FQDN: ${_fqdn:-(none)}
The last line in ddclient.conf must be the FQDN
EOF

exit 1
fi
fi

_delete() {
openstack "${@:3}" list -f json | jq --arg key "$1" --arg value "$2" -rc 'map(select(.[$key] == $value)) | .[].ID' | while read -r id; do openstack "${@:3}" delete "$id"; done
}
Expand Down Expand Up @@ -103,13 +118,18 @@ set -o pipefail
_public_ip=$(openstack floating ip list --port "$_machine" -f json | jq -r '.[0] | ."Floating IP Address"')

# Create baseline Talos configuration, override this with talos-bootstrap
talosctl gen config -f cpouta "https://$_private_ip:6443" --with-secrets secrets.yaml --config-patch @<(cat <<- EOF
machine:
type: init # Bootstrap automatically
cluster:
allowSchedulingOnControlPlanes: true # Single-node cluster
EOF
)
talosctl gen config -f cpouta "https://$_private_ip:6443" \
--with-secrets secrets.yaml \
--config-patch @<(cat <<- EOF
machine:
type: init # Bootstrap automatically
cluster:
allowSchedulingOnControlPlanes: true # Single-node cluster
EOF
) \
${_fqdn+--additional-sans "$_fqdn"}

# Update generated talosconfig
talosctl --talosconfig talosconfig config endpoint "$_public_ip"
talosctl --talosconfig talosconfig config node "$_private_ip"
talosctl config merge talosconfig
Expand All @@ -122,9 +142,61 @@ set -o pipefail
talosctl kubeconfig -fm
sed -i "s/$_private_ip/$_public_ip/g" ~/.kube/config

# Print IPs for convenient access
echo "Private IP: $_private_ip"
echo "Public IP: $_public_ip"
if [ -n "$_fqdn" ]; then
# Deploy linuxserver/ddclient to perform periodic Dynamic DNS (DDNS) updates
kubectl create namespace ddns
kubectl -n ddns create secret generic ddns-config \
--from-file=ddclient.conf=ddclient.conf
kubectl apply -f <(cat <<- EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: ddns
namespace: ddns
spec:
selector:
matchLabels:
app: ddns
template:
metadata:
labels:
app: ddns
spec:
containers:
- name: ddclient
image: linuxserver/ddclient:3.11.2
securityContext:
privileged: false
volumeMounts:
- mountPath: /defaults
name: ddns-config
volumes:
- name: ddns-config
secret:
secretName: ddns-config
EOF
)

# Use the FQDN instead of the public IP
talosctl --talosconfig talosconfig config endpoint "$_fqdn"
talosctl config merge talosconfig

# Wait for the cluster to become healthy
while ! talosctl health; do sleep 1; done
talosctl kubeconfig -fm
sed -i "s/$_private_ip/$_fqdn/g" ~/.kube/config
fi

# Print IPs for convenient access
printf "%-12s%s\n" "Private IP:" "$_private_ip" "Public IP:" "$_public_ip"

# Print FQDN if configured
if [ -n "$_fqdn" ]; then
printf "%-12s%s\n" "FQDN:" "$_fqdn"
fi

# Confirm readiness
echo "Cluster ready."

exit
}
13 changes: 13 additions & 0 deletions work/ddclient.template.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example ddclient configuration for dynamic DNS updates to dy.fi (Finnish-only DDNS service),
# Change the file name to "ddclient.conf" to enable. Edit the <email>, <password> and <host>
# entries to match your setup, or change the configuration entirely to target your preferred
# DDNS service. The last line MUST match the DDNS FQDN.

daemon=60
use=web
web=checkip.dy.fi
server=www.dy.fi
protocol=dyndns2
login=<email>
password=<password>
<host>.dy.fi

0 comments on commit 25f0b9f

Please sign in to comment.