Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add talos support #1192

Merged
merged 18 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@
"matchStrings": [
// Example:
// k3s_release_version: "v1.27.3+k3s1"
"datasource=(?<datasource>\\S+) depName=(?<depName>\\S+)( versioning=(?<versioning>\\S+))?\n.*?\"(?<currentValue>.*)\"\n",
"datasource=(?<datasource>\\S+) depName=(?<depName>\\S+)( versioning=(?<versioning>\\S+))?( extractVersion=(?<extractVersion>\\S+))?\n.*?\"(?<currentValue>.*)\"\n",
// Example:
// - https://github.com/rancher/system-upgrade-controller/releases/download/v0.11.0/crd.yaml
"datasource=(?<datasource>\\S+) depName=(?<depName>\\S+)( versioning=(?<versioning>\\S+))?\n.*?-\\s(.*?)\/(?<currentValue>[^/]+)\/[^/]+\n",
Expand Down
55 changes: 55 additions & 0 deletions .github/tests/config-talos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
ci_test: true

bootstrap_distribution: talos
bootstrap_github_username: onedr0p
bootstrap_github_repository_name: flux-cluster-template
bootstrap_github_repository_branch: main
bootstrap_age_public_key: $BOOTSTRAP_AGE_PUBLIC_KEY
bootstrap_timezone: Etc/UTC
bootstrap_acme_email: fake
bootstrap_acme_production_enabled: false
bootstrap_flux_github_webhook_token: fake
bootstrap_cloudflare_domain: fake
bootstrap_cloudflare_token: fake
bootstrap_cloudflare_account_tag: fake
bootstrap_cloudflare_tunnel_secret: fake
bootstrap_cloudflare_tunnel_id: fake
bootstrap_node_cidr: 10.10.10.0/24
bootstrap_kube_api_addr: 10.10.10.254
bootstrap_kube_api_hostname: fake
bootstrap_k8s_gateway_addr: 10.10.10.253
bootstrap_external_ingress_addr: 10.10.10.252
bootstrap_internal_ingress_addr: 10.10.10.251
bootstrap_cilium_loadbalancer_mode: dsr
bootstrap_ipv6_enabled: false
bootstrap_cluster_cidr: 10.42.0.0/16
bootstrap_service_cidr: 10.43.0.0/16
bootstrap_local_storage_path: /var/openebs/local
bootstrap_nodes:
master:
- name: k8s-0
address: 10.10.10.100
username: fake
diskSerial: fake
- name: k8s-1
address: 10.10.10.101
username: fake
diskSerial: fake
- name: k8s-2
address: 10.10.10.102
username: fake
diskSerial: fake
worker:
- name: k8s-3
address: 10.10.10.103
username: fake
diskSerial: fake
- name: k8s-4
address: 10.10.10.104
username: fake
diskSerial: fake
- name: k8s-5
address: 10.10.10.105
username: fake
diskSerial: fake
8 changes: 8 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
- k3s-ipv4
- k3s-ipv6
- k3s-no-kube-vip
- talos
addon-files: ["addons"]
steps:
- name: Checkout
Expand Down Expand Up @@ -112,6 +113,13 @@ jobs:
shell: bash
run: task configure --yes

- name: Run Talos configure
if: ${{ steps.config-env.outputs.distribution == 'talos' }}
shell: bash
run: |
task talos:gensecret --yes
task talos:genconfig

- name: Run Ansible lint
if: ${{ steps.config-env.outputs.distribution == 'k3s' || steps.config-env.outputs.distribution == 'k0s' }}
shell: bash
Expand Down
1 change: 1 addition & 0 deletions .taskfiles/K0s/Taskfile.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
# yaml-language-server: $schema=https://taskfile.dev/schema.json
version: "3"

env:
Expand Down
72 changes: 72 additions & 0 deletions .taskfiles/Talos/Taskfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
# yaml-language-server: $schema=https://taskfile.dev/schema.json
version: "3"

vars:
TALOS_DIR: "{{.ROOT_DIR}}/kubernetes/talos"
TALHELPER_SECRET_FILE: "{{.TALOS_DIR}}/talhelper.sops.yaml"
TALHELPER_CONFIG_FILE: "{{.TALOS_DIR}}/talconfig.yaml"

tasks:

gensecret:
desc: Generate talos secret
prompt: This will overwrite the existing secret... continue?
dir: "{{.TALOS_DIR}}"
cmds:
- talhelper gensecret > {{.TALHELPER_SECRET_FILE}}
- task: :sops:.encrypt-file
vars:
file: "{{.TALHELPER_SECRET_FILE}}"
preconditions:
- { msg: "Missing talhelper config file", sh: "test -f {{.TALHELPER_CONFIG_FILE}}" }

genconfig:
desc: Generate talos config
dir: "{{.TALOS_DIR}}"
cmd: talhelper genconfig
preconditions:
- { msg: "Missing talhelper config file", sh: "test -f {{.TALHELPER_CONFIG_FILE}}" }

apply-config:
desc: Apply talos config on a node
dir: "{{.TALOS_DIR}}"
cmd: talhelper gencommand apply --extra-flags=--insecure | bash

bootstrap:
desc: Bootstrap the talos cluster
dir: "{{.TALOS_DIR}}"
cmd: talhelper gencommand bootstrap | bash

kubeconfig:
desc: Generate talos kubeconfig
prompt: This will overwrite the existing kubeconfig... continue?
dir: "{{.TALOS_DIR}}"
cmd: talosctl kubeconfig {{.ROOT_DIR}} --force

apply-extras:
desc: Apply extras
dir: "{{.TALOS_DIR}}"
cmds:
- kubectl --kubeconfig {{.KUBECONFIG_FILE}} kustomize --enable-helm ./cni | kubectl apply --kubeconfig {{.KUBECONFIG_FILE}} --server-side --filename -
- kubectl --kubeconfig {{.KUBECONFIG_FILE}} kustomize --enable-helm ./kubelet-csr-approver | kubectl apply --kubeconfig {{.KUBECONFIG_FILE}} --server-side --filename -
preconditions:
- { msg: "Missing kubeconfig", sh: "test -f {{.KUBECONFIG_FILE}}" }

upgrade-talos:
desc: Upgrade talos on a node
cmd: talosctl --nodes {{.node}} upgrade --image {{.image}} --preserve=true --reboot-mode=powercycle
vars:
image: '{{ or .image (fail "Argument (image) is required") }}'
node: '{{ or .node (fail "Argument (node) is required") }}'
preconditions:
- { msg: "Node not found", sh: "talosctl --nodes {{.node}} get machineconfig" }

upgrade-k8s:
desc: Upgrade k8s on a node
cmd: talosctl --nodes {{.node}} upgrade-k8s --to {{.to}}
vars:
node: '{{ or .node (fail "Argument (node) is required") }}'
to: '{{ or .to (fail "Argument (to) is required") }}'
preconditions:
- { msg: "Node not found", sh: "talosctl --nodes {{.node}} get machineconfig" }
1 change: 1 addition & 0 deletions .taskfiles/Workstation/Archfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ moreutils
sops
stern-bin
talhelper-bin
talosctl
2 changes: 2 additions & 0 deletions .taskfiles/Workstation/Brewfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
tap "fluxcd/tap"
tap "go-task/tap"
tap "k0sproject/tap"
tap "siderolabs/talos"
brew "age"
brew "cloudflared"
brew "direnv"
Expand All @@ -16,4 +17,5 @@ brew "moreutils"
brew "sops"
brew "stern"
brew "talhelper"
brew "talosctl"
brew "yq"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Deploy a Kubernetes cluster backed by Flux

Welcome to my highly opinionated template for deploying a single Kubernetes ([k3s](https://k3s.io) or [k0s](https://github.com/k0sproject/k0s)) cluster with [Ansible](https://www.ansible.com) and using [Flux](https://toolkit.fluxcd.io) to manage its state.
Welcome to my opinionated and extendable template for deploying a single Kubernetes cluster with [k0s](https://github.com/k0sproject/k0s), [k3s](https://k3s.io) or [Talos](https://github.com/siderolabs/talos) backed by [Flux](https://fluxcd.io/flux/) to manage its state.

## 👋 Introduction

Expand Down
1 change: 1 addition & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ includes:
repository:
aliases: ["repo"]
taskfile: .taskfiles/Repository/Taskfile.yaml
talos: .taskfiles/Talos/Taskfile.yaml
sops: .taskfiles/Sops/Taskfile.yaml
workstation: .taskfiles/Workstation/Taskfile.yaml

Expand Down
15 changes: 11 additions & 4 deletions bootstrap/tasks/validation/cli.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
- name: Check if required CLI tools are present
ansible.builtin.shell: |
command -v {{ item }} >/dev/null 2>&1
ansible.builtin.shell: command -v {{ item }} >/dev/null 2>&1
loop: ["age", "cloudflared", "flux", "sops", "jq", "kubeconform", "kustomize"]
changed_when: false
check_mode: false
Expand All @@ -10,10 +9,18 @@

- name: Check if required CLI tools are present for k0s
when: bootstrap_distribution == "k0s"
ansible.builtin.shell: |
command -v {{ item }} >/dev/null 2>&1
ansible.builtin.shell: command -v {{ item }} >/dev/null 2>&1
loop: ["k0sctl"]
changed_when: false
check_mode: false
register: result
failed_when: result.rc != 0 and result.rc != 127

- name: Check if required CLI tools are present for talos
when: bootstrap_distribution == "talos"
ansible.builtin.shell: command -v {{ item }} >/dev/null 2>&1
loop: ["talhelper", "talosctl"]
changed_when: false
check_mode: false
register: result
failed_when: result.rc != 0 and result.rc != 127
28 changes: 15 additions & 13 deletions bootstrap/tasks/validation/net.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
---
- name: Set reachable address
ansible.builtin.set_fact:
current_address: "{{ item.external_address | default(item.address) }}"
loop: "{{ bootstrap_nodes.master + bootstrap_nodes.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"

- name: Check if master node count is odd
ansible.builtin.assert:
that:
Expand Down Expand Up @@ -161,7 +154,6 @@
fail_msg: Node address {{ item.address }} is not within {{ bootstrap_node_cidr }}.
quiet: true
loop: "{{ bootstrap_nodes.master + bootstrap_nodes.worker | default([]) }}"
when: item.external_address is not defined
loop_control:
label: "{{ item.address }}"

Expand Down Expand Up @@ -193,14 +185,24 @@
fail_msg: All node names are not unique.
quiet: true

- name: Check if nodes SSH ports are reachable
when: not ci_test | default(false)
- name: Check if SSH ports are reachable
when: (not ci_test | default(false)) and (not bootstrap_distribution == "talos")
ansible.builtin.wait_for:
host: "{{ current_address }}"
host: "{{ item.address }}"
port: 22
search_regex: OpenSSH
timeout: 10
connection: local
loop: "{{ bootstrap_nodes.master + bootstrap_nodes.worker | default([]) }}"
loop_control:
label: "{{ current_address }}"
label: "{{ item.address }}"

- name: Check if Talos ports are reachable
when: (not ci_test | default(false)) and (bootstrap_distribution == "talos")
ansible.builtin.wait_for:
host: "{{ item.address }}"
port: 50000
timeout: 10
connection: local
loop: "{{ bootstrap_nodes.master + bootstrap_nodes.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"
2 changes: 1 addition & 1 deletion bootstrap/tasks/validation/vars.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

- name: Check if bootstrap distribution is valid
ansible.builtin.assert:
that: bootstrap_distribution in ['k0s', 'k3s']
that: bootstrap_distribution in ['k0s', 'k3s', 'talos']
success_msg: Distribution {{ bootstrap_distribution }} is valid
fail_msg: Distribution {{ bootstrap_distribution }} is not valid

Expand Down
5 changes: 5 additions & 0 deletions bootstrap/templates/.sops.yaml.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
creation_rules:
- # IMPORTANT: This rule MUST be above the others
path_regex: talos/.*\.sops\.ya?ml
key_groups:
- age:
- "#{ bootstrap_age_public_key }#"
- path_regex: kubernetes/.*\.sops\.ya?ml
encrypted_regex: "^(data|stringData)$"
key_groups:
Expand Down
8 changes: 0 additions & 8 deletions bootstrap/templates/ansible/inventory/hosts.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,15 @@ kubernetes:
#% for item in bootstrap_nodes.master %#
"#{ item.name }#":
ansible_user: "#{ item.username }#"
#% if item.external_address is defined %#
ansible_host: "#{ item.external_address }#"
#% else %#
ansible_host: "#{ item.address }#"
#% endif %#
#% endfor %#
#% if bootstrap_nodes.worker | default([]) | length > 0 %#
worker:
hosts:
#% for item in bootstrap_nodes.worker %#
"#{ item.name }#":
ansible_user: "#{ item.username }#"
#% if item.external_address is defined %#
ansible_host: "#{ item.external_address }#"
#% else %#
ansible_host: "#{ item.address }#"
#% endif %#
#% endfor %#
#% endif %#
#% endif %#
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#% if bootstrap_distribution == "talos" %#
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: kubelet-csr-approver
spec:
interval: 30m
chart:
spec:
chart: kubelet-csr-approver
version: 1.0.6
sourceRef:
kind: HelmRepository
name: postfinance
namespace: flux-system
install:
remediation:
retries: 3
upgrade:
cleanupOnFail: true
remediation:
retries: 3
uninstall:
keepHistory: false
values:
providerRegex: |
^k(m|w)\d\d?$
#% endif %#
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#% if bootstrap_distribution == "talos" %#
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./helmrelease.yaml
#% endif %#
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#% if bootstrap_distribution == "talos" %#
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: &app kubelet-csr-approver
namespace: flux-system
spec:
targetNamespace: kube-system
commonMetadata:
labels:
app.kubernetes.io/name: *app
path: ./kubernetes/apps/kube-system/kubelet-csr-approver/app
prune: false # never should be deleted
sourceRef:
kind: GitRepository
name: home-kubernetes
wait: false
interval: 30m
retryInterval: 1m
timeout: 5m
#% endif %#
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ resources:
#% if bootstrap_distribution == "k3s" %#
- ./coredns/ks.yaml
#% endif %#
#% if bootstrap_distribution == "talos" %#
- ./kubelet-csr-approver/ks.yaml
#% endif %#
- ./metrics-server/ks.yaml
#% if bootstrap_distribution == "k0s" and spegel.enabled | default(false) %#
#% if (bootstrap_distribution == "k0s" or bootstrap_distribution == "talos") and spegel.enabled | default(false) %#
- ./spegel/ks.yaml
#% endif %#