updated ansible for lightning-lane

This commit is contained in:
2026-03-07 22:47:37 -06:00
parent 36c2e9540c
commit 344e8dff69
19 changed files with 480 additions and 132 deletions

View File

@@ -1,33 +1,12 @@
--- ---
# file: host_vars/lightning_lane/vars # file: host_vars/lightning_lane/vars
# Traefik Load Balancer Server # lightning-lane — Traefik Reverse Proxy / Load Balancer
# VM provisioned by Terraform (pre-pipeline bootstrap)
# Supported hypervisors: # ─── Network ─────────────────────────────────────────────────────────────────
# - Proxmox ip_address: 10.1.71.35
platform: "proxmox" # ─── Application ─────────────────────────────────────────────────────────────
app_role: reverse_proxy
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.) app_name: traefik
proxmox_clone_node: "fantasyland" app_deployment: docker_compose
# VM Configuration
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
vm_size: "small"
vm_storage: "general"
# Proxmox HA Configuration
ha_group: "pve02"
proxmox_host_target: "pve02"
# Network Configuration
# IP address for the Traefik load balancer
ip_address: 10.1.71.24
#vm_mac_address: 'BC:24:11:50:00:80'
# Software Configuration
# Traefik will be installed and configured on this host
# VM Template Configuration
#vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}"

View File

@@ -1,7 +1,9 @@
# file: inventory.yml # file: inventory.yml
proxmox: proxmox:
hosts: hosts:
pve0[1:3]: main-street-usa:
tomorrowland:
fantasyland:
ntp_servers: ntp_servers:
hosts: hosts:
@@ -27,8 +29,8 @@ prometheus_nodes:
load_balancers: load_balancers:
hosts: hosts:
lightning-lane: lightning_lane:
ansible_host: 10.1.71.24 ansible_host: 10.1.71.35
ansible_become: true ansible_become: true
# node_explorer: # node_explorer:
# hosts: # hosts:
@@ -55,10 +57,6 @@ n8n_server:
hosts: hosts:
tiki-room: tiki-room:
traefik_server:
hosts:
lightning_lane:
# dhcp_server: # dhcp_server:
# hosts: # hosts:
# matchbox: # matchbox:
@@ -67,10 +65,6 @@ backup_servers:
hosts: hosts:
timekeeper: timekeeper:
# freeipa:
# hosts:
# infra01:
# ipaserver: # ipaserver:
# hosts: # hosts:
# infra01.int.mk-labs.cloud: # infra01.int.mk-labs.cloud:

View File

@@ -0,0 +1,19 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/deploy_traefik.yml
# DESCRIPTION: Deploys Traefik reverse proxy on lightning-lane.
# Installs Docker and configures Traefik with Cloudflare DNS-01
# certificate resolution for *.local.mk-labs.cloud
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/deploy_traefik.yml
# ------------------------------------------------------------------------------
- name: Deploy Traefik reverse proxy
hosts: traefik_server
become: true
roles:
- common
- docker-host
- traefik

View File

@@ -0,0 +1,22 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/defaults/main.yml
# ------------------------------------------------------------------------------
common_timezone: America/Chicago
common_ntp_server: 10.1.71.33 # sundial
common_packages:
- curl
- wget
- vim
- htop
- git
- jq
- unzip
- ca-certificates
- gnupg
- lsb-release
- net-tools
- dnsutils

View File

@@ -1,4 +0,0 @@
[Resolve]
DNS=127.0.0.1
DNSSEC=yes
DNSStubListener=no

View File

@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------------
# FILE: roles/common/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart timesyncd
systemd:
name: systemd-timesyncd
state: restarted

View File

@@ -0,0 +1,22 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/defaults/main.yml
# ------------------------------------------------------------------------------
common_timezone: America/Chicago
common_ntp_server: 10.1.71.33 # sundial
common_packages:
- curl
- wget
- vim
- htop
- git
- jq
- unzip
- ca-certificates
- gnupg
- lsb-release
- net-tools
- dnsutils

View File

@@ -1,101 +1,45 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# FILE: roles/common/tasks/main.yml # FILE: roles/common/tasks/main.yml
# DESCRIPTION: Baseline configuration applied to all managed hosts.
# Handles hostname, timezone, core packages, NTP, and
# ansible user setup.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
- name: Disable swap
command: swapoff -a
changed_when: false
- name: Persist swap off by commenting out swap in fstab - name: Set hostname
replace: hostname:
path: /etc/fstab name: "{{ inventory_hostname | replace('_', '-') }}"
regexp: '^(\s*)([^#\n]+\s+swap\s+.*)$'
replace: '#\2'
backup: yes
- name: Load required kernel modules - name: Set timezone
modprobe: timezone:
name: "{{ item }}" name: "{{ common_timezone }}"
state: present
loop:
- overlay
- br_netfilter
- name: Persist kernel modules on boot - name: Update apt cache
copy: apt:
dest: /etc/modules-load.d/k8s.conf update_cache: yes
content: | cache_valid_time: 3600
overlay
br_netfilter
- name: Configure required sysctl params for Kubernetes - name: Install base utility packages
copy: apt:
dest: /etc/sysctl.d/k8s.conf name: "{{ common_packages }}"
content: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
- name: Apply sysctl params without reboot
command: sysctl --system
changed_when: false
- name: Set SELinux to permissive mode
selinux:
policy: targeted
state: permissive
- name: Install DNF plugins core for managing repositories
dnf:
name: dnf-plugins-core
state: present state: present
- name: Add Docker CE repository - name: Configure NTP to use sundial
command: dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo template:
args: src: timesyncd.conf.j2
creates: /etc/yum.repos.d/docker-ce.repo dest: /etc/systemd/timesyncd.conf
mode: '0644'
notify: restart timesyncd
- name: Install containerd - name: Ensure systemd-timesyncd is enabled and running
dnf:
name: containerd.io
state: present
- name: Create containerd config directory
file:
path: /etc/containerd
state: directory
- name: Generate default containerd config and enable SystemdCgroup
shell: |
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
args:
creates: /etc/containerd/config.toml
- name: Restart and enable containerd service
systemd: systemd:
name: containerd name: systemd-timesyncd
state: restarted state: started
enabled: yes enabled: yes
daemon_reload: yes
- name: Add Kubernetes repository - name: Ensure ansible user has sudo without password
yum_repository: lineinfile:
name: kubernetes path: /etc/sudoers.d/{{ ansible_user }}
description: Kubernetes line: "{{ ansible_user }} ALL=(ALL) NOPASSWD:ALL"
baseurl: https://pkgs.k8s.io/core:/stable:/v1.33/rpm/ create: yes
gpgkey: https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key mode: '0440'
gpgcheck: yes validate: 'visudo -cf %s'
- name: Install Kubernetes packages
dnf:
name:
- kubelet
- kubeadm
- kubectl
state: present
disable_excludes: kubernetes
- name: Enable the kubelet service
systemd:
name: kubelet
enabled: yes

View File

@@ -0,0 +1,4 @@
# Managed by Ansible — do not edit manually
[Time]
NTP={{ common_ntp_server }}
FallbackNTP=ntp.ubuntu.com

View File

@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------------
# FILE: roles/docker-host/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart docker
systemd:
name: docker
state: restarted

View File

@@ -0,0 +1,88 @@
# ------------------------------------------------------------------------------
# FILE: roles/docker-host/tasks/main.yml
# DESCRIPTION: Prepares an Ubuntu VM to run Docker Compose workloads.
# Installs Docker CE, configures the daemon, and ensures
# the ansible user (wed) can manage containers.
# ------------------------------------------------------------------------------
- name: Install prerequisite packages
apt:
name:
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
update_cache: yes
- name: Create keyrings directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Add Docker GPG key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
- name: Add Docker repository
apt_repository:
repo: >-
deb [arch={{ ansible_architecture | replace('x86_64', 'amd64') }}
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu
{{ ansible_distribution_release }} stable
state: present
filename: docker
- name: Install Docker CE and Compose plugin
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
update_cache: yes
- name: Ensure Docker service is started and enabled
systemd:
name: docker
state: started
enabled: yes
- name: Add ansible user to docker group
user:
name: "{{ ansible_user }}"
groups: docker
append: yes
- name: Configure Docker daemon
copy:
dest: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-address-pools": [
{
"base": "172.17.0.0/16",
"size": 24
}
]
}
mode: '0644'
notify: restart docker
- name: Create Docker Compose project directory
file:
path: /opt/docker
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: '0775'

View File

@@ -0,0 +1,41 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/traefik/defaults/main.yml
# ------------------------------------------------------------------------------
# Traefik version (matches boilerplate)
traefik_version: "v3.6.8"
# Directory structure on the host
traefik_base_dir: /opt/docker/traefik
traefik_config_dir: "{{ traefik_base_dir }}/config"
traefik_certs_dir: "{{ traefik_base_dir }}/certs"
traefik_logs_dir: "{{ traefik_base_dir }}/logs"
# Network
traefik_network: proxy
traefik_http_port: 80
traefik_https_port: 443
traefik_dashboard_port: 8080
traefik_dashboard_enabled: true
# TLS / ACME
traefik_tls_enabled: true
traefik_tls_certresolver: cloudflare
traefik_tls_acme_email: "" # Set in vault
traefik_tls_redirect: true
# Domain
traefik_domain: "local.mk-labs.cloud"
# Cloudflare API token — set in vault
traefik_cloudflare_api_token: ""
# Security headers middleware
traefik_security_headers: true
# Access log
traefik_accesslog_enabled: false
# Prometheus metrics
traefik_prometheus_enabled: false

View File

@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------------
# FILE: roles/traefik/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart traefik
community.docker.docker_compose_v2:
project_src: "{{ traefik_base_dir }}"
state: restarted

View File

@@ -0,0 +1,75 @@
# ------------------------------------------------------------------------------
# FILE: roles/traefik/tasks/main.yml
# DESCRIPTION: Deploys Traefik as a Docker Compose stack with Cloudflare
# DNS-01 certificate resolution for *.local.mk-labs.cloud
# ------------------------------------------------------------------------------
- name: Create Traefik directory structure
file:
path: "{{ item }}"
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: '0775'
loop:
- "{{ traefik_base_dir }}"
- "{{ traefik_config_dir }}"
- "{{ traefik_config_dir }}/dynamic"
- "{{ traefik_certs_dir }}"
- "{{ traefik_logs_dir }}"
- name: Create acme.json for certificate storage
file:
path: "{{ traefik_certs_dir }}/acme.json"
state: touch
owner: root
group: root
mode: '0600'
modification_time: preserve
access_time: preserve
- name: Deploy Traefik static configuration
template:
src: traefik.yml.j2
dest: "{{ traefik_config_dir }}/traefik.yml"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart traefik
- name: Deploy dynamic configuration
template:
src: dynamic.yml.j2
dest: "{{ traefik_config_dir }}/dynamic/default.yml"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart traefik
- name: Deploy Docker Compose file
template:
src: compose.yml.j2
dest: "{{ traefik_base_dir }}/compose.yml"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart traefik
- name: Deploy environment file
template:
src: env.j2
dest: "{{ traefik_base_dir }}/.env"
owner: "{{ ansible_user }}"
group: docker
mode: '0600'
notify: restart traefik
- name: Create Traefik Docker network
docker_network:
name: "{{ traefik_network }}"
state: present
- name: Start Traefik
community.docker.docker_compose_v2:
project_src: "{{ traefik_base_dir }}"
state: present

View File

@@ -0,0 +1,36 @@
# ------------------------------------------------------------------------------
# Traefik Docker Compose
# Managed by Ansible — do not edit manually
# ------------------------------------------------------------------------------
services:
traefik:
image: traefik:{{ traefik_version }}
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "{{ traefik_http_port }}:80"
- "{{ traefik_https_port }}:443"
{% if traefik_dashboard_enabled %}
- "{{ traefik_dashboard_port }}:8080"
{% endif %}
env_file:
- .env
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- {{ traefik_config_dir }}/traefik.yml:/etc/traefik/traefik.yml:ro
- {{ traefik_config_dir }}/dynamic:/etc/traefik/dynamic:ro
- {{ traefik_certs_dir }}/acme.json:/certs/acme.json
{% if traefik_accesslog_enabled %}
- {{ traefik_logs_dir }}:/logs
{% endif %}
networks:
- {{ traefik_network }}
labels:
- "traefik.enable=true"
networks:
{{ traefik_network }}:
external: true

View File

@@ -0,0 +1,34 @@
# ------------------------------------------------------------------------------
# Traefik Dynamic Configuration
# Managed by Ansible — do not edit manually
# ------------------------------------------------------------------------------
http:
{% if traefik_security_headers %}
middlewares:
security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
customResponseHeaders:
X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex"
server: ""
X-Forwarded-Proto: "https"
{% endif %}
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256

View File

@@ -0,0 +1,2 @@
# Managed by Ansible — do not edit manually
CF_DNS_API_TOKEN={{ traefik_cloudflare_api_token }}

View File

@@ -0,0 +1,68 @@
# ------------------------------------------------------------------------------
# Traefik Static Configuration
# Managed by Ansible — do not edit manually
# ------------------------------------------------------------------------------
api:
dashboard: {{ traefik_dashboard_enabled | lower }}
insecure: {{ traefik_dashboard_enabled | lower }}
entryPoints:
web:
address: ":{{ traefik_http_port }}"
{% if traefik_tls_enabled and traefik_tls_redirect %}
http:
redirections:
entryPoint:
to: websecure
scheme: https
{% endif %}
websecure:
address: ":{{ traefik_https_port }}"
{% if traefik_tls_enabled %}
http:
tls:
certResolver: {{ traefik_tls_certresolver }}
domains:
- main: "{{ traefik_domain }}"
sans:
- "*.{{ traefik_domain }}"
{% endif %}
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: {{ traefik_network }}
file:
directory: /etc/traefik/dynamic
watch: true
{% if traefik_tls_enabled %}
certificatesResolvers:
{{ traefik_tls_certresolver }}:
acme:
email: "{{ traefik_tls_acme_email }}"
storage: /certs/acme.json
dnsChallenge:
provider: {{ traefik_tls_certresolver }}
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
{% endif %}
{% if traefik_accesslog_enabled %}
accessLog:
filePath: /logs/access.log
{% endif %}
{% if traefik_prometheus_enabled %}
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
{% endif %}
log:
level: INFO