feat!: Rewrite configure script in ansible (#822)

* feat: smol changes

Signed-off-by: Devin Buhl <devin@buhl.casa>

* feat!: Rewrite configure script in ansible

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: add comment for real path

Signed-off-by: Devin Buhl <devin@buhl.casa>

* feat: verification is done

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: do not need net common

Signed-off-by: Devin Buhl <devin@buhl.casa>

* chore: clean up old comments

Signed-off-by: Devin Buhl <devin@buhl.casa>

* chore: clean up old comments

Signed-off-by: Devin Buhl <devin@buhl.casa>

* feat: finish up ansible host generation and more

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: backup/restore sops config between tasks

Signed-off-by: Devin Buhl <devin@buhl.casa>

* chore: clean up test comments

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: use ansible template on template

Signed-off-by: Devin Buhl <devin@buhl.casa>

* Update template/vars/config.sample.yaml

Co-authored-by: Manuel Rüger <manuel@rueg.eu>

* Update template/tasks/verify_cli.yaml

* chore: update readme

Signed-off-by: Devin Buhl <devin@buhl.casa>

* chore: update readme

Signed-off-by: Devin Buhl <devin@buhl.casa>

* Update README.md

Co-authored-by: Manuel Rüger <manuel@rueg.eu>

* fix: move bcrypt logic to template

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: derp

Signed-off-by: Devin Buhl <devin@buhl.casa>

---------

Signed-off-by: Devin Buhl <devin@buhl.casa>
Co-authored-by: Manuel Rüger <manuel@rueg.eu>
This commit is contained in:
Devin BuhlandManuel Rüger authored and GitHub committed 2023-07-04 11:36:58 -04:00
1 parent 26164c7278
commit de0ed1c70a
58 files changed
+698 -764

No files matched your search

-99
View File
@@ -1,99 +0,0 @@
#
# Cluster related variables
#
# The repo you created from this template
# e.g. https://github.com/onedr0p/home-cluster
export BOOTSTRAP_GIT_REPOSITORY=""
# To enable Flux to update your cluster on `git push` set the following to one of:
# `generated` - this will generate a token and print it in the logs
# Set this to any other string and it will be used for the secret
export BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET="generated" # NOTE: Must only contain alphanumeric characters and dashes
# The Weave GitOps dashboard admin password
# `generated` - this will generate a token and print it in the logs
# Set this to any other string and it will be used for the secret
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="generated" # NOTE: Must only contain alphanumeric characters and dashes
# The Grafana admin password
# `generated` - this will generate a token and print it in the logs
# Set this to any other string and it will be used for the secret
export BOOTSTRAP_GRAFANA_ADMIN_PASSWORD="generated" # NOTE: Must only contain alphanumeric characters and dashes
# Age Public Key - string should start with age
# e.g. age15uzrw396e67z9wdzsxzdk7ka0g2gr3l460e0slaea563zll3hdfqwqxdta
export BOOTSTRAP_AGE_PUBLIC_KEY=""
# Choose your timezone
# e.g. America/New_York
export BOOTSTRAP_TIMEZONE="Etc/UTC"
# The email you want to be associated with the ACME account
export BOOTSTRAP_ACME_EMAIL=""
# Choose one of your cloudflare domains
# e.g. onedr0p.com
export BOOTSTRAP_CLOUDFLARE_DOMAIN=""
# Your global Cloudflare API Token (not API Key)
export BOOTSTRAP_CLOUDFLARE_APITOKEN=""
# Create a cloudflare tunnel to automatically ingress into your cluster
# https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/local/
# cloudflared tunnel create <NAME or UUID>
export BOOTSTRAP_CLOUDFLARE_ACCOUNT_TAG=""
export BOOTSTRAP_CLOUDFLARE_TUNNEL_SECRET=""
export BOOTSTRAP_CLOUDFLARE_TUNNEL_ID=""
# The load balancer IP for k8s_gateway, choose a available IP in your nodes network that is not being used
export BOOTSTRAP_K8S_GATEWAY_ADDR=""
# The load balancer IP for ingress-nginx, choose a available IP in your nodes network that is not being used
export BOOTSTRAP_INGRESS_NGINX_ADDR=""
# The IP address to use with kube-vip, choose a available IP in your nodes network that is not being used
export BOOTSTRAP_KUBE_VIP_ADDR=""
# Choose your cluster or service cidrs
# Leave this unchanged unless you know what you are doing
export BOOTSTRAP_CLUSTER_CIDR="10.42.0.0/16"
export BOOTSTRAP_SERVICE_CIDR="10.43.0.0/16"
#
# Ansible related variables
#
#
# Default prefixes for hostnames assigned by Ansible
# These are unused on nodes where BOOTSTRAP_ANSIBLE_HOSTNAME_ is provided
#
export BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX="k8s-" # NOTE: Must only contain alphanumeric characters and dashes
export BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX="k8s-" # NOTE: Must only contain alphanumeric characters and dashes
#
# Ansible hosts - repeat this block as many times as you need,
# incrementing the last digit on the variable name for each node
#
# IP Address to the node
# That doesn't conflict with any other IP addresses here
# e.g. 192.168.1.200
export BOOTSTRAP_ANSIBLE_HOST_ADDR_0=""
# User Ansible will log into the nodes
export BOOTSTRAP_ANSIBLE_SSH_USERNAME_0="" # NOTE: Must only contain alphanumeric characters and dashes
# Password Ansible will use to escalate to sudo
export BOOTSTRAP_ANSIBLE_SUDO_PASSWORD_0="" # NOTE: Must only contain alphanumeric characters and dashes
# Set this node as a control node (true/false)
export BOOTSTRAP_ANSIBLE_CONTROL_NODE_0=""
# Optional: Set the hostname of the node, if set this will override the *_HOSTNAME_PREFIX vars above
export BOOTSTRAP_ANSIBLE_HOSTNAME_0=""
# export BOOTSTRAP_ANSIBLE_HOST_ADDR_1=""
# export BOOTSTRAP_ANSIBLE_SSH_USERNAME_1="" # NOTE: Must only contain alphanumeric characters and dashes
# export BOOTSTRAP_ANSIBLE_SUDO_PASSWORD_1="" # NOTE: Must only contain alphanumeric characters and dashes
# export BOOTSTRAP_ANSIBLE_CONTROL_NODE_1=""
# export BOOTSTRAP_ANSIBLE_HOSTNAME_1=""
# export BOOTSTRAP_ANSIBLE_HOST_ADDR_2=""
# export BOOTSTRAP_ANSIBLE_SSH_USERNAME_2="" # NOTE: Must only contain alphanumeric characters and dashes
# export BOOTSTRAP_ANSIBLE_SUDO_PASSWORD_2="" # NOTE: Must only contain alphanumeric characters and dashes
# export BOOTSTRAP_ANSIBLE_CONTROL_NODE_2=""
# export BOOTSTRAP_ANSIBLE_HOSTNAME_2=""
-2
View File
@@ -1,6 +1,4 @@
#shellcheck disable=SC2148,SC2155
export KUBECONFIG=$(expand_path ./kubeconfig)
export ANSIBLE_CONFIG=$(expand_path ./ansible.cfg)
export ANSIBLE_HOST_KEY_CHECKING="False"
export K8S_AUTH_KUBECONFIG=$(expand_path ./kubeconfig)
export SOPS_AGE_KEY_FILE=$(expand_path ~/.config/sops/age/keys.txt)
-1
View File
@@ -1,5 +1,4 @@
* text=auto eol=lf
*.yml.j2 linguist-language=YAML
*.yaml.j2 linguist-language=YAML
*.sops.* diff=sopsdiffer
*.sops.toml linguist-language=JSON
+91
View File
@@ -0,0 +1,91 @@
---
version: "3"
env:
K8S_AUTH_KUBECONFIG: "{{.ROOT_DIR}}/kubeconfig"
vars:
ANSIBLE_PLAYBOOK_DIR: "{{.ANSIBLE_DIR}}/playbooks"
ANSIBLE_INVENTORY_DIR: "{{.ANSIBLE_DIR}}/inventory"
tasks:
init:
desc: Install / Upgrade Ansible galaxy deps
dir: "{{.ANSIBLE_DIR}}"
cmds:
- pip3 install --user --requirement requirements.txt
- ansible-galaxy install -r requirements.yaml --roles-path ~/.ansible/roles --force
- ansible-galaxy collection install -r requirements.yaml --collections-path ~/.ansible/collections --force
list:
desc: List all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml --list-hosts
prepare:
desc: Prepare all the k8s nodes for running k3s
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-prepare.yaml
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
install:
desc: Install Kubernetes on the nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-installation.yaml
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
upgrade:
desc: Upgrade Kubernetes on the nodes (currently this only upgrades kube-vip)
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-upgrade.yaml
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
nuke:
desc: Uninstall Kubernetes on the nodes
dir: "{{.ANSIBLE_DIR}}"
interactive: true
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-nuke.yaml
- task: force-reboot
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
ping:
desc: Ping all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml --one-line -m 'ping'
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
uptime:
desc: Uptime of all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml --one-line -a 'uptime'
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
force-reboot:
desc: Reboot all the k8s nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-reboot.yaml
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
force-poweroff:
desc: Shutdown all the k8s nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible kubernetes -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yaml -a '/usr/bin/systemctl poweroff' --become
env:
ANSIBLE_CONFIG: "{{.ANSIBLE_DIR}}/ansible.cfg"
-76
View File
@@ -1,76 +0,0 @@
---
version: "3"
env:
ANSIBLE_CONFIG: "{{.ROOT_DIR}}/ansible.cfg"
K8S_AUTH_KUBECONFIG: "{{.ROOT_DIR}}/kubeconfig"
vars:
ANSIBLE_PLAYBOOK_DIR: "{{.ANSIBLE_DIR}}/playbooks"
ANSIBLE_INVENTORY_DIR: "{{.ANSIBLE_DIR}}/inventory"
tasks:
init:
desc: Install / Upgrade Ansible galaxy deps
dir: "{{.ANSIBLE_DIR}}"
cmds:
- pip3 install --user --requirement requirements.txt
- ansible-galaxy install -r requirements.yml --roles-path ~/.ansible/roles --force
- ansible-galaxy collection install -r requirements.yml --collections-path ~/.ansible/collections --force
list:
desc: List all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml --list-hosts
prepare:
desc: Prepare all the k8s nodes for running k3s
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-prepare.yml
install:
desc: Install Kubernetes on the nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-installation.yml
upgrade:
desc: Upgrade Kubernetes on the nodes (currently this only upgrades kube-vip)
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-upgrade.yml
nuke:
desc: Uninstall Kubernetes on the nodes
dir: "{{.ANSIBLE_DIR}}"
interactive: true
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-nuke.yml
- task: force-reboot
ping:
desc: Ping all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml --one-line -m 'ping'
uptime:
desc: Uptime of all the hosts
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible all -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml --one-line -a 'uptime'
force-reboot:
desc: Reboot all the k8s nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible-playbook -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml {{.ANSIBLE_PLAYBOOK_DIR}}/cluster-reboot.yml
force-poweroff:
desc: Shutdown all the k8s nodes
dir: "{{.ANSIBLE_DIR}}"
cmds:
- ansible kubernetes -i {{.ANSIBLE_INVENTORY_DIR}}/hosts.yml -a '/usr/bin/systemctl poweroff' --become
File renamed without changes.
+4 -4
View File
@@ -1,13 +1,13 @@
{
"files.associations": {
"*.json5": "jsonc",
"**/ansible/**/*.yml": "ansible",
"**/ansible/**/*.sops.yml": "yaml",
"**/ansible/**/inventory/**/*.yml": "yaml",
"**/ansible/**/*.yaml": "ansible",
"**/ansible/**/*.sops.yaml": "yaml",
"**/ansible/**/inventory/**/*.yaml": "yaml",
"**/kubernetes/**/*.sops.toml": "plaintext"
},
"yaml.schemas": {
"ansible": "ansible/*.yml",
"ansible": "ansible/*.yaml",
"Kubernetes": "kubernetes/*.yaml"
},
"editor.bracketPairColorization.enabled": true,
+11 -19
View File
@@ -79,9 +79,9 @@ Clone **your new repo** to you local workstation and `cd` into it.
1. Install the following CLI tools on your workstation, if you are **NOT** using [Homebrew](https://brew.sh/) on MacOS or Linux **ignore** steps 4 and 5.
- Required: [age](https://github.com/FiloSottile/age), [ansible](https://www.ansible.com), [flux](https://toolkit.fluxcd.io/), [weave-gitops](https://docs.gitops.weave.works/docs/installation/weave-gitops/), [cloudflared](https://github.com/cloudflare/cloudflared), [cilium-cli](https://github.com/cilium/cilium-cli), [go-task](https://github.com/go-task/task), [direnv](https://github.com/direnv/direnv), [ipcalc](http://jodies.de/ipcalc), [jq](https://stedolan.github.io/jq/), [kubectl](https://kubernetes.io/docs/tasks/tools/), [python-pip3](https://pypi.org/project/pip/), [sops v3](https://github.com/mozilla/sops), [yq v4](https://github.com/mikefarah/yq)
- Required: [age](https://github.com/FiloSottile/age), [ansible](https://www.ansible.com), [flux](https://toolkit.fluxcd.io/), [cloudflared](https://github.com/cloudflare/cloudflared), [go-task](https://github.com/go-task/task), [direnv](https://github.com/direnv/direnv), [jq](https://stedolan.github.io/jq/), [kubectl](https://kubernetes.io/docs/tasks/tools/), [python-pip3](https://pypi.org/project/pip/), [sops v3](https://github.com/getsops/sops)
- Recommended: [helm](https://helm.sh/), [kustomize](https://github.com/kubernetes-sigs/kustomize), [stern](https://github.com/stern/stern), [yamllint](https://github.com/adrienverge/yamllint)
- Recommended: [helm](https://helm.sh/), [kustomize](https://github.com/kubernetes-sigs/kustomize), [stern](https://github.com/stern/stern)
2. This guide heavily relies on [go-task](https://github.com/go-task/task) as a framework for setting things up. It is advised to learn and understand the commands it is running under the hood.
@@ -170,30 +170,22 @@ In order to expose services to the internet you will need to create a [Cloudflar
### 📄 Configuration
📍 The `.config.env` file contains necessary configuration that is needed by Ansible and Flux.
📍 The `template/vars/config.yaml` file contains necessary configuration that is needed by Ansible and Flux.
1. Copy the `.config.sample.env` to `.config.env` and start filling out all the environment variables.
1. Copy the configuration file and start filling out all the variables.
**All are required** unless otherwise noted in the comments.
```sh
cp .config.sample.env .config.env
cp template/vars/config.sample.yaml template/vars/config.yaml
```
2. Once that is done, verify the configuration is correct by running:
```sh
task verify
```
3. If you do not encounter any errors run start having the script wire up the templated files and place them where they need to be.
2. Once done run the following command which will verify and generate the files needed to continue
```sh
task configure
```
⚠️ This will print out the clear-text passwords for Grafana and Weave Gitops if you had them set to `generated` in your `.config.env`. Take note of these, you'll need them to log into the applications.
### ⚡ Preparing Ubuntu Server with Ansible
📍 Here we will be running an Ansible Playbook to prepare Ubuntu server for running a Kubernetes cluster.
@@ -276,14 +268,14 @@ In order to expose services to the internet you will need to create a [Cloudflar
```sh
task cluster:verify
# ► checking prerequisites
# ✔ kubectl 1.21.5 >=1.18.0-0
# ✔ Kubernetes 1.21.5+k3s1 >=1.16.0-0
# ✔ kubectl 1.27.3 >=1.18.0-0
# ✔ Kubernetes 1.27.3+k3s1 >=1.16.0-0
# ✔ prerequisites checks passed
```
2. Push you changes to git
📍 **Verify** all the `*.sops.yaml` and `*.sops.yml` files under the `./ansible`, and `./kubernetes` directories are **encrypted** with SOPS
📍 **Verify** all the `*.sops.yaml` and `*.sops.yaml` files under the `./ansible`, and `./kubernetes` directories are **encrypted** with SOPS
```sh
git add -A
@@ -456,7 +448,7 @@ To enable Renovate on your repository, click the 'Configure' button over at thei
Flux is pull-based by design meaning it will periodically check your git repository for changes, using a webhook you can enable Flux to update your cluster on `git push`. In order to configure Github to send `push` events from your repository to the Flux webhook receiver you will need two things:
1. Webhook URL - Your webhook receiver will be deployed on `https://flux-webhook.${BOOTSTRAP_CLOUDFLARE_DOMAIN}/hook/:hookId`. In order to find out your hook id you can run the following command:
1. Webhook URL - Your webhook receiver will be deployed on `https://flux-webhook.${bootstrap_cloudflare_domain}/hook/:hookId`. In order to find out your hook id you can run the following command:
```sh
kubectl -n flux-system get receiver/github-receiver
@@ -476,7 +468,7 @@ Flux is pull-based by design meaning it will periodically check your git reposit
sops -d ./kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml | yq .stringData.token
```
**Note:** Don't forget to update the `BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET` variable in your `.config.env` file so it matches the generated secret if applicable
**Note:** Don't forget to update the `bootstrap_flux_github_webhook_token` variable in the `config.yaml` file so it matches the generated secret if applicable
Now that you have the webhook url and secret, it's time to set everything up on the Github repository side. Navigate to the settings of your repository on Github, under "Settings/Webhooks" press the "Add webhook" button. Fill in the webhook url and your secret.
+7 -15
View File
@@ -2,18 +2,17 @@
version: "3"
vars:
KUBERNETES_DIR: "{{.ROOT_DIR}}/kubernetes"
TEMPLATE_DIR: "{{.ROOT_DIR}}/template"
ANSIBLE_DIR: "{{.ROOT_DIR}}/ansible"
dotenv: [".config.env"]
KUBERNETES_DIR: "{{.ROOT_DIR}}/kubernetes"
env:
KUBECONFIG: "{{.ROOT_DIR}}/kubeconfig"
SOPS_AGE_KEY_FILE: ~/.config/sops/age/keys.txt
includes:
ansible: .taskfiles/AnsibleTasks.yml
cluster: .taskfiles/ClusterTasks.yml
ansible: .taskfiles/AnsibleTasks.yaml
cluster: .taskfiles/ClusterTasks.yaml
tasks:
init:
@@ -35,21 +34,14 @@ tasks:
fluxcd/tap/flux
go-task/tap/go-task
helm
ipcalc
jq
kubernetes-cli
kustomize
sops
stern
weaveworks/tap/gitops
yq
verify:
desc: Verify env settings
cmds:
- ./configure --verify
configure:
desc: Configure repository from env settings
desc: Configure repository from Ansible vars
dir: "{{.TEMPLATE_DIR}}"
cmds:
- ./configure
- ansible-playbook configure.yaml
+3 -3
View File
@@ -6,10 +6,10 @@ stdout_callback = yaml
force_valid_group_names = ignore
# File/Directory settings
log_path = ~/.ansible/ansible.log
inventory = ./ansible/inventory
roles_path = ~/.ansible/roles:./ansible/roles
inventory = ./inventory
roles_path = ~/.ansible/roles:./roles
collections_path = ~/.ansible/collections
remote_tmp = /tmp
remote_tmp = ~/.ansible/tmp
local_tmp = ~/.ansible/tmp
# Fact Caching settings
fact_caching = jsonfile
@@ -29,7 +29,7 @@
k3s_state: installed
- name: Kubeconfig
ansible.builtin.include_tasks: tasks/kubeconfig.yml
ansible.builtin.include_tasks: tasks/kubeconfig.yaml
- name: Wait for custom manifests to rollout
when:
@@ -58,20 +58,20 @@
- k3s_primary_control_node
- (k3s_server_manifests_templates | length > 0
or k3s_server_manifests_urls | length > 0)
ansible.builtin.include_tasks: tasks/coredns.yml
ansible.builtin.include_tasks: tasks/coredns.yaml
- name: Cilium
when:
- k3s_primary_control_node
- (k3s_server_manifests_templates | length > 0
or k3s_server_manifests_urls | length > 0)
ansible.builtin.include_tasks: tasks/cilium.yml
ansible.builtin.include_tasks: tasks/cilium.yaml
- name: Cruft
when: k3s_primary_control_node
ansible.builtin.include_tasks: tasks/cruft.yml
ansible.builtin.include_tasks: tasks/cruft.yaml
- name: Stale Containers
ansible.builtin.include_tasks: tasks/stale_containers.yml
ansible.builtin.include_tasks: tasks/stale_containers.yaml
vars:
stale_containers_state: enabled
@@ -63,7 +63,7 @@
k3s_state: uninstalled
- name: Stale Containers
ansible.builtin.include_tasks: tasks/stale_containers.yml
ansible.builtin.include_tasks: tasks/stale_containers.yaml
vars:
stale_containers_state: disabled
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -17,7 +17,7 @@ spec:
image:
repository: registry.k8s.io/coredns/coredns
tag: v1.10.1
replicaCount: 3
replicaCount: 1
service:
# Choose the 10th IP address from the start of the service-cidr
clusterIP: {{ k3s_server['service-cidr'] | ansible.utils.nthhost(10) }}
@@ -1,15 +1,15 @@
---
collections:
- name: community.general
version: 7.1.0
- name: community.sops
version: 1.6.4
- name: ansible.posix
version: 1.5.4
- name: ansible.utils
version: 2.10.3
- name: community.general
version: 7.1.0
- name: kubernetes.core
version: 2.4.0
- name: community.sops
version: 1.6.4
roles:
- name: xanmanning.k3s
src: https://github.com/PyratLabs/ansible-role-k3s.git
Vendored
-482
View File
@@ -1,482 +0,0 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
# shellcheck disable=SC2155
export PROJECT_DIR=$(git rev-parse --show-toplevel)
# shellcheck disable=SC2155
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
# shellcheck disable=SC1091
source "${PROJECT_DIR}/.config.env"
show_help() {
cat << EOF
Usage: $(basename "$0") <options>
-h, --help Display help
--verify Verify .config.env settings
EOF
}
main() {
local verify=
parse_command_line "$@"
if [[ "${verify}" == 1 ]]; then
verify_start
verify_binaries
verify_master_count
verify_ansible_hosts
verify_lbs
verify_kubevip
verify_cluster_service_cidrs
verify_age
verify_git_repository
verify_cloudflare
verify_success
else
# generate sops configuration file
envsubst < "${PROJECT_DIR}/tmpl/.sops.yaml" \
> "${PROJECT_DIR}/.sops.yaml"
# generate cluster settings
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster-settings.yaml" \
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-settings.yaml"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster.yaml" \
> "${PROJECT_DIR}/kubernetes/flux/config/cluster.yaml"
# generate secrets
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cluster-secrets.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cert-manager-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cloudflared-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/networking/cloudflared/app/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/cloudflared/app/secret.sops.yaml"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/external-dns-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
# generate ansible settings
envsubst < "${PROJECT_DIR}/tmpl/ansible/supplemental.yml" \
> "${PROJECT_DIR}/ansible/inventory/group_vars/kubernetes/supplemental.yml"
# generate ansible hosts file and secrets
generate_ansible_hosts
generate_ansible_host_secrets
setup_github_webhook
setup_weave_gitops
setup_grafana_admin
setup_prometheus_endpoints
success
fi
}
parse_command_line() {
while :; do
case "${1:-}" in
-h|--help)
show_help
exit
;;
--verify)
verify=1
;;
*)
break
;;
esac
shift
done
if [[ -z "$verify" ]]; then
verify=0
fi
}
_has_binary() {
command -v "${1}" >/dev/null 2>&1 || {
_log "ERROR(${FUNCNAME[0]})" "${1} is not installed or not found in \$PATH"
exit 1
}
_log "INFO(${FUNCNAME[0]})" "Found CLI tool ${1} and it is in \$PATH"
}
_has_optional_envar() {
local option="${1}"
# shellcheck disable=SC2015
[[ "${!option}" == "" ]] && {
_log "WARN" "Unset optional variable ${option}"
} || {
_log "INFO(${FUNCNAME[0]})" "Found variable '${option}' with value '${!option}'"
}
}
_has_envar() {
local option="${1}"
local secret="${2:-false}"
local value=
# shellcheck disable=SC2015
if [[ "${!option}" == "" ]]; then
_log "ERROR(${FUNCNAME[0]})" "Unset variable ${option}"
exit 1
fi
value="${!option}"
if [[ $secret == "true" ]]; then
value="***"
fi
_log "INFO(${FUNCNAME[0]})" "Found variable '${option}' with value '${value}'"
}
_has_valid_ip() {
local ip="${1}"
local variable_name="${2}"
if ! ipcalc "${ip}" | awk 'BEGIN{FS=":"; is_invalid=0} /^INVALID/ {is_invalid=1; print $1} END{exit is_invalid}' >/dev/null 2>&1; then
_log "INFO(${FUNCNAME[0]})" "Variable '${variable_name}' has an invalid IP address '${ip}'"
exit 1
else
_log "INFO(${FUNCNAME[0]})" "Variable '${variable_name}' has a valid IP address '${ip}'"
fi
}
verify_age() {
_has_envar "BOOTSTRAP_AGE_PUBLIC_KEY"
_has_envar "SOPS_AGE_KEY_FILE"
if [[ ! "$BOOTSTRAP_AGE_PUBLIC_KEY" =~ ^age.* ]]; then
_log "ERROR(${FUNCNAME[0]})" "BOOTSTRAP_AGE_PUBLIC_KEY does not start with age"
exit 1
else
_log "INFO(${FUNCNAME[0]})" "Age public key is in the correct format"
fi
if [[ ! -f ~/.config/sops/age/keys.txt ]]; then
_log "ERROR(${FUNCNAME[0]})" "Unable to find Age file keys.txt in ~/.config/sops/age"
exit 1
else
_log "INFO(${FUNCNAME[0]})" "Found Age public key '${BOOTSTRAP_AGE_PUBLIC_KEY}'"
fi
}
verify_binaries() {
_has_binary "age"
_has_binary "ansible"
_has_binary "envsubst"
_has_binary "flux"
_has_binary "git"
_has_binary "gitops"
_has_binary "ipcalc"
_has_binary "jq"
_has_binary "pip3"
_has_binary "sops"
_has_binary "ssh"
_has_binary "task"
_has_binary "yq"
if ! [[ "$(sops --version)" =~ 3\.[0-9]+\.[0-9]+ ]]; then
_log "ERROR(${FUNCNAME[0]})" "Incompatible sops version, make sure you are using the latest release of github.com/mozilla/sops"
exit 1
fi
if ! [[ "$(yq --version)" =~ 4\.[0-9]+\.[0-9]+ ]]; then
_log "ERROR(${FUNCNAME[0]})" "Incompatible yq version, make sure you are using the latest release of github.com/mikefarah/yq"
exit 1
fi
}
verify_kubevip() {
_has_envar "BOOTSTRAP_KUBE_VIP_ADDR"
_has_valid_ip "${BOOTSTRAP_KUBE_VIP_ADDR}" "BOOTSTRAP_KUBE_VIP_ADDR"
}
verify_lbs() {
#TODO: Validate IPs aren't already in use with arp
_has_envar "BOOTSTRAP_K8S_GATEWAY_ADDR"
_has_envar "BOOTSTRAP_INGRESS_NGINX_ADDR"
_has_valid_ip "${BOOTSTRAP_K8S_GATEWAY_ADDR}" "BOOTSTRAP_K8S_GATEWAY_ADDR"
_has_valid_ip "${BOOTSTRAP_INGRESS_NGINX_ADDR}" "BOOTSTRAP_INGRESS_NGINX_ADDR"
}
verify_cluster_service_cidrs() {
#TODO: Validate input is a CIDR range
_has_envar "BOOTSTRAP_CLUSTER_CIDR"
_has_envar "BOOTSTRAP_SERVICE_CIDR"
}
verify_git_repository() {
_has_envar "BOOTSTRAP_GIT_REPOSITORY"
export GIT_TERMINAL_PROMPT=0
pushd "$(mktemp -d)" >/dev/null 2>&1
[ "$(git ls-remote "${BOOTSTRAP_GIT_REPOSITORY}" 2> /dev/null)" ] || {
_log "ERROR(${FUNCNAME[0]})" "Unable to find the remote Git repository '${BOOTSTRAP_GIT_REPOSITORY}'"
exit 1
}
popd >/dev/null 2>&1
export GIT_TERMINAL_PROMPT=1
}
verify_master_count() {
local master_node_count=
master_node_count=0
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
if [[ "${!node_control}" == "true" ]]; then
master_node_count=$((master_node_count+1))
fi
done
# Check for existance of master nodes and that their count is not an even number
if [[ ${master_node_count} -eq 0 || $((master_node_count%2)) -eq 0 ]]; then
_log "ERROR(${FUNCNAME[0]})" "You must have 1, 3 or an odd number of master nodes >=3 inorder for etcd to have quorum"
exit 1
fi
_log "INFO(${FUNCNAME[0]})" "Verified control plane node count"
}
verify_cloudflare() {
local errors=
local account_zone=
_has_envar "BOOTSTRAP_CLOUDFLARE_APITOKEN" "true"
_has_envar "BOOTSTRAP_CLOUDFLARE_DOMAIN" "true"
_has_envar "BOOTSTRAP_ACME_EMAIL" "true"
# Try to retrieve zone information from Cloudflare's API
account_zone=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${BOOTSTRAP_CLOUDFLARE_DOMAIN}&status=active" \
-H "Authorization: Bearer ${BOOTSTRAP_CLOUDFLARE_APITOKEN}" \
-H "Content-Type: application/json"
)
if [[ "$(echo "${account_zone}" | jq ".success")" == "true" ]]; then
_log "INFO(${FUNCNAME[0]})" "Verified Cloudflare Account and Zone information"
else
errors=$(echo "${account_zone}" | jq -c ".errors")
_log "ERROR(${FUNCNAME[0]})" "Unable to get Cloudflare Account and Zone information ${errors}"
exit 1
fi
local cloudflare_tunnel=
_has_envar "BOOTSTRAP_CLOUDFLARE_ACCOUNT_TAG" "true"
_has_envar "BOOTSTRAP_CLOUDFLARE_TUNNEL_SECRET" "true"
_has_envar "BOOTSTRAP_CLOUDFLARE_TUNNEL_ID" "true"
# Try to retrieve the Cloudflare Tunnel information from Cloudflare's API
cloudflare_tunnel=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/${BOOTSTRAP_CLOUDFLARE_ACCOUNT_TAG}/cfd_tunnel/${BOOTSTRAP_CLOUDFLARE_TUNNEL_ID}" \
-H "Authorization: Bearer ${BOOTSTRAP_CLOUDFLARE_APITOKEN}" \
-H "Content-Type: application/json"
)
if [[ "$(echo "${cloudflare_tunnel}" | jq ".success")" == "true" ]]; then
_log "INFO(${FUNCNAME[0]})" "Verified Cloudflare Tunnel information"
else
errors=$(echo "${cloudflare_tunnel}" | jq -c ".errors")
_log "ERROR(${FUNCNAME[0]})" "Unable to get Cloudflare Tunnel information ${errors}"
exit 1
fi
}
verify_ansible_hosts() {
local node_id=
local node_addr=
local node_username=
local node_password=
local node_control=
local node_hostname=
local default_control_node_prefix=
local default_worker_node_prefix=
default_control_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX"
default_worker_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX"
_has_optional_envar "${default_control_node_prefix}"
_has_optional_envar "${default_worker_node_prefix}"
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_addr="BOOTSTRAP_ANSIBLE_HOST_ADDR_${node_id}"
node_username="BOOTSTRAP_ANSIBLE_SSH_USERNAME_${node_id}"
node_password="BOOTSTRAP_ANSIBLE_SUDO_PASSWORD_${node_id}"
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
node_hostname="BOOTSTRAP_ANSIBLE_HOSTNAME_${node_id}"
_has_envar "${node_addr}"
_has_envar "${node_username}"
_has_envar "${node_password}" "true"
_has_envar "${node_control}"
_has_optional_envar "${node_hostname}"
if [[ "${!node_addr}" == "${BOOTSTRAP_KUBE_VIP_ADDR}" ]]; then
_log "ERROR(${FUNCNAME[0]})" "The kube-vip IP '${BOOTSTRAP_KUBE_VIP_ADDR}' should not be the same as the IP for node '${!node_addr}'"
exit 1
fi
if [[ "${!node_addr}" == "${BOOTSTRAP_K8S_GATEWAY_ADDR}" ]]; then
_log "ERROR(${FUNCNAME[0]})" "The k8s-gateway load balancer IP '${BOOTSTRAP_K8S_GATEWAY_ADDR}' should not be the same as the IP for node '${!node_addr}'"
exit 1
fi
if [[ "${!node_addr}" == "${BOOTSTRAP_INGRESS_NGINX_ADDR}" ]]; then
_log "ERROR(${FUNCNAME[0]})" "The ingress load balancer IP '${BOOTSTRAP_INGRESS_NGINX_ADDR}' should not be the same as the IP for node '${!node_addr}'"
exit 1
fi
if ssh -q -o BatchMode=yes -o ConnectTimeout=5 "${!node_username}"@"${!var}" "true"; then
_log "INFO(${FUNCNAME[0]})" "SSH into host '${!var}' with username '${!node_username}' was successfull"
else
_log "ERROR(${FUNCNAME[0]})" "SSH into host '${!var}' with username '${!node_username}'was NOT successful, did you copy over your SSH key?"
exit 1
fi
done
}
verify_start() {
_log "INFO(${FUNCNAME[0]})" "Starting verification of .config.env, please wait..."
}
verify_success() {
_log "INFO(${FUNCNAME[0]})" "All checks passed!"
_log "INFO(${FUNCNAME[0]})" "Run the script without --verify to template all the files out"
exit 0
}
generate_ansible_host_secrets() {
local node_id=
local node_username=
local node_password=
local node_hostname=
local node_control=
default_control_node_prefix=${BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX:-k8s-}
default_worker_node_prefix=${BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX:-k8s-}
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
if [[ "${!node_control}" == "true" ]]; then
node_hostname="BOOTSTRAP_ANSIBLE_HOSTNAME_${node_id}"
host_key="${!node_hostname:-${default_control_node_prefix}}"
if [ "${host_key}" == "${default_control_node_prefix}" ]; then
node_hostname=${default_control_node_prefix}${node_id}
else
node_hostname=${!node_hostname}
fi
else
node_hostname="BOOTSTRAP_ANSIBLE_HOSTNAME_${node_id}"
host_key="${!node_hostname:-${default_worker_node_prefix}}"
if [ "${host_key}" == "${default_worker_node_prefix}" ]; then
node_hostname=${default_worker_node_prefix}${node_id}
else
node_hostname=${!node_hostname}
fi
fi
{
node_username="BOOTSTRAP_ANSIBLE_SSH_USERNAME_${node_id}"
node_password="BOOTSTRAP_ANSIBLE_SUDO_PASSWORD_${node_id}"
printf "kind: Secret\n"
printf "ansible_user: %s\n" "${!node_username}"
printf "ansible_become_pass: %s\n" "${!node_password}"
} > "${PROJECT_DIR}/ansible/inventory/host_vars/${node_hostname}.sops.yml"
sops --encrypt --in-place "${PROJECT_DIR}/ansible/inventory/host_vars/${node_hostname}.sops.yml"
done
}
generate_ansible_hosts() {
local worker_node_count=
default_control_node_prefix=${BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX:-k8s-}
default_worker_node_prefix=${BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX:-k8s-}
{
printf -- "---\n"
printf "kubernetes:\n"
printf " children:\n"
printf " master:\n"
printf " hosts:\n"
master_node_count=0
worker_node_count=0
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
if [[ "${!node_control}" == "true" ]]; then
master_node_count=$((master_node_count+1))
node_hostname="BOOTSTRAP_ANSIBLE_HOSTNAME_${node_id}"
host_key="${!node_hostname:-${default_control_node_prefix}}"
if [ "${host_key}" == "${default_control_node_prefix}" ]; then
node_hostname=${default_control_node_prefix}${node_id}
else
node_hostname=${!node_hostname}
fi
printf " %s:\n" "${node_hostname}"
printf " ansible_host: %s\n" "${!var}"
else
worker_node_count=$((worker_node_count+1))
fi
done
if [[ ${worker_node_count} -gt 0 ]]; then
printf " worker:\n"
printf " hosts:\n"
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
if [[ "${!node_control}" == "false" ]]; then
node_hostname="BOOTSTRAP_ANSIBLE_HOSTNAME_${node_id}"
host_key="${!node_hostname:-${default_worker_node_prefix}}"
if [ "${host_key}" == "${default_worker_node_prefix}" ]; then
node_hostname=${default_worker_node_prefix}${node_id}
else
node_hostname=${!node_hostname}
fi
printf " %s:\n" "${node_hostname}"
printf " ansible_host: %s\n" "${!var}"
fi
done
fi
} > "${PROJECT_DIR}/ansible/inventory/hosts.yml"
}
setup_prometheus_endpoints() {
yq --inplace 'del(.spec.values.kubeControllerManager.endpoints[])' \
"${PROJECT_DIR}/kubernetes/apps/monitoring/kube-prometheus-stack/app/helmrelease.yaml"
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
if [[ "${!node_control}" == "true" ]]; then
node_addr="BOOTSTRAP_ANSIBLE_HOST_ADDR_${node_id}"
_log "INFO(${FUNCNAME[0]})" "Setting up Prometheus endpoint for '${!node_addr}'"
yq --inplace ".spec.values.kubeControllerManager.endpoints += \"${!node_addr}\"" \
"${PROJECT_DIR}/kubernetes/apps/monitoring/kube-prometheus-stack/app/helmrelease.yaml"
fi
done
}
setup_github_webhook() {
_has_envar "BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET"
WEBHOOK_SECRET="${BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET}"
if [[ "${WEBHOOK_SECRET}" == "generated" ]]; then
WEBHOOK_SECRET="$(openssl rand -hex 12)"
fi
export BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET="${WEBHOOK_SECRET}"
_log "INFO(${FUNCNAME[0]})" "Using GitHub Token '${WEBHOOK_SECRET}' for Flux"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/github-webhook-token-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
}
setup_weave_gitops() {
_has_envar "BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD"
WEAVE_GITOPS_ADMIN_PASSWORD="${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}"
if [[ "${WEAVE_GITOPS_ADMIN_PASSWORD}" == "generated" ]]; then
WEAVE_GITOPS_ADMIN_PASSWORD="$(openssl rand -hex 12)"
fi
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="${WEAVE_GITOPS_ADMIN_PASSWORD}"
_log "INFO(${FUNCNAME[0]})" "Using admin password '${WEAVE_GITOPS_ADMIN_PASSWORD}' for Weave Gitops"
# Convert password to bcrypt hash
# shellcheck disable=SC2155
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="$(echo -n "${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}" | gitops get bcrypt-hash)"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/weave-gitops-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
}
setup_grafana_admin() {
_has_envar "BOOTSTRAP_GRAFANA_ADMIN_PASSWORD"
GRAFANA_ADMIN_PASSWORD="${BOOTSTRAP_GRAFANA_ADMIN_PASSWORD}"
if [[ "${GRAFANA_ADMIN_PASSWORD}" == "generated" ]]; then
GRAFANA_ADMIN_PASSWORD="$(openssl rand -hex 12)"
fi
export BOOTSTRAP_GRAFANA_ADMIN_PASSWORD="${GRAFANA_ADMIN_PASSWORD}"
_log "INFO(${FUNCNAME[0]})" "Using password '${GRAFANA_ADMIN_PASSWORD}' for Grafana"
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/grafana-admin-secret.sops.yaml" \
> "${PROJECT_DIR}/kubernetes/apps/monitoring/grafana/app/secret.sops.yaml"
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/monitoring/grafana/app/secret.sops.yaml"
}
success() {
_log "INFO(${FUNCNAME[0]})" "All files have been templated, proceed to the next steps outlined in the README"
exit 0
}
_log() {
local type="${1}"
local msg="${2}"
printf 'timestamp="%s" type="%s" message="%s"\n' "$(date)" "${type}" "${msg}"
}
main "$@"
@@ -0,0 +1,91 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: coredns
namespace: kube-system
spec:
interval: 30m
chart:
spec:
chart: coredns
version: 1.24.1
sourceRef:
kind: HelmRepository
name: coredns
namespace: flux-system
maxHistory: 2
install:
createNamespace: true
remediation:
retries: 3
upgrade:
cleanupOnFail: true
remediation:
retries: 3
uninstall:
keepHistory: false
values:
fullnameOverride: coredns
image:
repository: registry.k8s.io/coredns/coredns
tag: v1.10.1
replicaCount: 1
service:
clusterIP: "${COREDNS_ADDR}"
serviceAccount:
create: true
deployment:
annotations:
reloader.stakater.com/auto: "true"
servers:
- zones:
- zone: .
scheme: dns://
use_tcp: true
port: 53
plugins:
- name: log
- name: errors
- name: health
configBlock: |-
lameduck 5s
- name: ready
- name: kubernetes
parameters: cluster.local in-addr.arpa ip6.arpa
configBlock: |-
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
- name: prometheus
parameters: 0.0.0.0:9153
- name: forward
parameters: . /etc/resolv.conf
- name: cache
parameters: 30
- name: loop
- name: reload
- name: loadbalance
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: coredns
@@ -0,0 +1,6 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kube-system
resources:
- ./helmrelease.yaml
@@ -0,0 +1,16 @@
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: cluster-apps-coredns
namespace: flux-system
spec:
path: ./kubernetes/apps/kube-system/coredns/app
prune: true
sourceRef:
kind: GitRepository
name: home-kubernetes
wait: false # no flux ks dependents
interval: 30m
retryInterval: 1m
timeout: 5m
@@ -4,6 +4,7 @@ kind: Kustomization
resources:
- ./namespace.yaml
- ./cilium/ks.yaml
- ./coredns/ks.yaml
- ./local-path-provisioner/ks.yaml
- ./metrics-server/ks.yaml
- ./reloader/ks.yaml
@@ -5,5 +5,5 @@ resources:
- ./namespace.yaml
# NOTE: Only enable system-upgrade-controller if you also update the version of k3s in the following file
# otherwise if you run ansible against an already provisioned cluster you might downgrade it
# https://github.com/onedr0p/flux-cluster-template/blob/main/ansible/inventory/group_vars/kubernetes/k3s.yml
# https://github.com/onedr0p/flux-cluster-template/blob/main/ansible/inventory/group_vars/kubernetes/main.yaml
# - ./system-upgrade-controller/ks.yaml
+84
View File
@@ -0,0 +1,84 @@
---
- name: Cluster Installation
hosts: localhost
connection: local
vars_files:
- vars/config.yaml
- defaults/templates.yaml
- defaults/extras.yaml
tasks:
- name: Get absolute path to this Git repository # noqa: command-instead-of-module
ansible.builtin.command: git rev-parse --show-toplevel
changed_when: false
check_mode: false
register: repository_path
failed_when: repository_path.rc != 0
- name: Verify configuration
ansible.builtin.include_tasks: tasks/verify_{{ task }}.yaml
loop: [age, cli, net, cloudflare, github]
loop_control:
loop_var: task
- name: Ensure template directories exist
ansible.builtin.file:
path: "{{ repository_path.stdout }}/{{ item.dest | dirname }}"
state: directory
mode: "0755"
loop: "{{ templates }}"
- name: Template out non-encrypted files
ansible.builtin.template:
src: "templates/{{ item.src }}"
dest: "{{ repository_path.stdout }}/{{ item.dest }}"
mode: "0755"
loop: "{{ templates | selectattr('encrypt', 'equalto', false) | list }}"
# https://github.com/ansible-collections/community.sops/issues/153
- name: Backup sops configuration file
ansible.builtin.copy:
src: "{{ repository_path.stdout }}/.sops.yaml"
dest: "{{ repository_path.stdout }}/.sops.yaml.orig"
mode: "0755"
- name: Remove sops configuration file
ansible.builtin.file:
path: "{{ repository_path.stdout }}/.sops.yaml"
state: absent
- name: Template out encrypted files
community.sops.sops_encrypt:
path: "{{ repository_path.stdout }}/{{ item.dest }}"
encrypted_regex: ^(data|stringData)$
age: ["{{ bootstrap_age_public_key }}"]
content_yaml: "{{ lookup('ansible.builtin.template', 'templates/' + item.src) | from_yaml }}"
mode: "0755"
force: true
loop: "{{ templates | selectattr('encrypt', 'equalto', true) | list }}"
- name: Ensure Ansible inventory directory exists
ansible.builtin.file:
path: "{{ repository_path.stdout }}/ansible/inventory/host_vars"
state: directory
mode: "0755"
- name: Template out node secrets
community.sops.sops_encrypt:
path: "{{ repository_path.stdout }}/ansible/inventory/host_vars/{{ item.name }}.sops.yaml"
age: ["{{ bootstrap_age_public_key }}"]
content_yaml: "{{ lookup('ansible.builtin.template', 'templates/ansible/node.sops.yaml.j2', template_vars=dict(password=item.password)) | from_yaml }}"
mode: "0755"
force: true
loop: "{{ bootstrap_hosts.master + bootstrap_hosts.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"
# https://github.com/ansible-collections/community.sops/issues/153
- name: Restore sops configuration file
ansible.builtin.copy:
src: "{{ repository_path.stdout }}/.sops.yaml.orig"
dest: "{{ repository_path.stdout }}/.sops.yaml"
mode: "0755"
- name: Remove backup sops configuration file
ansible.builtin.file:
path: "{{ repository_path.stdout }}/.sops.yaml.orig"
state: absent
+2
View File
@@ -0,0 +1,2 @@
---
bootstrap_coredns_addr: "{{ bootstrap_service_cidr | ansible.utils.nthhost(10) }}"
+44
View File
@@ -0,0 +1,44 @@
---
templates:
# Root
- src: .sops.yaml.j2
dest: ./.sops.yaml
encrypt: false
# Ansible dir
- src: ansible/supplemental.yaml.j2
dest: ./ansible/inventory/group_vars/kubernetes/supplemental.yaml
encrypt: false
- src: ansible/hosts.yaml.j2
dest: ./ansible/hosts.yaml
encrypt: false
# Kubernetes dir
- src: kubernetes/kube-prometheus-stack-helmrelease.yaml.j2
dest: ./kubernetes/apps/monitoring/kube-prometheus-stack/app/helmrelease.yaml
encrypt: false
- src: kubernetes/cert-manager-secret.sops.yaml.j2
dest: ./kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml
encrypt: true
- src: kubernetes/cloudflared-secret.sops.yaml.j2
dest: ./kubernetes/apps/networking/cloudflared/app/secret.sops.yaml
encrypt: true
- src: kubernetes/cluster-secrets.sops.yaml.j2
dest: ./kubernetes/flux/vars/cluster-secrets.sops.yaml
encrypt: true
- src: kubernetes/cluster-settings.yaml.j2
dest: ./kubernetes/flux/vars/cluster-settings.yaml
encrypt: false
- src: kubernetes/cluster.yaml.j2
dest: ./kubernetes/flux/config/cluster.yaml
encrypt: false
- src: kubernetes/external-dns-secret.sops.yaml.j2
dest: ./kubernetes/apps/networking/external-dns/app/secret.sops.yaml
encrypt: true
- src: kubernetes/github-webhook-token-secret.sops.yaml.j2
dest: ./kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml
encrypt: true
- src: kubernetes/grafana-admin-secret.sops.yaml.j2
dest: ./kubernetes/apps/monitoring/grafana/app/secret.sops.yaml
encrypt: true
- src: kubernetes/weave-gitops-secret.sops.yaml.j2
dest: ./kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml
encrypt: true
+22
View File
@@ -0,0 +1,22 @@
---
- name: Query age key file
ansible.builtin.stat:
path: ~/.config/sops/age/keys.txt
register: result
- name: Check if age key file exists
ansible.builtin.assert:
that: [result.stat.exists]
success_msg: Age file ~/.config/sops/age/keys.txt exists
fail_msg: Age file ~/.config/sops/age/keys.txt does not exist
- name: Query age key file contents
ansible.builtin.set_fact:
age_contents: "{{ lookup('file', '~/.config/sops/age/keys.txt') }}"
- name: Check if age public keys match
ansible.builtin.assert:
that:
- "'{{ bootstrap_age_public_key }}' in age_contents"
success_msg: Age public key {{ bootstrap_age_public_key }} exists
fail_msg: Age public key {{ bootstrap_age_public_key }} does not exist
+8
View File
@@ -0,0 +1,8 @@
---
- name: Check for required CLI tools
ansible.builtin.command: "command -v {{ item }}"
loop: [age, flux, git, pip3, sops, task]
changed_when: false
check_mode: false
register: result
failed_when: result.rc != 0 and result.rc != 127
+34
View File
@@ -0,0 +1,34 @@
---
- name: Query Cloudflare zone
ansible.builtin.uri:
url: "https://api.cloudflare.com/client/v4/zones?name={{ bootstrap_cloudflare_domain }}&status=active"
headers:
Authorization: "Bearer {{ bootstrap_cloudflare_token }}"
Content-Type: application/json
timeout: 5
return_content: true
body_format: json
register: result
- name: Check if Cloudflare zone exists
ansible.builtin.assert:
that: ["result.json.success == true"]
success_msg: "Cloudflare zone {{ bootstrap_cloudflare_domain }} exists"
fail_msg: "Cloudflare zone {{ bootstrap_cloudflare_domain }} does not exist"
- name: Query Cloudflared tunnel
ansible.builtin.uri:
url: "https://api.cloudflare.com/client/v4/accounts/{{ bootstrap_cloudflare_account_tag }}/cfd_tunnel/{{ bootstrap_cloudflare_tunnel_id }}"
headers:
Authorization: "Bearer {{ bootstrap_cloudflare_token }}"
Content-Type: application/json
timeout: 5
return_content: true
body_format: json
register: result
- name: Check if Cloudflared tunnel exists
ansible.builtin.assert:
that: ["result.json.success == true"]
success_msg: "Cloudflared tunnel {{ bootstrap_cloudflare_tunnel_id }} exists"
fail_msg: "Cloudflared tunnel {{ bootstrap_cloudflare_tunnel_id }} does not exist"
+30
View File
@@ -0,0 +1,30 @@
---
- name: Query Github username
ansible.builtin.uri:
url: "https://api.github.com/users/{{ bootstrap_github_username }}"
timeout: 5
return_content: true
body_format: json
register: result
- name: Check if username exists
ansible.builtin.assert:
that:
- "result.json.login == '{{ bootstrap_github_username }}'"
success_msg: "Github user {{ bootstrap_github_username }} exists"
fail_msg: "Github user {{ bootstrap_github_username }} does not exist"
- name: Query Github repo
ansible.builtin.uri:
url: "https://api.github.com/repos/{{ bootstrap_github_username }}/{{ bootstrap_github_repository_name }}"
timeout: 5
return_content: true
body_format: json
register: result
- name: Check if repo exists
ansible.builtin.assert:
that:
- "result.json.full_name == '{{ bootstrap_github_username }}/{{ bootstrap_github_repository_name }}'"
success_msg: "Github repo {{ bootstrap_github_username }}/{{ bootstrap_github_repository_name }} exists"
fail_msg: "Github repo {{ bootstrap_github_username }}/{{ bootstrap_github_repository_name }} does not exist"
+94
View File
@@ -0,0 +1,94 @@
---
- name: Verify master node count
ansible.builtin.assert:
that:
- "{{ bootstrap_hosts.master | length > 0 }}"
- "{{ bootstrap_hosts.master | length is odd }}"
success_msg: "Master node count {{ bootstrap_hosts.master | length }} is correct."
fail_msg: "Master node count {{ bootstrap_hosts.master | length }} is not greater than 0 or is not odd."
- name: Verify node CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_node_cidr is ansible.utils.ipv4 }}"]
success_msg: "Node CIDR {{ bootstrap_node_cidr }} is valid."
fail_msg: "Node CIDR {{ bootstrap_node_cidr }} is invalid."
- name: Verify cluster CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_cluster_cidr is ansible.utils.ipv4 }}"]
success_msg: "Cluster CIDR {{ bootstrap_cluster_cidr }} is valid."
fail_msg: "Cluster CIDR {{ bootstrap_cluster_cidr }} is invalid."
- name: Verify service CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_service_cidr is ansible.utils.ipv4 }}"]
success_msg: "Service CIDR {{ bootstrap_service_cidr }} is valid."
fail_msg: "Service CIDR {{ bootstrap_service_cidr }} is invalid."
- name: Verify k8s_gateway
ansible.builtin.assert:
that: ["{{ bootstrap_k8s_gateway_addr is ansible.utils.ipv4 }}"]
success_msg: "k8s_gateway address {{ bootstrap_k8s_gateway_addr }} is valid."
fail_msg: "k8s_gateway address {{ bootstrap_k8s_gateway_addr }} is invalid."
- name: Verify k8s_gateway in node CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_node_cidr | ansible.utils.network_in_usable(bootstrap_k8s_gateway_addr) }}"]
success_msg: "k8s_gateway address {{ bootstrap_k8s_gateway_addr }} is within {{ bootstrap_node_cidr }}."
fail_msg: "k8s_gateway address {{ bootstrap_k8s_gateway_addr }} is not within {{ bootstrap_node_cidr }}."
- name: Verify ingress-nginx
ansible.builtin.assert:
that: ["{{ bootstrap_ingress_nginx_addr is ansible.utils.ipv4 }}"]
success_msg: "ingress-nginx address {{ bootstrap_ingress_nginx_addr }} is valid."
fail_msg: "ingress-nginx address {{ bootstrap_ingress_nginx_addr }} is invalid."
- name: Verify ingress-nginx in node CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_node_cidr | ansible.utils.network_in_usable(bootstrap_ingress_nginx_addr) }}"]
success_msg: "ingress-nginx address {{ bootstrap_ingress_nginx_addr }} is within {{ bootstrap_node_cidr }}."
fail_msg: "ingress-nginx address {{ bootstrap_ingress_nginx_addr }} is not within {{ bootstrap_node_cidr }}."
- name: Verify kube-vip
ansible.builtin.assert:
that: ["{{ bootstrap_kube_vip_addr is ansible.utils.ipv4 }}"]
success_msg: "kube-vip address {{ bootstrap_kube_vip_addr }} is valid."
fail_msg: "kube-vip address {{ bootstrap_kube_vip_addr }} is invalid."
- name: Verify kube-vip in node CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_node_cidr | ansible.utils.network_in_usable(bootstrap_kube_vip_addr) }}"]
success_msg: "kube-vip address {{ bootstrap_kube_vip_addr }} is within {{ bootstrap_node_cidr }}."
fail_msg: "kube-vip address {{ bootstrap_kube_vip_addr }} is not within {{ bootstrap_node_cidr }}."
- name: Verify nodes are not the same IPs as k8s_gateway, ingress-nginx or kube-vip
ansible.builtin.assert:
that:
- "{{ item.address not in (bootstrap_k8s_gateway_addr, bootstrap_ingress_nginx_addr, bootstrap_kube_vip_addr) }}"
success_msg: "Node address {{ item.address }} is different than k8s_gateway, ingress-nginx or kube-vip."
fail_msg: "Node address {{ item.address }} is not different than k8s_gateway, ingress-nginx or kube-vip."
quiet: true
loop: "{{ bootstrap_hosts.master + bootstrap_hosts.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"
- name: Verify nodes are in node CIDR
ansible.builtin.assert:
that: ["{{ bootstrap_node_cidr | ansible.utils.network_in_usable(item.address) }}"]
success_msg: "Node address {{ item.address }} is within {{ bootstrap_node_cidr }}."
fail_msg: "Node address {{ item.address }} is not within {{ bootstrap_node_cidr }}."
quiet: true
loop: "{{ bootstrap_hosts.master + bootstrap_hosts.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"
- name: Verify SSH port is reachable
ansible.builtin.wait_for:
host: "{{ item.address }}"
port: 22
search_regex: OpenSSH
timeout: 10
connection: local
loop: "{{ bootstrap_hosts.master + bootstrap_hosts.worker | default([]) }}"
loop_control:
label: "{{ item.address }}"
@@ -4,8 +4,8 @@ creation_rules:
encrypted_regex: "^(data|stringData)$"
key_groups:
- age:
- ${BOOTSTRAP_AGE_PUBLIC_KEY}
- "{{ bootstrap_age_public_key }}"
- path_regex: ansible/.*\.sops\.ya?ml
key_groups:
- age:
- ${BOOTSTRAP_AGE_PUBLIC_KEY}
- "{{ bootstrap_age_public_key }}"
+20
View File
@@ -0,0 +1,20 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
---
kubernetes:
children:
master:
hosts:
{% for item in bootstrap_hosts.master %}
{{ item.name }}:
ansible_user: {{ item.username }}
ansible_host: {{ item.address }}
{% endfor %}
{% if bootstrap_hosts.worker | default([]) | length > 0 %}
worker:
hosts:
{% for item in bootstrap_hosts.worker %}
{{ item.name }}:
ansible_user: {{ item.username }}
ansible_host: {{ item.address }}
{% endfor %}
{% endif %}
@@ -0,0 +1,2 @@
---
ansible_become_pass: "{{ password }}"
@@ -0,0 +1,6 @@
---
timezone: "{{ bootstrap_timezone }}"
coredns_addr: "{{ bootstrap_coredns_addr }}"
kube_vip_addr: "{{ bootstrap_kube_vip_addr }}"
cluster_cidr: "{{ bootstrap_cluster_cidr }}"
service_cidr: "{{ bootstrap_service_cidr }}"
@@ -5,4 +5,4 @@ metadata:
name: cert-manager-secret
namespace: cert-manager
stringData:
api-token: "${BOOTSTRAP_CLOUDFLARE_APITOKEN}"
api-token: "{{ bootstrap_cloudflare_token }}"
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: Secret
metadata:
name: cloudflared-secret
namespace: networking
stringData:
TUNNEL_ID: "{{ bootstrap_cloudflare_tunnel_id }}"
credentials.json: |
{
"AccountTag": "{{ bootstrap_cloudflare_account_tag }}",
"TunnelSecret": "{{ bootstrap_cloudflare_tunnel_secret }}",
"TunnelID": "{{ bootstrap_cloudflare_tunnel_id }}"
}
@@ -0,0 +1,10 @@
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-secrets
namespace: flux-system
stringData:
SECRET_DOMAIN: "{{ bootstrap_cloudflare_domain }}"
SECRET_ACME_EMAIL: "{{ bootstrap_acme_email }}"
SECRET_CLOUDFLARE_TUNNEL_ID: "{{ bootstrap_cloudflare_tunnel_id }}"
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
data:
TIMEZONE: "{{ bootstrap_timezone }}"
COREDNS_ADDR: "{{ bootstrap_coredns_addr }}"
K8S_GATEWAY_ADDR: "{{ bootstrap_k8s_gateway_addr }}"
INGRESS_NGINX_ADDR: "{{ bootstrap_ingress_nginx_addr }}"
KUBE_VIP_ADDR: "{{ bootstrap_kube_vip_addr }}"
CLUSTER_CIDR: "{{ bootstrap_cluster_cidr }}"
SERVICE_CIDR: "{{ bootstrap_service_cidr }}"
@@ -8,7 +8,7 @@ spec:
interval: 30m
ref:
branch: main
url: "${BOOTSTRAP_GIT_REPOSITORY}"
url: "https://github.com/{{ bootstrap_github_username }}/{{ bootstrap_github_repository_name }}.git"
ignore: |
# exclude all
/*
@@ -5,4 +5,4 @@ metadata:
name: external-dns-secret
namespace: networking
stringData:
api-token: "${BOOTSTRAP_CLOUDFLARE_APITOKEN}"
api-token: "{{ bootstrap_cloudflare_token }}"
@@ -5,4 +5,4 @@ metadata:
name: github-webhook-token-secret
namespace: flux-system
stringData:
token: "${BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET}"
token: "{{ bootstrap_flux_github_webhook_token }}"
@@ -6,4 +6,4 @@ metadata:
namespace: monitoring
stringData:
admin-user: admin
admin-password: "${BOOTSTRAP_GRAFANA_ADMIN_PASSWORD}"
admin-password: "{{ bootstrap_grafana_admin_password }}"
@@ -1,3 +1,4 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
@@ -88,7 +89,9 @@ spec:
kubeControllerManager:
enabled: true
endpoints: &cp
- 127.0.0.1 # Replaced by configure
{% for item in bootstrap_hosts.master %}
- {{ item.address }}
{% endfor %}
serviceMonitor:
metricRelabelings:
# Remove duplicate metrics
@@ -7,4 +7,4 @@ metadata:
type: Opaque
stringData:
username: admin
password: "${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}"
password: "{{ bootstrap_weave_gitops_admin_password | password_hash('bcrypt') }}"
+1
View File
@@ -0,0 +1 @@
config.yaml
+59
View File
@@ -0,0 +1,59 @@
---
#
# Bootstrap configuration - This file is gitignored
#
# Github username (e.g. onedr0p)
bootstrap_github_username:
# Github repository (e.g. flux-cluster-template)
bootstrap_github_repository_name:
# Age Public Key (e.g. age15uzrw396e67z9wdzsxzdk7ka0g2gr3l460e0slaea563zll3hdfqwqxdta)
bootstrap_age_public_key:
# Choose your timezone (e.g. America/New_York)
bootstrap_timezone: Etc/UTC
# Email you want to be associated with the ACME account (used for TLS certificates via letsencrypt.org)
bootstrap_acme_email:
# Flux github webhook token (openssl rand -hex 12)
bootstrap_flux_github_webhook_token:
# Grafana admin password (openssl rand -hex 12)
bootstrap_grafana_admin_password:
# Weave GitOps dashboard password (openssl rand -hex 12)
bootstrap_weave_gitops_admin_password:
# Cloudflare domain
bootstrap_cloudflare_domain:
# Cloudflare API Token (not API Key)
bootstrap_cloudflare_token:
# Cloudflared Account Tag (cat ~/.cloudflared/*.json | jq -r .AccountTag)
bootstrap_cloudflare_account_tag:
# Cloudflared Tunnel Secret (cat ~/.cloudflared/*.json | jq -r .TunnelSecret)
bootstrap_cloudflare_tunnel_secret:
# Cloudflared Tunnel ID (cat ~/.cloudflared/*.json | jq -r .TunnelID)
bootstrap_cloudflare_tunnel_id:
# CIDR your nodes are on (e.g. 192.168.1.0/24)
bootstrap_node_cidr:
# Load balancer IP for k8s_gateway, choose an available IP in your nodes network that is not being used
bootstrap_k8s_gateway_addr:
# Load balancer IP for ingress-nginx, choose an available IP in your nodes network that is not being used
bootstrap_ingress_nginx_addr:
# IP address to use with kube-vip, choose an available IP in your nodes network that is not being used
bootstrap_kube_vip_addr:
# Choose your cluster and service cidrs, leave these unchanged unless you know what you are doing
bootstrap_cluster_cidr: 10.42.0.0/16
bootstrap_service_cidr: 10.43.0.0/16
# Node information
bootstrap_hosts:
# Use only 1, 3 or more odd master nodes, recommended is 3
master:
# - name: kube0
# address:
# username:
# password:
worker:
# - name: kube1
# address:
# username:
# password:
-5
View File
@@ -1,5 +0,0 @@
---
timezone: "${BOOTSTRAP_TIMEZONE}"
kube_vip_addr: "${BOOTSTRAP_KUBE_VIP_ADDR}"
cluster_cidr: "${BOOTSTRAP_CLUSTER_CIDR}"
service_cidr: "${BOOTSTRAP_SERVICE_CIDR}"
@@ -1,14 +0,0 @@
---
apiVersion: v1
kind: Secret
metadata:
name: cloudflared-secret
namespace: networking
stringData:
TUNNEL_ID: "${BOOTSTRAP_CLOUDFLARE_TUNNEL_ID}"
credentials.json: |
{
"AccountTag": "${BOOTSTRAP_CLOUDFLARE_ACCOUNT_TAG}",
"TunnelSecret": "${BOOTSTRAP_CLOUDFLARE_TUNNEL_SECRET}",
"TunnelID": "${BOOTSTRAP_CLOUDFLARE_TUNNEL_ID}"
}
-10
View File
@@ -1,10 +0,0 @@
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-secrets
namespace: flux-system
stringData:
SECRET_DOMAIN: "${BOOTSTRAP_CLOUDFLARE_DOMAIN}"
SECRET_ACME_EMAIL: "${BOOTSTRAP_ACME_EMAIL}"
SECRET_CLOUDFLARE_TUNNEL_ID: "${BOOTSTRAP_CLOUDFLARE_TUNNEL_ID}"
@@ -1,13 +0,0 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
data:
TIMEZONE: "${BOOTSTRAP_TIMEZONE}"
K8S_GATEWAY_ADDR: "${BOOTSTRAP_K8S_GATEWAY_ADDR}"
INGRESS_NGINX_ADDR: "${BOOTSTRAP_INGRESS_NGINX_ADDR}"
KUBE_VIP_ADDR: "${BOOTSTRAP_KUBE_VIP_ADDR}"
CLUSTER_CIDR: "${BOOTSTRAP_CLUSTER_CIDR}"
SERVICE_CIDR: "${BOOTSTRAP_SERVICE_CIDR}"