Compare commits

...

10 Commits

Author SHA1 Message Date
Max Pfeiffer 17f9bda085 Merge pull request #21 from max-pfeiffer/bugfix/argocd-resources
Fixed LB IPAM IP assignment and clusterissuer sync
2026-02-01 12:32:23 +01:00
Max Pfeiffer ba5c914019 Fixed LB IPAM IP assignment and clusterissuer sync 2026-02-01 12:31:52 +01:00
Max Pfeiffer 22b6db34bb Fixed kubeconfig output command in docs 2026-02-01 10:04:36 +01:00
Max Pfeiffer cbf848f040 Fixed proxmox node name in example 2026-02-01 09:51:51 +01:00
Max Pfeiffer c1476adae7 Fixed cluster name in example 2026-02-01 09:41:58 +01:00
Max Pfeiffer 373fa0541d Merge pull request #19 from max-pfeiffer/feature/acme-dns-and-kubernetes-improvements
Acme dns and kubernetes improvements
2026-01-30 09:07:16 +01:00
Max Pfeiffer d255f24dec Added acme-dns and a DNS01 ClusterIssuer 2026-01-30 09:05:41 +01:00
Max Pfeiffer 035e676fd2 Simplified argocd helm chart configuration 2026-01-30 09:03:27 +01:00
Max Pfeiffer 911b9c4c75 Merge pull request #18 from max-pfeiffer/feature/gitops-metrics-server
Added Kubernetes metrics server
2026-01-25 20:47:10 +01:00
Max Pfeiffer c52f8484c7 Added Kubernetes metrics server
As an interim solution I configured it insecurely, not verifying TLS certificates.
2026-01-25 20:46:16 +01:00
12 changed files with 215 additions and 79 deletions
+10 -7
View File
@@ -59,7 +59,7 @@ $ tofu apply
``` ```
You can then grab and move the kube config file for Kubernetes provisioning like so: You can then grab and move the kube config file for Kubernetes provisioning like so:
```shell ```shell
$ tofu output kubeconfig -raw > ~/.kube/config $ tofu output -raw kubeconfig > ~/.kube/config
$ chmod 600 ~/.kube/config $ chmod 600 ~/.kube/config
``` ```
Test if your cluster access works by listing the nodes: Test if your cluster access works by listing the nodes:
@@ -78,18 +78,14 @@ from. All options can be configured using variables in `configuration.auto.tfvar
1. **Quick start**: installs Cilium LB config, ArgoCD, Ingress without TLS (default settings) with OpenTofu. [ArgoCD](https://argoproj.github.io/cd/) is 1. **Quick start**: installs Cilium LB config, ArgoCD, Ingress without TLS (default settings) with OpenTofu. [ArgoCD](https://argoproj.github.io/cd/) is
available on http://argocd.local. available on http://argocd.local.
* install_cilium_lb_config = true * install_cilium_lb_config = true
* argocd_domain = "argocd.local" * argocd_helm_values: [see defaults in variables.tf](kubernetes/variables.tf)
* argocd_server_insecure = true
* argocd_ingress_enabled = true
* install_argocd_app_of_apps = false * install_argocd_app_of_apps = false
* install_argocd_app_of_apps_git_repo_secret = false * install_argocd_app_of_apps_git_repo_secret = false
2. **GitOps using your own repository**: installs ArgoCD, no Cilium LB config, no Ingress and the Kubernetes resources in 2. **GitOps using your own repository**: installs ArgoCD, no Cilium LB config, no Ingress and the Kubernetes resources in
the repository you specify in `argocd_app_of_apps_source`. Credentials for a private repository can be configured the repository you specify in `argocd_app_of_apps_source`. Credentials for a private repository can be configured
and installed with OpenTofu using `install_argocd_app_of_apps_git_repo_secret` and the related variables: and installed with OpenTofu using `install_argocd_app_of_apps_git_repo_secret` and the related variables:
* install_cilium_lb_config = false * install_cilium_lb_config = false
* argocd_domain = "yourpublicdomain.com" * argocd_helm_values: add your Helm values and override defaults, for instance keep server insecure and switch off ingress
* argocd_server_insecure = true
* argocd_ingress_enabled = false
* install_argocd_app_of_apps = true * install_argocd_app_of_apps = true
* argocd_app_of_apps_source = YOUR SOURCE SETTINGS * argocd_app_of_apps_source = YOUR SOURCE SETTINGS
* install_argocd_app_of_apps_git_repo_secret = true * install_argocd_app_of_apps_git_repo_secret = true
@@ -122,6 +118,13 @@ $ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.p
ArgoCD web user interface should be up and running by now. You can access it in your web browser on ArgoCD web user interface should be up and running by now. You can access it in your web browser on
http://argocd.local if you didn't change the defaults or under the domain you configured with `argocd_domain`. http://argocd.local if you didn't change the defaults or under the domain you configured with `argocd_domain`.
Or log in using ArgoCD CLI (if [installed](https://argo-cd.readthedocs.io/en/stable/cli_installation/))
and check on sync status of your apps:
```shell
$ argocd login --port-forward --port-forward-namespace argocd --plaintext
$ argocd app list --port-forward --port-forward-namespace argocd --plaintext
```
## Roadmap ## Roadmap
Proxmox part: Proxmox part:
* make node resources configurable (CPU, memory, etc.) * make node resources configurable (CPU, memory, etc.)
@@ -21,3 +21,22 @@ spec:
sectionName: http sectionName: http
kind: Gateway kind: Gateway
--- ---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns01
annotations:
argocd.argoproj.io/sync-wave: "20"
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-dns01-cluster-issuer-account-key
solvers:
- dns01:
acmeDNS:
host: http://acme-dns-api
accountSecretRef:
name: acme-dns
key: acmedns.json
@@ -0,0 +1,99 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: acme-dns
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "10"
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: cert
syncPolicy:
automated:
prune: true
selfHeal: true
destination:
namespace: cert
server: https://kubernetes.default.svc
source:
chart: acme-dns
repoURL: https://max-pfeiffer.github.io/acme-dns-server-helm-chart
targetRevision: 0.1.1
helm:
valuesObject:
services:
api:
type: ClusterIP
ports:
api: 80
dns:
metadata:
annotations:
"lbipam.cilium.io/ips": "192.168.10.98"
config: |
[general]
# DNS interface. Note that systemd-resolved may reserve port 53 on 127.0.0.53
# In this case acme-dns will error out and you will need to define the listening interface
# for example: listen = "127.0.0.1:53"
listen = "0.0.0.0:53"
# protocol, "both", "both4", "both6", "udp", "udp4", "udp6" or "tcp", "tcp4", "tcp6"
protocol = "both"
# domain name to serve the requests off of
domain = "acme-dns.superquick.click"
# zone name server
nsname = "acme-dns.superquick.click"
# admin email address, where @ is substituted with .
nsadmin = "admin.superquick.click"
# predefined records served in addition to the TXT
records = [
# domain pointing to the public IP of your acme-dns server
"acme-dns.superquick.click. A 85.3.109.133",
# specify that auth.example.org will resolve any *.auth.example.org records
"acme-dns.superquick.click. NS acme-dns.superquick.click.",
]
# debug messages from CORS etc
debug = false
[database]
# Database engine to use, sqlite3 or postgres
engine = "sqlite3"
# Connection string, filename for sqlite3 and postgres://$username:$password@$host/$db_name for postgres
# Please note that the default Docker image uses path /var/lib/acme-dns/acme-dns.db for sqlite3
connection = "/var/lib/acme-dns/acme-dns.db"
# connection = "postgres://user:password@localhost/acmedns_db"
[api]
# listen ip eg. 127.0.0.1
ip = "0.0.0.0"
# disable registration endpoint
disable_registration = false
# listen port, eg. 443 for default HTTPS
port = "80"
# possible values: "letsencrypt", "letsencryptstaging", "cert", "none"
tls = "none"
# only used if tls = "cert"
tls_cert_privkey = "/etc/tls/example.org/privkey.pem"
tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem"
# only used if tls = "letsencrypt"
acme_cache_dir = "api-certs"
# optional e-mail address to which Let's Encrypt will send expiration notices for the API's cert
notification_email = ""
# CORS AllowOrigins, wildcards can be used
corsorigins = [
"*"
]
# use HTTP header to get the client ip
use_header = false
# header name to pull the ip address / list of ip addresses from
header_name = "X-Forwarded-For"
[logconfig]
# logging level: "error", "warning", "info" or "debug"
loglevel = "debug"
# possible values: stdout, TODO file & integrations
logtype = "stdout"
# file path for logfile TODO
# logfile = "./acme-dns.log"
# format, either "json" or "text"
logformat = "text"
@@ -0,0 +1,26 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: metrics-server
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "-800"
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
syncPolicy:
automated:
prune: true
selfHeal: true
destination:
namespace: kube-system
server: https://kubernetes.default.svc
source:
chart: metrics-server
repoURL: https://kubernetes-sigs.github.io/metrics-server/
targetRevision: 3.13.0
helm:
valuesObject:
args:
- "--kubelet-insecure-tls"
+1 -1
View File
@@ -4,7 +4,7 @@ metadata:
name: acme name: acme
namespace: network namespace: network
annotations: annotations:
argocd.argoproj.io/sync-wave: "30" argocd.argoproj.io/sync-wave: "20"
spec: spec:
gatewayClassName: cilium gatewayClassName: cilium
addresses: addresses:
+19 -3
View File
@@ -8,9 +8,25 @@ cilium_load_balancer_ip_range_start = "192.168.10.95"
cilium_load_balancer_ip_range_stop = "192.168.10.99" cilium_load_balancer_ip_range_stop = "192.168.10.99"
# ArgoCD # ArgoCD
argocd_domain = "argocd.local" argocd_helm_values = [
argocd_server_insecure = true {
argocd_ingress_enabled = true name = "global.domain"
value = "argocd.local"
},
{
# See: https://argo-cd.readthedocs.io/en/stable/operator-manual/tls/#configuring-tls-for-argocd-server
name = "configs.params.server\\.insecure"
value = "true"
},
{
name = "server.ingress.enabled"
value = "true"
},
{
name = "server.ingress.ingressClassName"
value = "cilium"
},
]
## App of Apps ## App of Apps
install_argocd_app_of_apps = false install_argocd_app_of_apps = false
+1 -1
View File
@@ -6,7 +6,7 @@ resource "helm_release" "argocd" {
repository = "https://argoproj.github.io/argo-helm" repository = "https://argoproj.github.io/argo-helm"
namespace = kubernetes_namespace_v1.argocd.id namespace = kubernetes_namespace_v1.argocd.id
timeout = 120 timeout = 120
set = local.argocd_values set = var.argocd_helm_values
} }
resource "helm_release" "cilium_lb_config" { resource "helm_release" "cilium_lb_config" {
-27
View File
@@ -1,27 +0,0 @@
locals {
argocd_values = concat(
[
{
name = "global.domain"
value = var.argocd_domain
},
],
var.argocd_server_insecure ? [
{
name = "configs.params.server\\.insecure"
value = "true"
},
] : [],
var.argocd_ingress_enabled ? [
{
name = "server.ingress.enabled"
value = "true"
},
{
name = "server.ingress.ingressClassName"
value = "cilium"
},
] : [],
length(var.argocd_helm_values) > 0 ? var.argocd_helm_values : []
)
}
+19 -19
View File
@@ -26,31 +26,31 @@ variable "cilium_load_balancer_ip_range_stop" {
type = string type = string
} }
variable "argocd_domain" {
description = "The FQDN for ArgoCD application"
type = string
}
# See: https://argo-cd.readthedocs.io/en/stable/operator-manual/tls/#configuring-tls-for-argocd-server
variable "argocd_server_insecure" {
description = "Flag for disabling internal TLS with --insecure in ArgoCD Helm chart"
type = bool
default = true
}
variable "argocd_ingress_enabled" {
description = "Flag for enabling/disabling creating an Ingress in ArgoCD Helm chart"
type = bool
default = true
}
variable "argocd_helm_values" { variable "argocd_helm_values" {
description = "Additional Helm values for installing the ArgoCD Helm chart" description = "Additional Helm values for installing the ArgoCD Helm chart"
type = list(object({ type = list(object({
name = string name = string
value = string value = string
})) }))
default = [] default = [
{
name = "global.domain"
value = "argocd.local"
},
{
# See: https://argo-cd.readthedocs.io/en/stable/operator-manual/tls/#configuring-tls-for-argocd-server
name = "configs.params.server\\.insecure"
value = "true"
},
{
name = "server.ingress.enabled"
value = "true"
},
{
name = "server.ingress.ingressClassName"
value = "cilium"
},
]
} }
# See: https://argo-cd.readthedocs.io/en/latest/operator-manual/cluster-bootstrapping/#app-of-apps-pattern # See: https://argo-cd.readthedocs.io/en/latest/operator-manual/cluster-bootstrapping/#app-of-apps-pattern
+17 -17
View File
@@ -19,25 +19,25 @@ provider "registry.opentofu.org/hashicorp/helm" {
} }
provider "registry.opentofu.org/siderolabs/talos" { provider "registry.opentofu.org/siderolabs/talos" {
version = "0.10.0" version = "0.10.1"
constraints = "0.10.0" constraints = "0.10.1"
hashes = [ hashes = [
"h1:nFn2rYLkst+Bt9qSmtB0hIfV6iaZ98rqYc5TSZDhwzc=", "h1:fc7ekyeFDNNvScqgHgowGjM9jnKFyUOMGfnEKJwuf1c=",
"zh:0640a27e658d5305c055721290a196780194c7f75ace9fd3461e0e2a8e465410",
"zh:0fa82a384b25a58b65523e0ea4768fa1212b1f5cfc0c9379d31162454fedcc9d", "zh:0fa82a384b25a58b65523e0ea4768fa1212b1f5cfc0c9379d31162454fedcc9d",
"zh:1340a04eec0b33e08cca08aa414b53c8e279ec32d22bec828faa17c6043119ba", "zh:349463cdd4cdb36e03276fdb855e687242237c7cf0bd5871aea995a83838c52e",
"zh:1ab34b5dca009111238b9a787c618ea61585646b1a2f6364d57c7906bbe31d12", "zh:3885026ef7c1c7012d312fc37a35af70821650b10cef03b8ffd08d22145c117d",
"zh:22ec1058cf4e75af80edc00777250129f6d211e020da2fd256b288bce215d9ea", "zh:3a5c4ddae27200663d3552daa8db6d6ad91f49746825e0556370f67e2d3ead5a",
"zh:334526c85d40fb87b772ec6eb00e7334940e17bb6c8ffe7dc9a7e22438487f1a", "zh:456e233aec7d83558255da87ba0b1c7fec81bf71b1aa4e0f35a2787d3f104c2a",
"zh:38def6886f13da461535d1691d90ff6d700a111edb8fd2c49058b9ad071c6bb6", "zh:6b781a16764c91259a6646f346cf47e99a31d7eefcdd188b1ea8b287b8fd0531",
"zh:3e63031980d12419efa0af2a398c17e3f75d6326fc49a298c689fc451efdd9cf", "zh:6d91f628812ec99a71964f00e83df93f6106b830af111b611b6a0f68ad6987ea",
"zh:48e71c03bb4f05cc6d6649f1c197669f170c60f63fbcd8f0a5c19a4e449113d9", "zh:80430dea846ef82a4fb430abe4f0213ae79f9f38a7a61752bbeeec59c82c1387",
"zh:61bfcb5f5cd594b0a445a87f8450183ed376c973e3a2d3a8916f3daccd19ceb3", "zh:84717212f789a026492b0a4d121fcdf4a15f48916f9500cdb4ffa1f6c26479cc",
"zh:8c06d6cfecd57a8a7c0d07d3bba0f9ebf8dda68068d1e2ca2f7fd30af4c629a0", "zh:a0fcaa3fd515d78cf635884165e111fa37b6300cefb0a6412fb1ed584d88599a",
"zh:9ecc15da7a8e8ae94908fbf7cb662c26fbf028a2eeb5496121593ee549e408d5", "zh:b0f8dbb8a667e00340ca9566d1bee933097b3b252a1df3737d2fb376964ab8cc",
"zh:be6925cb91e302e1e7b7d161c3204d259b5f2c7d5b8ea315765ee493033b0b52", "zh:b8191729e70d5e7e53730f7c499ab16faec23d45969424c1f304bab0f6fcfcb6",
"zh:c4b02f4271265e03ca473f330704d2010a6f6836b0fb26d17c7df758f8ec058c", "zh:be3b5cfc57abdbab689088b2677516703600a12eaefc02a2355ba9002f80f273",
"zh:d3a9cd0451d55b71639ce97f561bdf0ebdbde5e4710a39bef75e0128c3efcd73", "zh:d53afbcbeaeeed6c7e65477da4daca2cc4ab0c52ad833219c1141f9310325dc2",
"zh:f04f8a103f5136bdd6910d531192ad0cb10c8734b519b9e9dff4185d5cc7113e",
] ]
} }
+2 -2
View File
@@ -2,7 +2,7 @@
proxmox_api_url = "https://192.168.1.25:8006/api2/json" proxmox_api_url = "https://192.168.1.25:8006/api2/json"
proxmox_api_token_id = "root@pam!supersecret" proxmox_api_token_id = "root@pam!supersecret"
proxmox_api_token_secret = "js7ej5k9-hd75-hd64-js56-js834jmd732" proxmox_api_token_secret = "js7ej5k9-hd75-hd64-js56-js834jmd732"
proxmox_target_node = "your proxmox node" proxmox_target_node = "your-proxmox-node"
proxmox_storage_device = "samsung-ssd" proxmox_storage_device = "samsung-ssd"
# Talos Linux # Talos Linux
@@ -14,7 +14,7 @@ kubernetes_version = "1.34.2"
talos_linux_iso_image_url = "https://factory.talos.dev/image/ce4c980550dd2ab1b17bbf2b08801c7eb59418eafe8f279833297925d67c7515/v1.11.6/nocloud-amd64.iso" talos_linux_iso_image_url = "https://factory.talos.dev/image/ce4c980550dd2ab1b17bbf2b08801c7eb59418eafe8f279833297925d67c7515/v1.11.6/nocloud-amd64.iso"
talos_linux_iso_image_filename = "talos-linux-v1.11.6-qemu-guest-agent-amd64.iso" talos_linux_iso_image_filename = "talos-linux-v1.11.6-qemu-guest-agent-amd64.iso"
# Name of the cluster # Name of the cluster
cluster_name = "your cluster name" cluster_name = "your-cluster-name"
# VIP address for the control planes, see https://www.talos.dev/v1.11/talos-guides/network/vip/ # VIP address for the control planes, see https://www.talos.dev/v1.11/talos-guides/network/vip/
cluster_vip_shared_ip = "192.168.10.100" cluster_vip_shared_ip = "192.168.10.100"
# The node configuration, adjust it to your liking # The node configuration, adjust it to your liking
+1 -1
View File
@@ -6,7 +6,7 @@ terraform {
} }
talos = { talos = {
source = "siderolabs/talos" source = "siderolabs/talos"
version = "0.10.0" version = "0.10.1"
} }
helm = { helm = {
source = "hashicorp/helm" source = "hashicorp/helm"